一、Android数据库框架
做android开发的都会知道sqlite,虽然curb的纯代码也不是很难写,但是市面上也有挺多开源的数据库框架。例如:面向对象的Android数据库框架OOSqlite、SqlBrite、SqlBrite、ORMLite、ActiveAndroid、LitePal、Realm等等。各种数据库框架都差不多,公司中用的是realm框架,但是这里我先挑greenDAO:3.2.0的使用来讲讲。
二、greenDAO框架的简单介绍
greenDAO是一个对象关系映射的数据库框架,ORM(Object Relation Mapping对象关系映射),其表现形式就是通过GreenDao将数据库和Bean对象关联起来。它的特点如下:
懒加载
GreenDao提供的 LazyList 可以实现懒加载的效果.原理是通过持有数据库cursor实现,注意使用完后必须关闭。
缓存机制
1.each session allocates memory, typically a session “cache” for entities.
同一个DaoSession会共享缓存实体.
2.greenDAO uses weak references here Custom Types.
通过弱引用缓存.
利用事务
事务除了可以用来确保数据处理的完整性,还能用于提升大量插入数据时的性能.
SQLite默认为每个插入和更新操作创建一个事务,并且在每次插入或更新后立即提交。数据量多的时候就会消耗过多的时间.
正确的做法是把整批的插入或更新操作放到在一个事务中执行.
例如:
XXDao.insertInTx( )
三、几个常见数据库的对比
1 ORMLite
优点:
文档比较全面,使用简单,易于上手
缺点:
使用注解和反射的方式,导致ORMLite性能较差、效率上不理想
2 ActiveAndroid
优点:
轻量级,使用起来非常简单
缺点:
基于注解的方式,使用前需要在manifest中配置
3 GreenDAO
优点:
- 性能最大化、内存开销最小化、对Android高度优化。
- 操作方便、文件体积比较小、 效率很高。
- 插入和更新的速度是SQLite的2倍,加载实体的速度是ORMLite的4.5倍。
- 支持数据库加密。
- 支持缓存。
- 代码自动生成。
4 Realm
作为对象型数据库,其中一个吸引人的地方就是它查询数据时的零拷贝特性,大大地提高了查询大量列表数据时的效率。
四、greenDAO:3.2.0的使用Demo
1 配置gradle相关
apply plugin: 'org.greenrobot.greendao'
android {
...
}
dependencies {
...
/* greendao 数据库*/
compile 'org.greenrobot:greendao:3.2.0'
//compile 'net.zetetic:android-database-sqlcipher:3.5.4' //数据库加密时添加
//compile 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v1.2.0' //使用数据库升级辅助GreenDaoUpgradleHepler时添加
}
//数据库版本以及Dao的相关设置
greendao {
//数据库schema版本
schemaVersion 1
//设置DaoMaster DaoSession Dao包名,默认的是bean所在的包名
daoPackage 'com.ycxc.easymvpdemo.greendao'
//设置DaoMaster DaoSeeeion Dao目录,默认是build/generated/source/greendao
//targetGenDir 'src/main/greendao'
//设置true,自动生成测试单元
//generateTests 'true'
//设置生成的单元测试目录,默认是src/androidTest/java
//targetGenDirTests 'src/androidTest/java'
}
2 项目最外层build.gradle配置
buildscript {
repositories {
jcenter()
}
dependencies {
...
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
}
}
3 编写实体类,这里记得要写上注解,如下(将以上注解写好后,点击AS上的Make Project即可)
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
/**
* @创建 HaiJia
* @时间 2017/2/27 16:15
* @描述 用户对象
*/
@Entity
public class User {
@Id
private long id;
private String name;
@Generated(hash = 775722222)
public User(){
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
表明该类是持久化的类【持久化含义,存入数据库文件中,作本地化处理】
可配置参数:
1)schema:告知GreenDao当前实体属于哪个schema
2)active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
3)nameInDb:在数据中使用的别名,默认使用的是实体的类名
4)indexes:定义索引,可以跨越多个列
5)createInDb:标记创建数据库表
@Id
选择一个long或Long类型的属性作为该实体所对应数据库中数据表的主键【类型要是long】
@Generated
写在构造方法前
@Property
对应于表中的字段,如果不设置,则默认java类属性对应相同的表字段
@NotNull
使一个属性不为空在数据库表中
@Transient
指定属性不具有持久性,仅仅使用一个暂时的状态
@index
指定一个属性作为索引中的字段
可配置的参数
1) name : 修改在索引中的字段名,不使用默认的。
2)unique :使此字段的值唯一。
@Unique
给字段一个UNIQUE约束
@ToOne
一对一
可配置的参数:
1)joinProperty
@ToMany
一对多
可配置的参数:
1)referencedJoinProperty
2)joinProperties
3)JoinEntity
@Keep
保持不混淆
Make Project完了之后,会出现下面的文件,并且实体类User也会多hash Id
4 上面的三个步骤完成之后,这个框架就可以使用了,先初始化数据库
/*初始化数据库相关*/
private void initDbHelp() {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "recluse-db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
userDao = daoSession.getUserDao();
}
5 插入数据(id为null,则自动为其分配自增的id)
String id = 123;
String name = "黄海佳";
QueryBuilder qb = userDao.queryBuilder();
ArrayList<User> list = (ArrayList<User>) qb.where(UserDao.Properties.Id.eq(id)).list();
if (list.size() > 0) {
Toast.makeText(mContext, "主键重复",0).show();
} else {
userDao.insert(new User(Long.valueOf(id), name));
Toast.makeText(mContext, "插入数据成功", 0).show();
}
6 删除指定数据(跟更新一样,要先查询再更新)
userDao.deleteByKey(Long.valueOf(id));
QueryBuilder qb = userDao.queryBuilder();
ArrayList<User> list = (ArrayList<User>) qb.where(UserDao.Properties.Id.eq(id)).list();
if (list.size() < 1) {
Toast.makeText(mContext, "删除数据成功", 0).show();
}
7 查询数据
GreenDao支持多种条件查询和查询模式比如list(),listLazy(),listLazyUncached(),listIterator()等
xxxDao.load(String key) 根据主键查询,得到具体的实体类,如果不存在则返回null
xxxDao.loadAll()得到全部数据集
xxxDao.queryBuilder() 提供各种方式的结果查询,比如进行有条件的查询,倒序等
Demo如下:
查询全部
List<User> staffs=staffDao.queryBuilder().list();
eq查询
QueryBuilder qb = userDao.queryBuilder();
ArrayList<User> list = (ArrayList<User>) qb.where(UserDao.Properties.Id.eq(id)).list();
if (list.size() > 0) {
for (User user : list) {
text = text + "\r\n" + user.getName();
}
} else {
Toast.makeText(mContext, "找不到相关的数据", 0).show();
}
模糊查询
List<User> staffs = staffDao.queryBuilder().where(StaffDao.Properties.Name.like("%黄%")).orderAsc(StaffDao.Properties.Id).list();
betwwen查询
List<User> staffs = staffDao.queryBuilder().where(StaffDao.Properties.Id.between(5, 8)).orderAsc(StaffDao.Properties.Id).list();
Gt查询
List<User> staffs = staffDao.queryBuilder().where(StaffDao.Properties.Age.gt(23)).orderAsc(StaffDao.Properties.Age).list();
Lt查询
List<User> staffs = staffDao.queryBuilder().where(StaffDao.Properties.Age.lt(23)).orderAsc(StaffDao.Properties.Age).list();
queryBuilder和queryRawCreate查询
//queryBuilder
List<User> staffs= staffDao.queryBuilder().where(new WhereCondition.StringCondition("AGE<23")).list();
//queryRawCreate
List<User> staffs = staffDao.queryRawCreate("where AGE<?", new Integer[]{25}).list();
关联查询
List<User> staffs=staffDao.queryBuilder().where(new WhereCondition.StringCondition("DEPARTMENT_ID IN " +
"(SELECT _ID FROM DEPARTMENT WHERE NAME ='研发部')")).list();
8 数据更新(跟删除一样,要先查询再更新)
// 需要更新的数据
Object obj;
// 根据需要更新数据的主键去数据库进行查询
Object object = xxxDao.load(obj.getKey());
if (object != null) {
// 说明数据库中存在此条数据,则进行数据更新
object.setXxx();
xxxDao.update(object);
} else {
xxxDao.insert(obj);
}
Demo
mUser = new User((long)123,"黄海佳大人");
mUserDao.update(mUser);
9 如果想看到 greendao 实际执行的sql语句,使用
QueryBuilder.LOG_SQL = true;
// 输出带有具体数值的sql日志
QueryBuilder.LOG_VALUES = true;
三、greenDAO:3.2.0的数据库升级问题
1 修改gradle文件:首先在module的gradle文件中修改版本号
//这里改为最新的版本号
schemaVersion 2
2 修改实体类
@Entity
public class User {
@Property
private int age;
@Property
private String password;
@Id
private Long id;
@Property(nameInDb = "USERNAME")
private String username;
@Property(nameInDb = "NICKNAME")
private String nickname;
}
3 以上两个步骤之后直接编译即可
四、greenDAO:3.2.0的数据库版本迁移
1 一般的数据库升级这样就可以了,特殊情况可能需要自己编写数据库迁移脚本,这种时候可以自定义UpgradeHelper
public class UpgradeHelper extends DaoMaster.DevOpenHelper {
public static String TAG = UpgradeHelper.class.getSimpleName();
public UpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
/**
* Here is where the calls to upgrade are executed
* onUpgrade方法中进行数据库的迁移
*/
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
/* i represent the version where the user is now and the class named with this number implies that is upgrading from i to
i++ schema */
for (int i = oldVersion; i < newVersion; i++) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by migrating all tables data");
// TODO: 注意把所新版本的表的xxDao都添加到这里
MigrationHelper.getInstance().migrate(db, UserDao.class);
}
}
}
五、最后
这东西写了我三个小时,妈妈我想哭。