1.简述
SQLite是一个轻量的、跨平台的、开源的数据库引擎。SQLite每个数据库都是以单个文件(.db)的形式存在,这些数据都是以B-Tree的数据结构形式存储在磁盘上。
使用SQLiteDatabase的insert,delete等方法或者execSQL方法默认都开启了事务,如果操作的顺利完成才会更新.db数据库。事务的实现是依赖于名为rollback journal文件,借助这个临时文件来完成原子操作和回滚功能。
/**
* SampleMethod
*/
public void sampleMethod() {
SQLiteDatabase database = getDataBase().getWritableDatabase();
//id一般为自增
String sql = "insert into TableTest(name) values('小明')";
database.beginTransaction();
try {
//多条插入
for(int i=0;i<10;i++){
database.execSQL(sql);
}
database.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
database.endTransaction();
}
}
开发注意点:
1.多数据批量操作,如多条数据同时插入、同时删除、一张表删除数据同时要求另外一张表插入等操作必须要在同一事务中完成。
2.注意上述事务不能在for循环内部执行 ,正确步骤为创建事务 -> 执行多条SQL操作 -> 提交事务
2.sqlite开源框架一些思考
开源的ORM(对象关系数据映射)框架,如greenDAO、ormlite等。在使用这些框架有必要很了解一下它们的利弊,特别是一些使用反射的框架,对性能的影响会比较大。有些框架在多线程同步方面也会产生一些问题,所以使用时要有所顾虑。
笔者在使用中觉得这些ORM框架最大的问题在于如物流、配送等极其复杂sql业务逻辑场景,实现复杂业务没有写sql语句方便,需求变更修改起来极其困难,最后都是天天班重构解决。这里推荐使用SpringMvc模式手写sql逻辑,既能避免多线程问题(主要可以手动修改多线程问题)、修改产品提的业务逻辑变更也更加方便。
3.SpringMvc模式手写sql逻辑
主要分Mode、Dao、Services、Controller层,说白了就是仿照Mybatis那一套写法。
为何推送这种写法,其一,笔者所待过的几乎所有公司,java端几乎100%会有将Hibernate等持久层废弃,采用Mybatis重构代码的开发工作;其二,很多java端构架师都会讲“自己封装过的jdbc才是最好用的持久层”,与其一不谋而合。
Model层
一张表对应一个表对象、 一个表对象扩展对象,要特别说明的是扩展对象可添加属性指sql中间产物,比如一个班级下学生count,业务层尽量不要在此添加扩展属性
/**
* Test表对象,属性一一对应Test表字段
*/
public class TableTest implements Serializable {
/**
* 自增ID
*/
public int id;
/**
* 名称
*/
public String Name;
}
/**
* Test表对象扩展对象,抛给业务层使用,也方便添加扩展属性
* 这里扩展属性指sql中间产物,比如一个班级下学生count,非业务层扩展属性
*
* @author zhukui
*/
public class TableBean extends TableTest {
//test表条数
int testCount;
}
Dao层:
拼接Sql语句建议使用StringBuffer或StringBuffer,减少资源浪费。
/**
* Dao层-用于专门写SQL语句
*
* @author zhukui
*/
public class TestDao {
/**
* 查询
*/
public static String getTest() {
StringBuffer buffer = new StringBuffer("select ");
buffer.append("id,name from ");
buffer.append("test");
buffer.append(" where id = ?");
//这里可以输出sql语句日志
return buffer.toString();
}
}
Services层:
用于处理SQL操作结果等简单逻辑,Cursor用完一定要关闭。
/**
* Service服务层-用于处理SQL操作结果等简单逻辑
*
* @author zhukui
*/
public class TestService {
/**
* 查询Test表
*/
private TestBean getTest(SQLiteDatabase database, int id) {
//sql语句
String sql = TestDao.getTest();
//这里可以输出参数日志
Cursor cursor = database.rawQuery(sql, new String[]{id});
FundBean bean = null;
if (cursor != null) {
while (cursor.moveToNext()) {
//id,name
bean = new TestBean();
bean.id = cursor.getInt(0);
bean.name = cursor.getString(1);
}
}
if (cursor != null) {
cursor.close();
}
//这里可以输出结果日志
return bean;
}
}
Controller层:
用于处理多个Service层结果
/**
* Controller层-用于处理多个Service层结果
*
* @author zhukui
*/
public class TestController {
/**
* 服务层
*
*/
TestService mTestService = new TestService();
/**
* doSomething
*/
public void doSomething() {
//处理拼接业务
mTestService.getTest();
//其他Service层逻辑
mTestService2.getTest();
//...............
//最后拼接需要的数据
}
}
上述每一层还可以增加一个接口用来解耦,每层逻辑大致同SpringMvc模式,开发中可适当扩展。
4.sqlite数据库创建及升级
A.数据库首次创建
数据库首次创建会执行onCreate方法,表的创建和初始化需要在此方法中进行。
/**
* 数据库首次创建
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS test " +
"(id VERCHAR PRIMARY KEY,name VERCHAR,age INTEGER)");
}
B.数据库升级
数据库升级会执行onUpgrade方法,一般开发中会执行旧表增加新列、增加新表等操作。
/**
* 数据库升级
*
* @param db 数据库实际操作类
* @param oldVersion 旧版本
* @param newVersion 新版本
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion >= 1 && oldVersion < 10) {
//test新增sex字段
db.execSQL("ALTER TABLE test ADD COLUMN sex VARCHAR default ''");
//新增test2表
db.execSQL("CREATE TABLE IF NOT EXISTS test2 " +
"(id VERCHAR PRIMARY KEY,name VERCHAR,age INTEGER)");
}
}
5.总结
1.大量数据插入、删除等操作,最好在子线程中执行。
2.使用SQLiteStatement提高效率。
//SQLiteDatabase SQLiteDatabase database = new SQLiteDatabase(); //sql SQLiteStatement sqlListStatment = database.compileStatement("insert into tableName(name) values (?)"); //isOpen if (database.isOpen()) { database.beginTransaction(); try { //index 为1开始索引,value为入库的值 //bingXXX为插入XXX类型 sqLiteStatement.bindString(index, value); sqLiteStatement.executeInsert(); } database.setTransactionSuccessful(); } finally { database.endTransaction(); } database.close(); }
3.批量操作一定要显示使用事务,Cursor用完一定要关闭。
4.查询时建议不要使用 "select * ",使用"select id,name ... "具体列名称,不需要使用的列名不要查询出来。
5.Cursor.getColumnIndex方法执行比较耗时,不要放到循环内部,要放到循环外。
Cursor cursor = db.query("tableName", new String[]{"name"}, null, null, null, null, null) ; int nameIndex = cursor.getColumnIndex("name") while (cursor.moveToNext()) { String name = cursor.getString(nameIndex); }