GreenDao 介绍:
greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。如下图所示:
官网地址:http://greenrobot.org/greendao/
github:https://github.com/greenrobot/greenDAO
GreenDao 优点:
性能高,号称Android最快的关系型数据库
内存占用小
库文件比较小,小于100K,编译时间低,而且可以避免65K方法限制
支持数据库加密 greendao支持SQLCipher进行数据库加密 有关SQLCipher可以参考这篇博客Android数据存储之Sqlite采用SQLCipher数据库加密实战
简洁易用的API
GreenDao 3.0改动:
使用过GreenDao的同学都知道,3.0之前需要通过新建GreenDaoGenerator工程生成Java数据对象(实体)和DAO对象,非常的繁琐而且也加大了使用成本。
GreenDao 3.0最大的变化就是采用注解的方式通过编译方式生成Java数据对象和DAO对象。
三大改变就是:1.换包名 2.实体注解 3.加密支持的优化
本文里面会遇到一些代码示例,就摘了官方文档和demo里的例子了,因为他们的例子已经写的很好了。
一、GreenDao3的配置
3.0相比2.0的配置较为方便,不用新建Module等一系列操作,可以直接在build.gradle里配置并新建实体用添加注解的方式生成
步骤1/2
build.gradle下添加这些配置(v7包下面的3个是greendao的)
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
}
}
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'org.greenrobot:greendao:3.0.1'
compile 'org.greenrobot:greendao-generator:3.0.0'
compile 'net.zetetic:android-database-sqlcipher:3.5.2'
}
greendao {
targetGenDir 'src/main/java'
daoPackage 'com.XXXX.dao.db'
}
步骤2/2
2.2版本是在maingen里使用addEntity,addProperty等方法,3.0只需要手动创建一个实体类加上注解即可(下面会详细说)
build项目,自动生成DaoMaster,Daosession,UserDao等文件,接下来就可以在代码中正常使用了。
二、实体注解
大部分的注解都能找到之前与2.0对应的语法
2.1常用注解
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "USERNAME")
private String name;
@NotNull
private int repos;
@Transient
private int tempUsageCount;
...
}
其中
@Entity 用于标识这是一个需要Greendao帮我们生成代码的bean
@Id 标明主键,括号里可以指定是否自增 相当于2.2版本的
Entity entity = schema.addEntity("User");
entity.addLongProperty("id").primaryKey().autoincrement();
@Property 用于设置属性在数据库中的列名(默认不写就是保持一致)
@NotNull 非空
@Transient 标识这个字段是自定义的不会创建到数据库表里 相当于2.2版本的
schema.enableKeepSectionsByDefault();
会生成下列代码
// KEEP INCLUDES - put your custom includes here
// KEEP INCLUDES END
// KEEP FIELDS - put your custom fields here
// KEEP FIELDS END
// KEEP METHODS - put your custom methods here
// KEEP METHODS END
之前想自定义的属性和其getset方法需要写在注释中,现在这个注解就能代替作用
2.2实体类注解
@Entity(
schema = "myschema",
active = true,
nameInDb = "AWESOME_USERS",
indexes = {
@Index(value = "name DESC", unique = true)
},
createInDb = false
)
public class User {
...
}
其中
schema是一个项目中有多个schema时 标明要让这个dao属于哪个schema
active 是标明是否支持实体类之间update,refresh,delete等操作 相当于2.2版本的
1
schema.enableActiveEntitiesByDefault();
nameInDb 就是写个存在数据库里的表名(不写默认是一致)
indexes 定义索引,这里可跨越多个列
CreateInDb 如果是有多个实体都关联这个表,可以把多余的实体里面设置为false避免重复创建(默认是true)
2.3索引注解
@Entity
public class User {
@Id private Long id;
@Index(unique = true)
private String name;
}
@Entity
public class User {
@Id private Long id;
@Unique private String name;
}
其中
@Index 通过这个字段建立索引
@Unique 添加唯一约束,上面的括号里unique=true作用相同
2.4关系注解
@Entity
public class Order {
@Id private Long id;
private long customerId;
@ToOne(joinProperty = "customerId")
private Customer customer;
}
@Entity
public class Customer {
@Id private Long id;
}
@ToOne 是将自己的一个属性与另一个表建立关联,相当于2.2版本的
1
Property property = entity.addLongProperty("customerId").getProperty();
entity.addToOne(Customer, property);
@ToMany 的使用场景有些多,下面的代码默认折叠起来
- View Code
@ToMany的属性referencedJoinProperty,类似于外键约束。
@JoinProperty 对于更复杂的关系,可以使用这个注解标明目标属性的源属性。
@JoinEntity 如果你在做多对多的关系,有其他的表或实体参与,可以给目标属性添加这个额外的注解(感觉不常用吧)
2.5派生注解
Paste_Image.png@Generated 这个是build后greendao自动生成的,这个注解理解为防止重复,每一块代码生成后会加个hash作为标记。 官方不建议你去碰这些代码,改动会导致里面代码与hash值不符。
三、数据库加密
在Greendao的迭代流程中可以看到这么一个库
1
compile 'org.greenrobot:greendao-generator-encryption:3.0.0beta3'
Greendao3 与下面这个加密库合作,encryption:3.0.0beta-3相当于一个适配层,之后迭代中并入greendao主库的3.0.1版本,对database相关的api进行了统一。
1
compile 'net.zetetic:android-database-sqlcipher:3.5.2'
之前的版本也是支持加密的,但是可以理解为在相互api传递数据的时候面临各种类型转换,3.0将其统一,使用更加流畅。
可以直接看写代码使用
User man1 = new User();
man1.setId(10001);
man1.setName("kobe");
DaoMaster.DevOpenHelper a = new DaoMaster.DevOpenHelper(this,"database_name",null);
try {
daoSession = new DaoMaster(a.getEncryptedWritableDb(MY_PWD)).newSession();
daoSession.getUserDao().insert(man1);
}catch (Exception e){
Log.d("e", String.valueOf(e));
}
// 若干代码逻辑后。。。
DaoSession normalSession = new DaoMaster(a.getWritableDb()).newSession();
Log.d("无法取数据",normalSession.getUserDao().loadAll().toString());
DaoSession encryptedSession = new DaoMaster(a.getEncryptedWritableDb(MY_PWD)).newSession();
Log.d("可以取数据",encryptedSession.getUserDao().loadAll().toString());
如上方代码所示,相比于之前的方法getWriteableDb,加密的方法是用了getEncryptedWritableDb。 并在得到DB并getSession时需要输入密钥。 其他的步骤和之前类似。
在取数据时使用的session必须也是使用相同的密钥new出来的,否则只能看到空数据。
07-27 /com.XXX.dsx.testgreendao3 D/无法取数据: []
07-27 /com.XXX.dsx.testgreendao3 D/可以取数据: [com.XXX.dsx.testgreendao3.User@2ae5190]
上面的那个MY_PWD是一个静态变量,建议使用本设备的唯一标识类似于UUID的字段做个加密获得,这样每个机器的密钥是不同的,并且不会发生改变。
如果把加密后的数据库的本地文件扒出来,也是查不到内容的, 使用dump仅仅可以看到表结构和列名。
如果觉得还不满意,可以对列名再进行加密。在建表时就对列名加密,后续使用可能会比较麻烦,建议加密一些关键表如USER,ACCOUNT。
Gradle 插件配置
比如上面想指定生成DaoMaster 、DaoSession、Dao位置
greendao { targetGenDir 'src/main/java'}
schemaVersion: 数据库schema版本,也可以理解为数据库版本号
daoPackage:设置DaoMaster 、DaoSession、Dao包名
targetGenDir:设置DaoMaster 、DaoSession、Dao目录
targetGenDirTest:设置生成单元测试目录
generateTests:设置自动生成单元测试用例
4.)实体@Entity注解
schema:告知GreenDao当前实体属于哪个schema
active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
****nameInDb:****在数据中使用的别名,默认使用的是实体的类名
******indexes:******定义索引,可以跨越多个列
********createInDb:******标记创建数据库表**
5.)基础属性注解
@Id :主键 Long型,可以通过@Id(autoincrement = true)设置自增长
@Property:设置一个非默认关系映射所对应的列名,默认是的使用字段名 举例:@Property (nameInDb="name")
@NotNul:设置数据库表当前列不能为空
@Transient :添加次标记之后不会生成数据库表的列
6.)索引注解
@Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique:向数据库列添加了一个唯一的约束
7.)关系注解
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系
出处
http://www.cnblogs.com/dsxniubility/archive/2016/07/28/5699543.html
使用参考
step1 创建表对象
@Entity
public class User {
@Id
private Long id;
private String name;
private int age;
//下面省去了 setter/getter
}
step3 创建DB帮助类
public class DBManager {
private final static String dbName = "test_db";
private static DBManager mInstance;
private DaoMaster.DevOpenHelper openHelper;
private Context context;
public DBManager(Context context) {
this.context = context;
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
/**
* 获取单例引用
*
* @param context
* @return
*/
public static DBManager getInstance(Context context) {
if (mInstance == null) {
synchronized (DBManager.class) {
if (mInstance == null) {
mInstance = new DBManager(context);
}
}
}
return mInstance;
}
/**
* 获取可读数据库
*/
private SQLiteDatabase getReadableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
SQLiteDatabase db = openHelper.getReadableDatabase();
return db;
}
/**
* 获取可写数据库
*/
private SQLiteDatabase getWritableDatabase() {
if (openHelper == null) {
openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
}
SQLiteDatabase db = openHelper.getWritableDatabase();
return db;
}
/**
* 插入一条记录
*
* @param user
*/
public void insertUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.insert(user);
}
/**
* 插入用户集合
*
* @param users
*/
public void insertUserList(List<User> users) {
if (users == null || users.isEmpty()) {
return;
}
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.insertInTx(users);
}
/**
* 删除一条记录
*
* @param user
*/
public void deleteUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.delete(user);
}
/**
* 更新一条记录
*
* @param user
*/
public void updateUser(User user) {
DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.update(user);
}
/**
* 查询用户列表
*/
public List<User> queryUserList() {
DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
List<User> list = qb.list();
return list;
}
/**
* 查询用户列表
*/
public List<User> queryUserList(int age) {
DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
qb.where( UserDao.Properties.Age.gt(age)).orderAsc( UserDao.Properties.Age);
List<User> list = qb.list();
return list;
}
}
step2 调用db帮助类,测试GreenDao框架
DBManager dbManager = DBManager.getInstance(this);
for (int i = 0; i < 5; i++) {
User user = new User();
user.setId((long) i);
user.setAge(i * 3);
user.setName("第" + i + "人");
dbManager.insertUser(user);
}
List<User> userList = dbManager.queryUserList();
for (User user : userList) {
Log.e("TAG", "queryUserList--before-->" + user.getId() + "--" + user.getName() +"--"+user.getAge());
if (user.getId() == 0) {
dbManager.deleteUser(user);
}
if (user.getId() == 3) {
user.setAge(10);
dbManager.updateUser(user);
}
}
userList = dbManager.queryUserList();
for (User user : userList) {
Log.e("TAG", "queryUserList--after--->" + user.getId() + "---" + user.getName()+"--"+user.getAge());
}
}
网友评论