アプリケーションで複数のテーブルを持つデータベースを使用しています。解析中に2つのテーブルにデータを書き込む必要があるXMLパーサーがあります。両方のテーブルに2つのデータベースアダプターを作成しましたが、問題が発生しました。 1つのテーブルで作業しているときは簡単です。
FirstDBAdapter firstTable = new FirstDBAdapter(mycontext);
firstTable.open(); // open and close it every time I need to insert something
// may be hundreds of times while parsing
// it opens not a table but whole DB
firstTable.insertItem(Item);
firstTable.close();
これはSAXパーサーなので、私の意見では(多分私は間違っているかもしれません)、これはさらに良いでしょう:
FirstDBAdapter firstTable = new FirstDBAdapter(mycontext);
@Override
public void startDocument() throws SAXException
{
firstTable.open(); // open and close only once
}
...
firstTable.insertItem(Item);
...
@Override
public void endDocument() throws SAXException
{
firstTable.close();
}
しかし、2番目のテーブルにデータを挿入する必要がある場合はどうすればよいですか?たとえば、私が2番目のアダプターを持っている場合、それは悪い考えになると思います。
FirstDBAdapter firstTable = new FirstDBAdapter(mycontext);
SecondDBAdapter secondTable = new SecondDBAdapter(mycontext);
@Override
public void startDocument() throws SAXException
{
firstTable.open();
secondTable.open();
}
これを達成する方法について何か考えはありますか?
私のデータベースアダプタ。インスタンスは常にApplicationから継承するMyApplicationに格納されます。最初のテーブルを定義した2番目のテーブルについて考えてみてください。現在、これは短いバージョンですが、実際には、このアダプターはデータベース内の7つのテーブルを処理します。
public class MyDbAdapter {
private static final String LOG_TAG = MyDbAdapter.class.getSimpleName();
private SQLiteDatabase mDb;
private static MyDatabaseManager mDbManager;
public MyDbAdapter() {
mDbManager = new MyDatabaseManager(MyApplication.getApplication());
mDb = mDbManager.getWritableDatabase();
}
public static final class GameColumns implements BaseColumns {
public static final String TABLE = "game";
public static final String IMEI = "imei";
public static final String LAST_UPDATE = "lastupdate";
public static final String NICKNAME = "nickname";
}
public String getImei() {
checkDbState();
String retValue = "";
Cursor c = mDb.rawQuery("SELECT imei FROM " + GameColumns.TABLE, null);
if (c.moveToFirst()) {
retValue = c.getString(c.getColumnIndex(GameColumns.IMEI));
}
c.close();
return retValue;
}
public void setImei(String imei) {
checkDbState();
ContentValues cv = new ContentValues();
cv.put(GameColumns.IMEI, imei);
mDb.update(GameColumns.TABLE, cv, null, null);
}
public boolean isOpen() {
return mDb != null && mDb.isOpen();
}
public void open() {
mDbManager = new MyDatabaseManager(MyApplication.getApplication());
if (!isOpen()) {
mDb = mDbManager.getWritableDatabase();
}
}
public void close() {
if (isOpen()) {
mDb.close();
mDb = null;
if (mDbManager != null) {
mDbManager.close();
mDbManager = null;
}
}
}
private void checkDbState() {
if (mDb == null || !mDb.isOpen()) {
throw new IllegalStateException("The database has not been opened");
}
}
private static class MyDatabaseManager extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "dbname";
private static final int DATABASE_VERSION = 7;
private MyDatabaseManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
createGameTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + "!");
}
private void dropDatabase(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + GameColumns.TABLE);
}
private void createGameTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + GameColumns.TABLE + " ("
+ GameColumns._ID + " INTEGER PRIMARY KEY,"
+ GameColumns.IMEI + " TEXT,"
+ GameColumns.LAST_UPDATE + " TEXT,"
+ GameColumns.NICKNAME + " TEXT);");
ContentValues cv = new ContentValues();
cv.put(GameColumns.IMEI, "123456789012345");
cv.put(GameColumns.LAST_UPDATE, 0);
cv.put(GameColumns.NICKNAME, (String) null);
db.insert(GameColumns.TABLE, null, cv);
}
}
}
データベース名/作成ステートメントとその他の共有情報を含む抽象基本クラスを作成し、それをすべてのテーブルに拡張することに成功しました。このようにして、すべてのCRUDメソッドを分離しておくことができます(私はそれを好みます)。唯一の欠点は、DATABASE_CREATEステートメントが親クラスに存在し、すべてのテーブルを含む必要があることです。これは、後で新しいテーブルを追加できないためですが、私の意見では、CRUDを維持するために支払うのは少額です各テーブルのメソッドは別々です。
これを行うのはかなり簡単でしたが、ここにいくつかのメモがあります:
これは、メモ帳チュートリアルに基づいた、私の抽象親クラスのコードです。子はこれを拡張し、スーパーのコンストラクタを呼び出します(これを自由に使用してください)。
package com.pheide.trainose;
import Android.content.Context;
import Android.database.SQLException;
import Android.database.sqlite.SQLiteDatabase;
import Android.database.sqlite.SQLiteOpenHelper;
import Android.util.Log;
public abstract class AbstractDbAdapter {
protected static final String TAG = "TrainOseDbAdapter";
protected DatabaseHelper mDbHelper;
protected SQLiteDatabase mDb;
protected static final String TABLE_CREATE_ROUTES =
"create table routes (_id integer primary key autoincrement, "
+ "source text not null, destination text not null);";
protected static final String TABLE_CREATE_TIMETABLES =
"create table timetables (_id integer primary key autoincrement, "
+ "route_id integer, depart text not null, arrive text not null, "
+ "train text not null);";
protected static final String DATABASE_NAME = "data";
protected static final int DATABASE_VERSION = 2;
protected final Context mCtx;
protected static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE_ROUTES);
db.execSQL(TABLE_CREATE_TIMETABLES);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS routes");
onCreate(db);
}
}
public AbstractDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public AbstractDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
}
もう少し詳細な説明がここにあります: http://pheide.com/page/11/tab/24#post1
phoxicleのソリューションは素晴らしい出発点ですが、Kevin Galliganの AndroidのSQLiteシリアル化に関するメモ によると、この実装はスレッドセーフではなく、複数のデータベース接続(たとえば、異なるスレッド)がデータベース:
実際の個別の接続から同時にデータベースに書き込もうとすると、失敗します。最初が完了するまで待機せず、次に書き込みます。それは単にあなたの変更を書きません。さらに悪いことに、SQLiteDatabaseで適切なバージョンの挿入/更新を呼び出さない場合、例外は発生しません。 LogCatにメッセージが表示されるだけです。
それで、マルチスレッド? 1つのヘルパーを使用します。
以下は、静的SQLiteOpenHelperインスタンスを使用するphoxicleのデータベースアダプターの変更された実装であり、単一のデータベース接続に制限されています。
public class DBBaseAdapter {
private static final String TAG = "DBBaseAdapter";
protected static final String DATABASE_NAME = "db.sqlite";
protected static final int DATABASE_VERSION = 1;
protected Context mContext;
protected static DatabaseHelper mDbHelper;
private static final String TABLE_CREATE_FOO =
"create table foo (_id integer primary key autoincrement, " +
"bar text not null)");
public DBBaseAdapter(Context context) {
mContext = context.getApplicationContext();
}
public SQLiteDatabase openDb() {
if (mDbHelper == null) {
mDbHelper = new DatabaseHelper(mContext);
}
return mDbHelper.getWritableDatabase();
}
public void closeDb() {
mDbHelper.close();
}
protected static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE_FOO);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS routes");
onCreate(db);
}
}
}
各テーブルのDBBaseAdapterを拡張して、CRUDメソッドを実装します。
public class DBFooTable extends DBBaseAdapter {
public DBFooTable(Context context) {
super(context);
}
public void getBar() {
SQLiteDatabase db = openDb();
// ...
closeDb();
}
多分少し遅れますが、テーブルではなくデータベースを常に開いています。だから、これは私を意味のない形にしています。
firstTable.open();
secondTable.open();
むしろこれを行います。
dataBase.getWritableDatabase();
次に、Justeを更新する場合は、テーブルを選択します。
public int updateTotal (int id, Jours jour){
ContentValues values = new ContentValues();
values.put(COL_TOTAL,Total );
//update the table you want
return bdd.update(TABLE_NAME, values, COL_JOUR + " = " + id, null);
}
そして、それだけです。他の人の役に立つことを願っています