一、GreenDao 简介
GreenDAO 是一款开源的面向 Android 的轻便、快捷的 ORM 框架,将 Java 对象映射到 SQLite 数据库中,我们操作数据库的时候,不再需要编写复杂的 SQL语句, 在性能方面,greenDAO 针对 Android 进行了高度优化,最小的内存开销 、依赖体积小 同时还是支持 数据库加密。
greenDAO 官网地址:greenrobot.org/greendao/
greenDAO GitHub 源码地址:greenrobot/greenDAO
二、GreenDao 特征
1、支持 protocol buffer(protobuf) 协议
GreenDao 支持 protocol buffer(protobuf) 协议数据的直接存储,如果你通过 protobuf 协议与服务器交互,将不需要任何的映射
2、代码生成
greenDAO 会根据配置信息自动生成核心管理类以及 DAO 对象
3、性能
所有 ORM 数据库的,greenDAO 是最快的,greenDAO 不作性能方面任何妥协
三、核心类介绍
1、DaoMaster:
使用 greenDAO 的入口点。DaoMaster 负责管理数据库对象(SQLiteDatabase)和 DAO 类(对象),我们可以通过它内部类 OpenHelper 和 DevOpenHelper SQLiteOpenHelper 创建不同模式的 SQLite 数据库。
2、DaoSession :
管理指定模式下的所有 DAO 对象,DaoSession 提供了一些通用的持久性方法比如插入、负载、更新和删除实体。
3、XxxDAO :
对于每个实体类, greenDAO 都会生成一个与之对应 DAO 对象,如:User 实体,则会生成一个 UserDao 类
4、Entities:
可持久化对象。通常,实体对象代表一个数据库行,使用标准 Java 属性(如一个 POJO 或 JavaBean )
四、集成 GreenDao
a、设置仓库与插件(Project: build.gradle)
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
b、配置依赖 ( Module:app build.gradle )
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
// This is only needed if you want to use encrypted databases
compile 'net.zetetic:android-database-sqlcipher:3.5.6' //加密库依赖(可选项)
}
c、配置数据库相关信息 ( Module:app build.gradle )
greendao {
schemaVersion 1 // 数据库版本号
daoPackage 'com.example.zhangruirui.greendao' // 设置 DaoMaster、DaoSession、Dao 包名
targetGenDir 'src/main/java' // 设置 DaoMaster、DaoSession、Dao 目录
}
d、基本使用步骤
// 生成数据库文件,名为 students-db
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "students-db", null);
SQLiteDatabase db = helper.getWritableDatabase();
// 建立特定模式下的所有的 DAO 对象和数据 db 对象的映射
DaoMaster master = new DaoMaster(db);
// 管理特定模式下的所有 DAO 对象,并提供一些通用的 CRUD 持久化方法
DaoSession session = master.newSession();
// 得到指定的 StudentDao 对象
StudentDao dao = session.getStudentDao();
dao.insert(student);
//...
五、实战
1、我们写一个简单的实体类(User),测试一下
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@Entity
public class User {
@Id
private long id;
private String name;
private int age;
@Generated(hash = 446251977)
public User(long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Generated(hash = 586692638)
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2、点击 Make Project(或者 Make Moudle ‘App’) 编译一下工程 。如果配置正确,会在配置的包目录下自动会生成 DaoMaster,DaoSession 和 UserDao 类 。
3、然后我们定义 OpenHelper 类:UserDBOpenHelper
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.example.zhangruirui.DaoMaster;
public class UserDBOpenHelper extends DaoMaster.DevOpenHelper {
public UserDBOpenHelper(Context context, String name) {
super(context, name);
}
public UserDBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
DaoMaster.dropAllTables(wrap(db), true);
}
}
4、然后,类似 SQLite ,我们需要定义 DBManager:UserManager 创建单例实例,来供外部操作数据库
import android.content.Context;
import android.support.annotation.WorkerThread;
import com.google.gson.Gson;
import java.io.Serializable;
import java.lang.reflect.Type;
public class UserManager {
private volatile static UserManager mInstance = null;
private Context mContext;
private UserStorage mUserStorage = new UserStorage(mContext);
private UserManager() {
}
public static UserManager getInstance() {
if (mInstance == null) {
synchronized (UserManager.class) {
if (mInstance == null) {
mInstance = new UserManager();
}
}
}
return mInstance;
}
public <T> T getUserAge(String key, Type typeOfT) {
try {
String json = mUserStorage.getUserAge(key);
Gson gson = new Gson();
CacheEntry entry = gson.fromJson(json, CacheEntry.class);
return gson.fromJson(entry.mJson, typeOfT);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@WorkerThread
public void setUserAge(String key, Object entity, Type type) {
setUserInner(key, entity, type);
}
@WorkerThread
private void setUserInner(String key, Object entity, Type type) {
Gson gson = new Gson();
String json = gson.toJson(entity, type);
CacheEntry entry = new CacheEntry(json);
json = gson.toJson(entry, CacheEntry.class);
if (entity == null) {
mUserStorage.removeUser(key);
} else {
mUserStorage.addUser(key, json);
}
}
static class CacheEntry implements Serializable {
final String mJson;
CacheEntry(String json) {
mJson = json;
}
}
}
5、获取 UserDao 对数据库表进行 CRUD 操作即可:UserStorage
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.WorkerThread;
import com.example.cui.User;
import org.greenrobot.greendao.query.DeleteQuery;
import org.greenrobot.greendao.query.QueryBuilder;
public class UserStorage {
private SQLiteDatabase mDatabase;
private UserDao mUserDao; // 获取 dao 对象
private final static String DB_NAME = "user_name_age.db"; // 定义数据库名
// 获取核心类的实例
UserStorage(Context context) {
DaoMaster.OpenHelper helper = new UserDBOpenHelper(context, DB_NAME, null);
try {
mDatabase = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(mDatabase);
DaoSession daoSession = daoMaster.newSession();
mUserDao = daoSession.getUserDao();
} catch (Exception e) {
e.printStackTrace();
}
}
public User getUserByName(String name) {
if (!isDataBaseValid()) {
return null;
}
return mUserDao.queryBuilder().where(UserDao.Properties.Name.eq(name)).unique();
}
/**
* 根据用户的名字删除对应的记录
*/
public void removeUser(String name) {
if (!isDataBaseValid()) {
return;
}
try {
QueryBuilder<User> qb = mUserDao.queryBuilder();
DeleteQuery<User> bd = qb.where(UserDao.Properties.Name.eq(name))
.buildDelete();
bd.executeDeleteWithoutDetachingEntities();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 新增记录,如果存在则更新,不存在直接插入
*/
@WorkerThread
public synchronized void addUser(String name, String json) {
if (!isDataBaseValid()) {
return;
}
try {
User user = new User();
user.setName(name);
user.setAge(json);
/**
* 解决 Exception:
* Cannot update entity without key - was it inserted before?
*/
User oldUser = getUserByName(name);
if (oldUser != null) {
user.setId(oldUser.getId());
}
// mUserDao.save(user);
if (getUserByName(name) == null) {
mUserDao.insert(user);
} else {
mUserDao.update(user);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除所有数据
*/
@WorkerThread
public synchronized void deleteAll() {
mUserDao.deleteAll();
}
private boolean isDataBaseValid() {
return mUserDao != null;
}
public String getUserAge(String key) {
return mUserDao.queryBuilder().where(UserDao.Properties.Name.eq(key)).list().get(0).getAge();
}
}
六、注解
表明这个实体类会在数据库中生成一个与之相对应的表
@Entity(
// If you have more than one schema, you can tell greenDAO
// to which schema an entity belongs (pick any string as a name).
schema = "myschema",
// Flag to make an entity "active": Active entities have update,
// delete, and refresh methods.
active = true,
// Specifies the name of the table in the database.
// By default, the name is based on the entities class name.
nameInDb = "AWESOME_USERS",
// Define indexes spanning multiple columns here.
indexes = {
@Index(value = "name DESC", unique = true)
},
// Flag if the DAO should create the database table (default is true).
// Set this to false, if you have multiple entities mapping to one table,
// or the table creation is done outside of greenDAO.
createInDb = false,
// Whether an all properties constructor should be generated.
// A no-args constructor is always required.
generateConstructors = true,
// Whether getters and setters for properties should be generated if missing.
generateGettersSetters = true
)
public class User {
...
}
@Id(autoincrement = true)
对应数据表中的 Id 字段,主键,必须为 Long 型
如果需要使用主键自增,此时 id 类型为 Long(注意是大写的)
@Transient
添加此标记后不会生成数据库表的列,仅仅作为一个普通的 java 类字段,用来临时存储数据的,不会被持久化
表名该属性在数据库中只能有唯一值