2011-11-16 101 views
71

我已經創建了一個數據庫。我想做交易。 SaveCustomer()包含多條語句,以便當時將記錄插入到Customer, CustomerControl, Profile, Payment表中。Android數據庫交易

當用戶調用SaveCustomer()方法時,那麼這些數據將轉到這4個tables.so我該怎麼辦事務?如果一張表插入失敗,則需要回滾所有內容。例如,當第三個表插入記錄時,我得到一個錯誤,然後還需要回滾前兩個表的插入記錄。

見我的代碼:

public void saveCustomer(){ 
    DBAdapter dbAdapter = DBAdapter.getDBAdapterInstance(RetailerOrderKeyActivity.this); 
    dbAdapter.openDataBase(); 
    ContentValues initialValues = new ContentValues(); 
    initialValues.put("CustomerName",customer.getName()); 
    initialValues.put("Address",customer.getAddress()); 
    initialValues.put("CustomerPID",strPID); 
    initialValues.put("Date",strDateOnly); 
    long n = dbAdapter.insertRecordsInDB("Customer", null, initialValues); 

} 

同樣的其它陳述的也有。

DBAdpter代碼:

public long insertRecordsInDB(String tableName, String nullColumnHack,ContentValues initialValues) { 
    long n =-1; 
    try { 
     myDataBase.beginTransaction(); 
     n = myDataBase.insert(tableName, nullColumnHack, initialValues); 

     myDataBase.endTransaction(); 
     myDataBase.setTransactionSuccessful(); 
    } catch (Exception e) { 
     // how to do the rollback 
     e.printStackTrace(); 
    } 

    return n; 
} 

這是全碼:

public class DBAdapter extends SQLiteOpenHelper { 

    private static String DB_PATH = "/data/data/com.my.controller/databases/"; 
    private static final String DB_NAME = "customer"; 
    private SQLiteDatabase myDataBase; 
    private final Context myContext; 
    private static DBAdapter mDBConnection; 


    private DBAdapter(Context context) { 
     super(context, DB_NAME, null, 1); 
     this.myContext = context; 
     DB_PATH = "/data/data/" 
       + context.getApplicationContext().getPackageName() 
       + "/databases/"; 
     // The Android's default system path of your application database is 
     // "/data/data/mypackagename/databases/" 
    } 


    public static synchronized DBAdapter getDBAdapterInstance(Context context) { 
     if (mDBConnection == null) { 
      mDBConnection = new DBAdapter(context); 
     } 
     return mDBConnection; 
    } 


    public void createDataBase() throws IOException { 
     boolean dbExist = checkDataBase(); 
     if (dbExist) { 
      // do nothing - database already exist 
     } else { 
      // By calling following method 
      // 1) an empty database will be created into the default system path of your application 
      // 2) than we overwrite that database with our database. 
      this.getReadableDatabase(); 
      try { 
       copyDataBase(); 
      } catch (IOException e) { 
       throw new Error("Error copying database"); 
      } 
     } 
    } 


    private boolean checkDataBase() { 
     SQLiteDatabase checkDB = null; 

     try { 
      String myPath = DB_PATH + DB_NAME; 
      checkDB = SQLiteDatabase.openDatabase(myPath, null,SQLiteDatabase.OPEN_READONLY); 

     } catch (SQLiteException e) { 
      // database does't exist yet. 
     } 
     if (checkDB != null) { 
      checkDB.close(); 
     } 
     return checkDB != null ? true : false; 
    } 


