SQLite 因其小巧轻便被安卓系统广泛采用,当然在操作小数据量时,差异并不明显;但当 SQLite 在操作略大一点的数据时就显得力不存心了,这时的 CRUD 操作对移动存储设备的性能有着极大的要求,另外用户体验的良好性也对 SQLite 的性能优化提出了要求。那么,当我们在操作大数据量时如何对 SQLite 进行优化呢?正确的操作是:开启事务。下面我们通过采用不同的方式向数据库中插入 10000 条数据来进行比较以体现开启事务对 SQLite 性能提升方面所做出的贡献。首先看一张截图来进行一个感性的认识:
- 源码及安装文件下载方式一:SQLiteDataBase.zip
从上图中我们会很清晰的看到通过普通方式插入 10000 条数据和开启事务插入 10000 条数据之间的差异,整整差了 83 秒。下面我们来看测试代码:
package cn.sunzn.sqlitedatabase; import android.app.Activity; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; import android.view.View; import android.widget.EditText; public class MainActivity extends Activity { protected static final int SUCCESS_INSERT_TO_DB_ONE = 1; protected static final int SUCCESS_INSERT_TO_DB_TWO = 2; private EditText et_usedtime1; private EditText et_usedtime2; Handler handler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case SUCCESS_INSERT_TO_DB_ONE: Integer usetime_one = (Integer) msg.obj; et_usedtime1.setText("插入10000条数据耗时:" + usetime_one / 1000 + "秒"); break; case SUCCESS_INSERT_TO_DB_TWO: Integer usetime_two = (Integer) msg.obj; et_usedtime2.setText("插入10000条数据耗时:" + usetime_two / 1000 + "秒"); break; default: break; } } }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_usedtime1 = (EditText) findViewById(R.id.et_usedtime1); et_usedtime2 = (EditText) findViewById(R.id.et_usedtime2); } /** * 1. 普通方式插入数据库 10000 条数据 */ public void insert1(View view) { MySQLiteOpenHelper openHelper = new MySQLiteOpenHelper(getApplicationContext()); final SQLiteDatabase database = openHelper.getWritableDatabase(); if (database.isOpen()) { new Thread() { public void run() { long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { ContentValues values = new ContentValues(); values.put("name", "tom:" + i); database.insert("person", "_id", values); } database.close(); long end = System.currentTimeMillis(); int usetime_one = (int) (end - start); Message message = new Message(); message.what = SUCCESS_INSERT_TO_DB_ONE; message.obj = usetime_one; handler.sendMessage(message); }; }.start(); } } /** * 2. 开启事务插入数据库 10000 条数据 */ public void insert2(View view) { MySQLiteOpenHelper openHelper = new MySQLiteOpenHelper(getApplicationContext()); final SQLiteDatabase database = openHelper.getWritableDatabase(); if (database.isOpen()) { new Thread() { public void run() { long start = System.currentTimeMillis(); database.beginTransaction(); for (int i = 0; i < 10000; i++) { ContentValues values = new ContentValues(); values.put("name", "tom:" + i); database.insert("person", "_id", values); } database.setTransactionSuccessful(); database.endTransaction(); database.close(); long end = System.currentTimeMillis(); int usetime_two = (int) (end - start); Message message = new Message(); message.what = SUCCESS_INSERT_TO_DB_TWO; message.obj = usetime_two; handler.sendMessage(message); }; }.start(); } } public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
为什么只是开启了一个事务就会有这么大的差距呢?很简单,SQLite 缺省为每个操作开启了一个事务,那么测试代码循环插入 10000 次开启了 10000 个事务,"事务开启 + SQL 执行 + 事务关闭" 自然耗费了大量的时间,这也是后面显式开启事务后为什么如此快的原因。