加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

sqlite 批量插入性能

发布时间:2020-12-12 19:59:31 所属栏目:百科 来源:网络整理
导读:一、新增 SQLite中的新增默认是单个事务控制的,一次新增就是一次数据库操作,一次事务。如果几千次for循环操作,必然存在效率问题。下面代码是通过事务控制的方式提升效率: public void addList(ListGroupMember listMember) { StringBuffer sbSQL = new S

一、新增

SQLite中的新增默认是单个事务控制的,一次新增就是一次数据库操作,一次事务。如果几千次for循环操作,必然存在效率问题。下面代码是通过事务控制的方式提升效率:
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)。上面的写法已经可以满足需要了……
INSERT INTO table(column1,column2) VALUES(val1,val2),(val1,val2)

批量新增的写法没什么好解释的了,下面分享下批量修改。

二、批量修改

需求的出现:比如存在N个聊天圈子,圈子中有N个成员。每次进入圈子的时候后台线程下载圈子成员最新数据,并更新数据库。这时候存在三个表:圈子,圈子-成员关系表,用户表。

用户表是所有圈子的用户,保存的时候需要判断是否存在,存在就新增,否则修改部分数据。(因为用户带有详细资料,而圈子成员返回的只有名字、账号、头像三个字段,不能用上面的方法先删除所有数据,然后批量新增)

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();
}

关键的一个地方:

insertWithOnConflict(String table,String nullColumnHack,ContentValues initialValues,int conflictAlgorithm)

部分参数介绍(忽略参数table和initialValues了,这个大家都知道吧 – -):

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,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…)” 这样的格式……

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读