    private void copyDataBase() throws IOException { 
     InputStream myInput = myContext.getAssets().open(DB_NAME); 
     String outFileName = DB_PATH + DB_NAME; 
     OutputStream myOutput = new FileOutputStream(outFileName); 
    byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = myInput.read(buffer)) > 0) { 
      myOutput.write(buffer, 0, length); 
     } 
      // Close the streams 
     myOutput.flush(); 
     myOutput.close(); 
     myInput.close(); 
    } 

    /** 
    * Open the database 
    * @throws SQLException 
    */ 
    public void openDataBase() throws SQLException { 
     String myPath = DB_PATH + DB_NAME; 
     myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);  
    } 


    @Override 
    public synchronized void close() { 
     if (myDataBase != null) 
      myDataBase.close(); 
     super.close(); 
    } 

    /** 
    * Call on creating data base for example for creating tables at run time 
    */ 
    @Override 
    public void onCreate(SQLiteDatabase db) { 
    } 


    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     db.execSQL("ALTER TABLE WMPalmUploadControl ADD Testing int"); 

    } 

    public void upgradeDb(){ 
     onUpgrade(myDataBase, 1, 2); 
    } 

    public Cursor selectRecordsFromDB(String tableName, String[] tableColumns, 
      String whereClase, String whereArgs[], String groupBy, 
      String having, String orderBy) { 
     return myDataBase.query(tableName, tableColumns, whereClase, whereArgs, 
       groupBy, having, orderBy); 
    } 


    public ArrayList<ArrayList<String>> selectRecordsFromDBList(String tableName, String[] tableColumns, 
      String whereClase, String whereArgs[], String groupBy, 
      String having, String orderBy) {   

     ArrayList<ArrayList<String>> retList = new ArrayList<ArrayList<String>>(); 
      ArrayList<String> list = new ArrayList<String>(); 
      Cursor cursor = myDataBase.query(tableName, tableColumns, whereClase, whereArgs, 
        groupBy, having, orderBy);   
      if (cursor.moveToFirst()) { 
      do { 
       list = new ArrayList<String>(); 
       for(int i=0; i<cursor.getColumnCount(); i++){     
        list.add(cursor.getString(i)); 
       } 
       retList.add(list); 
      } while (cursor.moveToNext()); 
      } 
      if (cursor != null && !cursor.isClosed()) { 
      cursor.close(); 
      } 
      return retList; 

    } 


    public long insertRecordsInDB(String tableName, String nullColumnHack,ContentValues initialValues) { 
     long n =-1; 
     try { 
      myDataBase.beginTransaction(); 
      n = myDataBase.insert(tableName, nullColumnHack, initialValues); 

      myDataBase.endTransaction(); 
      myDataBase.setTransactionSuccessful(); 
     } catch (Exception e) { 
      // how to do the rollback 
      e.printStackTrace(); 
     } 

     return n; 
    } 


    public boolean updateRecordInDB(String tableName, 
      ContentValues initialValues, String whereClause, String whereArgs[]) { 
     return myDataBase.update(tableName, initialValues, whereClause, 
       whereArgs) > 0;    
    } 

    public int updateRecordsInDB(String tableName, 
      ContentValues initialValues, String whereClause, String whereArgs[]) { 
     return myDataBase.update(tableName, initialValues, whereClause, whereArgs);  
    } 


    public int deleteRecordInDB(String tableName, String whereClause, 
      String[] whereArgs) { 
     return myDataBase.delete(tableName, whereClause, whereArgs); 
    } 


    public Cursor selectRecordsFromDB(String query, String[] selectionArgs) { 
     return myDataBase.rawQuery(query, selectionArgs);  
    } 


    public ArrayList<ArrayList<String>> selectRecordsFromDBList(String query, String[] selectionArgs) {  
      ArrayList<ArrayList<String>> retList = new ArrayList<ArrayList<String>>(); 
      ArrayList<String> list = new ArrayList<String>(); 
      Cursor cursor = myDataBase.rawQuery(query, selectionArgs);    
      if (cursor.moveToFirst()) { 
      do { 
       list = new ArrayList<String>(); 
       for(int i=0; i<cursor.getColumnCount(); i++){     
        list.add(cursor.getString(i)); 
       } 
       retList.add(list); 
      } while (cursor.moveToNext()); 
      } 
      if (cursor != null && !cursor.isClosed()) { 
      cursor.close(); 
      } 
      return retList; 
     } 

} 

database lock issue in HTC Desire

如果插入表數據時發生任何問題,我想回滾。

請幫我

謝謝。

我看着這同相關的問題:

回答

24

你應該添加endTransactionfinally,而不是在你的try塊

finally { 
    myDataBase.endTransaction(); 
    } 

如果任何交易不 結束的更改將回滾被標記爲乾淨(通過調用setTransactionSuccessful)。 否則他們會承諾。

+1

感謝您的信息。在我的'SaveCustomer()'我打算調用'long n = dbAdapter.insertRecordsInDB(「Customer」,null,initialValues);'在4次有不同記錄。它會回滾一切,如果在中間表中有任何錯誤發生。我有4個表。需要在4個表中添加具有不同記錄的記錄。 – Kartheepan

258

其實你做錯了。 如果您有多個記錄要插入到數據庫中,或者如果在其中一個數據庫表中插入數據時出現問題,並且必須從其他表中回滾數據,則必須設置開始事務。

例如

你有兩個表

  1. 一個

現在,你想這兩個表中插入數據,但你將不得不如果你回滾事務在將數據插入表格時將會出現任何錯誤。

現在你已經成功地在表A中插入數據,現在你試圖在表中插入數據B.現在,如果在表B中插入數據時出錯,那麼你必須從表中刪除相關數據這意味着你必須回滾事務。

如何在Android的

  1. 使用數據庫事務。如果你想開始有一種方法交易beginTransaction()
  2. 如果你想提交事務有一種方法setTransactionSuccessful()將提交數據庫中的值
  3. 如果您已開始交易,則需要關閉交易,以便有一種方法endTransaction(),它將結束您的數據庫交易

現在有兩個要點

  1. 如果你想設置的交易獲得成功,你需要寫setTransactionSuccessful()然後endTransaction()beginTransaction()
  2. 如果要回滾您的交易,那麼你需要endTransaction()無通過setTransactionSuccessful()承諾交易。

您可以從here

獲取有關SQLite數據庫事務的詳細信息在你的情況

你可以叫你saveCustomer()功能try和catch塊

db.beginTransaction(); 
try { 
    saveCustomer(); 
    db.setTransactionSuccessful(); 
} catch { 
    //Error in between database transaction 
} finally { 
    db.endTransaction(); 
} 
+3

感謝這些信息。它對我更有幫助!再次感謝 – Piraba

+11

你應該在你的finally中添加'endTransaction',而不是在你的try塊中。 – VansFannel

+6

@VansFannel你是對的,最後是關閉數據庫事務的最佳場所。謝謝你讓它變得更好。 – Dharmendra

11

插入使用交易記錄,這是非常快的

String sql = "INSERT INTO table (col1, col2) VALUES (?, ?)"; 
db.beginTransaction(); 

SQLiteStatement stmt = db.compileStatement(sql); 
for (int i = 0; i < values.size(); i++) { 
    stmt.bindString(1, values.get(i).col1); 
    stmt.bindString(2, values.get(i).col2); 
    stmt.execute(); 
    stmt.clearBindings(); 
} 

db.setTransactionSuccessful(); 
db.endTransaction();