GreenDao是一个对象关系型框架,也就是我们常说的ORM框架,使用它可以通过操作对象的方式去操作数据库。从而不用手写sql代码,简化开发。
本文针对GreenDao3.2.2版本进行操作,为什么需要强调版本号? 因为GreenDao2和GreenDao3有比较大的差别,3.0以后相比较之前的版本操作更加的方便。
添加依赖
1,在bulid.gradle文件下的dependencies下添加所需依赖
compile 'org.greenrobot:greendao-generator:3.2.2'
compile 'org.greenrobot:greendao:3.2.2' // add library
2,在bulid.gradle下进行配置
apply plugin: 'org.greenrobot.greendao'
greendao{
schemaVersion 2 //升级greenDao版本号
daoPackage '生成文件包名' // 一般为app包名+生成文件的文件夹名
targetGenDir 'src/main/java' //生成的路径
}
3,在project下的build.gradle配置
dependencies {
//其他省略
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}
上面的配置也就算完了。
我们先明确一下需求:创建一个名为test.db的数据库,而数据库中有一张表user,需要使用greenDao对user表进行CRUD操作,数据库升级等常用的操作。
创建实体类
先需要定义个User类并标明@Entity注解和数据库中的表进行对应
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
private String name;
private int grade;
@Transient//Transient表示该字段不参与序列化操作,不作为表中列名
private int tempUsageCount;
//…set(),get()方法省略
public Integer age;
@Generated(hash = 1097688115)
public User(Long id, String name, int grade, Integer age) {
this.id = id;
this.name = name;
this.grade = grade;
this.age = age;
}
@Generated(hash = 586692638)
public User() {
}
}
需要注意的是@Id:通过这个注解标记的字段必须是包装类型Long类型,表示该字段为主键,并且它默认就是自增。否则在升级/降级数据库的时候,会报错。
生成数据库操作类
成功构建工程之后,GreenDao会生成UserDao,DaoSession,DaoMaster三个文件。自动生成的Dao,Session,Master官方是不建议直接修改这些文件的代码,因为当数据库需要升级/降级的时候使用生成器重新生成将会覆盖之前修改过的代码
为方便操作,我们先封装一个DBManager类:
public class DBManager {
private static final String DB_NAME = "test.db";
private static DBManager mDbManager;
private static DaoMaster.DevOpenHelper mDevOpenHelper;
private static volatile DaoMaster mDaoMaster;
private static volatile DaoSession mDaoSession;
private Context mContext;
private DBManager(Context context) {
this.mContext = context;
// 初始化数据库信息
mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);
getDaoMaster(context);
getDaoSession(context);
}
public static DBManager getInstance(Context context) {
if (null == mDbManager) {
synchronized (DBManager.class) {
if (null == mDbManager) {
mDbManager = new DBManager(context);
}
}
}
return mDbManager;
}
/**
* 获取可读数据库
*
* @param context
* @return
*/
public static SQLiteDatabase getReadableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
}
return mDevOpenHelper.getReadableDatabase();
}
/**
* 获取可写数据库
*
* @param context
* @return
*/
public static SQLiteDatabase getWritableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
}
return mDevOpenHelper.getWritableDatabase();
}
/**
* 获取DaoMaster
* <p>
* 判断是否存在数据库,如果没有则创建数据库
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);
mDaoMaster = new DaoMaster(mDevOpenHelper.getWritableDb());
}
}
}
return mDaoMaster;
}
/**
* 获取DaoSession
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (null == mDaoSession) {
synchronized (DBManager.class) {
mDaoSession = getDaoMaster(context).newSession();
}
}
return mDaoSession;
}
}
对数据表的进行操作
添加User表数据
/**
* 向User表中添加一条记录
*/
private void addData() {
DaoMaster daoMaster = DBManager.getDaoMaster(mContext);
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
mUser = new User();
mUser.setName("Hubery" + System.currentTimeMillis());
mUser.setAge(15);
userDao.insert(mUser);
}
/**
* 更新一条记录
* @param user
*/
public void updateUser(User user) {
DaoMaster daoMaster = DBManager.getDaoMaster(mContext);
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.update(user);
}
/**
* 删除一条记录
*
* @param user
*/
public void deleteUser(User user) {
DaoMaster daoMaster = DBManager.getDaoMaster(mContext);
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
userDao.delete(user);
}
/**
* 查询用户列表
*/
public User queryUserModel(String curName) {
DaoMaster daoMaster = DBManager.getDaoMaster(mContext);
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
qb.where(UserDao.Properties.Name.like("%" + curName + "%")).build();
List<User> list = qb.list();
if (list != null && list.size() > 0) {
Toast.makeText(mContext, list.get(0).getName(), Toast.LENGTH_LONG).show();
return list.get(0);
} else {
return null;
}
}
/**
* 查询用户列表
*/
public List<User> queryUserList() {
DaoMaster daoMaster = DBManager.getDaoMaster(mContext);
DaoSession daoSession = daoMaster.newSession();
UserDao userDao = daoSession.getUserDao();
QueryBuilder<User> qb = userDao.queryBuilder();
List<User> list = qb.list();
return list;
}
当然GreenDao为我们封装的对表的操作还不仅仅是这些,包括表一对多等复杂操作,感兴趣的可以自行去查阅相关文档。
数据库中表升级/降级
说完GreenDao对数据表的基本操作之后,再来看看数据库的升级,数据库的升级需要继承android.database.sqlite包中的SQLiteOpenHelper类,升级/降级的操作需要在onUpgrade()方法中执行。
/**
* 数据库升级
* Created by hubery on 2018/2/9.
*/
public class OpenHelper extends DaoMaster.OpenHelper {
public OpenHelper(Context context, String name) {
super(context, name);
}
public OpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
//判断条件
//操作数据库的更新 有几个表升级都可以传入到下面
MigrationHelper.getInstance().migrate(db,UserDao.class);
}
}
当然在这里我们只是做一个功能的演示,并没有拿oldVersion和newVersion版本号去控制升级/降级。现在我们把升级/降级的操作都放到MigrationHelper中去,先来看看这个类:
**
* Created by hubery on 2018/2/8.
*/
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);// 重新创建新的数据库表
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
/**
* 生成临时列表
*
* @param db
* @param daoClasses
*/
private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);//通过反射拿到表中的字段
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
/**
* 存储新的数据库表 以及数据
*
* @param db
* @param daoClasses
*/
private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class<?> type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
}
if (type.equals(Boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
throw exception;
}
private List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
restoreData(db, daoClasses);
}
这里升级的步骤:先创建一张临时表,把表中数据插入到临时表中,然后新建一个新的表,把临时表的数据拷贝到新表里面去,最后删除临时表。
性能效率对比
因为GreenDao框架对表进行CRU操作的时候,由于其本身底层使用的不是反射,而是编译时期生成的代码,而不是反射的机制,所以相对比其他的ORM关系型数据库而言,效率会高很多。
这是官网的一张对比截图以及官网的一段描述:
所有的ORM关系型数据库中,greendao是最快的。greendao不作任何妥协的性能。数据库非常适合存储大量数据,因此速度很快。使用greendao,大多数实体可以插入,更新,以每秒几千单位率加载。
另外提一下ObjectBox:ObjectBox是移动端数据库框架,灵感来自于NoSql,速度非常快,号称是市面上最快的移动端数据库框架。目前非关系行数据库也就只有Realm 能与之相比。
本文主要讲解了一下greendao的基本使用,包括引入greendao,greendao对于单表的CRUD操作,以及数据库升级,性能对比等。