SQLite中的新增默認是單個事務控制的,一次新增就是一次數據庫操做,一次事務。若是幾千次for循環操做,必然存在效率問題。下面代碼是經過事務控制的方式提高效率: java
public void addList(List<GroupMember> listMember) { StringBuffer sbSQL = new StringBuffer(); SQLiteDatabase db = super.getDatabase(); db.beginTransaction(); for (int i = 0; i < listMember.size(); i++) { GroupMember groupMember = listMember.get(i); if(i == 0) { // 根據當前用戶id和圈子id刪除圈子成員 del(groupMember.getUserId(), groupMember.getGroupId());// 第一次新增的時候刪除歷史數據 } if(i != 0) { sbSQL.delete(0, sbSQL.length()); } sbSQL.append(" INSERT INTO ").append(TABLE).append(" (user_id, group_id, member_id, role_id) VALUES"); sbSQL.append(" (").append(groupMember.getUserId()) .append(",").append(groupMember.getGroupId()) .append(",").append(groupMember.getMemberId()) .append(",").append(groupMember.getRole()) .append(");"); db.execSQL(sbSQL.toString()); } db.setTransactionSuccessful(); db.endTransaction(); }
儘可能別用下面的SQL語法,在部分機型上面會報錯。(小米、三星S3)。上面的寫法已經能夠知足須要了…… android
INSERT INTO table(column1, column2) VALUES(val1, val2), (val1, val2)
批量新增的寫法沒什麼好解釋的了,下面分享下批量修改。 sql
需求的出現:好比存在N個聊天圈子,圈子中有N個成員。每次進入圈子的時候後臺線程下載圈子成員最新數據,並更新數據庫。這時候存在三個表:圈子,圈子-成員關係表,用戶表。 數據庫
用戶表是全部圈子的用戶,保存的時候須要判斷是否存在,存在就新增,不然修改部分數據。(由於用戶帶有詳細資料,而圈子成員返回的只有名字、帳號、頭像三個字段,不能用上面的方法先刪除全部數據,而後批量新增) app
SQL關鍵寫法以下(重點是SQLiteDatabase.insertWithOnConflict的用法): 性能
public void insertOrReplace(List<GroupMember> listMember) { SQLiteDatabase db = super.getDatabase(); db.beginTransaction(); for (int i = 0; i < listMember.size(); i++) { BaseUserInfo baseUserInfo = listMember.get(i).getBaseUserInfo(); ContentValues cv = new ContentValues(); cv.put("user_id", baseUserInfo.getUserId()); cv.put("name", baseUserInfo.getName()); cv.put("logo", baseUserInfo.getLogo()); // 生成的sql是 INSERT INTRO OR REPLACE INTO 這樣的 (若是存在就替換存在的字段值. 存在的判斷標準是主鍵衝突, 這裏的主鍵是userId). 下面會介紹這個地方的方法 db.insertWithOnConflict(TABLE, null, cv, SQLiteDatabase.CONFLICT_REPLACE); } db.setTransactionSuccessful(); db.endTransaction(); }
關鍵的一個地方: ui
insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) this
部分參數介紹(忽略參數table和initialValues了,這個你們都知道吧 - -): spa
1) nullColumnHack:當values參數爲空或者裏面沒有內容的時候,咱們insert是會失敗的(底層數據庫不容許插入一個空行),爲了防止這種狀況,咱們要在這裏指定一個列名,到時候若是發現將要插入的行爲空行時,就會將你指定的這個列名的值設爲null,而後再向數據庫中插入。(實際開發中通常設置爲null就好。) 線程
好比:若是values爲空,最後生成的SQL大概是"INSERT INTO table"這樣的,那麼這是一個錯誤的SQL,確定插入失敗。可是若是指定了nullColumnHack,最終會生成SQL"INSERT INTO TABLE("+nullColumnHack+")" VALUES (null)"; 這樣會插入一行沒數據的行,可是SQL不會報錯了。
實際android源碼以下:
public long insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) { acquireReference(); try { StringBuilder sql = new StringBuilder(); sql.append("INSERT"); sql.append(CONFLICT_VALUES[conflictAlgorithm]); // 注意這裏, 等下介紹 sql.append(" INTO "); sql.append(table); sql.append('('); Object[] bindArgs = null; int size = (initialValues != null && initialValues.size() > 0) ? initialValues.size() : 0; if (size > 0) { bindArgs = new Object[size]; int i = 0; for (String colName : initialValues.keySet()) { sql.append((i > 0) ? "," : ""); sql.append(colName); bindArgs[i++] = initialValues.get(colName); } sql.append(')'); sql.append(" VALUES ("); for (i = 0; i < size; i++) { sql.append((i > 0) ? ",?" : "?"); } } else { sql.append(nullColumnHack + ") VALUES (NULL"); } sql.append(')'); SQLiteStatement statement = new SQLiteStatement(this, sql.toString(), bindArgs); try { return statement.executeInsert(); } finally { statement.close(); } } finally { releaseReference(); } }
2) conflictAlgorithm:
該參數是一個int值,上面源碼中也用到了(CONFLICT_VALUES[conflictAlgorithm]),那麼CONFLICT_VALUES的值是什麼?Android源碼中以下:
public static final int CONFLICT_ROLLBACK = 1; public static final int CONFLICT_ABORT = 2; public static final int CONFLICT_FAIL = 3; public static final int CONFLICT_IGNORE = 4; public static final int CONFLICT_REPLACE = 5; public static final int CONFLICT_NONE = 0; private static final String[] CONFLICT_VALUES = new String[]{"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
好了,結合方法 insertWithOnConflict的源碼一塊兒就明白了,當你指定了該參數,最終獲得的SQL是 "INSERT OR REPLACE INTO table(column1, column2...) VALUES(val1, val2...)" 這樣的格式……
這樣就解決了最開始說的需求產生場景中遇到了的性能瓶頸。
分享出來,但願對有須要的人有幫助。