GreenDAO是一款开源且面向Android的轻便、快捷的ORM框架,可以将对象映射到SQLite数据库中.它针对Android进行了高度优化,性能最大化且内存消耗极少同时还支持数据库加密.[百科]
我的项目名称为Search
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'//添加插件
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
之后点击Sync Project
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'
之后在dependencies中添加依赖
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'org.greenrobot:greendao:3.2.2' // 添加依赖
}
之后配置数据库相关信息
greendao {
schemaVersion 1 //当前数据库版本
targetGendir 'src/main/java'//指定生成代码的目录
daoPackage 'com.lab.search'//生成代码到具体的包下
}
配置就完成了,之后点击Sync Now
在Sync时,出现了下载依赖很慢的事情,所以我在工程目录下的build.gradle将buildscript的repositories改成了
repositories {
google()
//jcenter()
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
以及
allprojects {
repositories {
google()
//jcenter()
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
}
把地址改成了阿里云的仓库,下载就快了。
在目录下创建一个Package名为bean,在bean包下面创建一个Java类,类为实体类,即仅有属性以及getter、setter、构造方法以及toString()方法的类,一个实体类则对应一张数据库的表,我将这个实体类取名为UserInfo,类中有id,userName,phoneNumber,address等属性
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Property;
@Entity
public class UserInfo {
@Id
private Long id;
@Property(nameInDb = "user_name")
private String userName;
@Property(nameInDb = "phone_number")
private String phoneNumber;
@Property(nameInDb = "address")
private String address;
}
在这里,我用了许多注解,而这些注解有什么作用呢?简单介绍一下在GreenDao中常用的一些注解
@Entity:将我们的java普通类变为一个能够被greenDAO识别的数据库类型的实体类,也就是将这个类标记为要映射到数据库的实体类
@Id:主键,选择使用long或Long,若写成@Id(autoincrement = true)则可标记为自增长。
@Property(nameInDb = “”) :表示该类的这个属性是表的一个字段(即一列),且非主键,nameInDb值则是这个字段的名字,
@NotNull: 不为null
@Transient 不保存于数据库,添加此标记后不会生成数据库表的列
@Index 作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique: 唯一约束,也就是值必须唯一
@ToOne 表为一对一关系
@ToMany 一对多关系
@Generated 由greendao产生的构造函数或方法,此注释标记的所有代码元素都可以在生成的下一次运行中更改/删除
编译(Make Project)之后,代码就自动生成了构造函数及set get方法,之后再加上toString方法,在进行数据库操作时,可用toString()方法打印来验证结果的正确性。
@Entity
public class UserInfo {
@Id
private long id;
@Property(nameInDb = "user_name")
private String userName;
@Property(nameInDb = "phone_number")
private String phoneNumber;
@Property(nameInDb = "address")
private String address;
@Generated(hash = 459973421)
public UserInfo(long id, String userName, String phoneNumber, String address) {
this.id = id;
this.userName = userName;
this.phoneNumber = phoneNumber;
this.address = address;
}
@Generated(hash = 1279772520)
public UserInfo() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return this.userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", userName='" + userName + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
", address='" + address + '\'' +
'}';
}
}
上述操作结束之后,在工程目录下,GreenDAO的生成目录中可以找到相应的数据库操作类,我实体类UserInfo的操作类名称为UserInfoDAO,同时也会自动生成DaoMaster和DaoSession
可以看到生成了三个文件,一个是实体类的操作类,还有DaoMaster,DaoSession等类。
我们先看看DaoMaster类,DaoMaster类主要定义了几个函数
(1)createAllTables、dropAllTables
/** Creates underlying database table using DAOs. */
public static void createAllTables(Database db, boolean ifNotExists) {
UserInfoDao.createTable(db, ifNotExists);
}
/** Drops underlying database table using DAOs. */
public static void dropAllTables(Database db, boolean ifExists) {
UserInfoDao.dropTable(db, ifExists);
}
这两个方法表明了DaoMaster的两个作用,创建和删除所有表。
(2)newSession
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
这两个类可以创建Session绘画,有两种重载形式,一种可以让我们自定义类型。
(3)构造函数
public DaoMaster(SQLiteDatabase db) {
this(new StandardDatabase(db));
}
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
registerDaoClass(UserInfoDao.class);
}
两个重载形式,一个时生成一个数据库,另一个则是注册Config,查看一下registerDaoClass类则会发现,daoConfigMap是一个Map结构
protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap;
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
通过传进来的UserInfoDao.class作为key,对这个daoConfig进行绑定操作。
而进入到DaoConfig类中,查看DaoConfig的源码时,可以看到注释中的介绍
/**
* Internal class used by greenDAO. DaoConfig stores essential data for DAOs, and is hold by AbstractDaoMaster. This
* class will retrieve the required information from the DAO classes.
*/
DaoConfig存储DAO的基本数据,并由AbstractDaoMaster所持有。 该类将从DAO类中检索所需的信息。即将DAO类作为key来检索信息
而DaoSession类则主要是用来操作DAO对象的,它有三个方法
(1)构造函数
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
daoConfigMap) {
super(db);
userInfoDaoConfig = daoConfigMap.get(UserInfoDao.class).clone();
userInfoDaoConfig.initIdentityScope(type);
userInfoDao = new UserInfoDao(userInfoDaoConfig, this);
registerDao(UserInfo.class, userInfoDao);
}
从代码中我们可以看到,构造函数做了这么几件事儿
1.取出map中对应DAO的daoConfig
2.初始化缓存类型
3.根据配置可以得到一个DAO对象
4.将DAO对象进行注册,也是通过Map进行管理
(2)getUserInfoDao方法
public UserInfoDao getUserInfoDao() {
return userInfoDao;
}
可返回dao对象,说明可以返回dao对象并对其进行具体的操作了。
(3)clear函数
public void clear() {
userInfoDaoConfig.clearIdentityScope();
}
clear函数就是清楚缓存的函数, clearIdentityScope()
其实,上面操作过后,可以直接进行数据库的使用了,但是这里仍然编写了一个DaoManage类,希望在使用过程中更方便的进行初始化工作
主要内容就是进行各种变量的初始化之后,获得数据库,获取DaoSession对象好对表进行数据操作。
代码如下:
public class DaoManage {
private Context mContext;
//数据库的名称
private static final String DB_NAME = "user.db";
//多线程中要被共享的要用volatile修饰,Greendao管理类
private volatile static DaoManage mInstance;
//DAOMaster 保存数据库对象
private static DaoMaster mDaoMaster;
//Helper类
private static DaoMaster.DevOpenHelper mHelper;
//Dao对象中的增删改查的对象
private static DaoSession mDaoSession;
private DaoManage(){
}
//使用单例模式来获取GreenDao管理类的对象,即操作数据库的对象
public static DaoManage getInstance(){
if (mInstance == null){
synchronized (DaoManage.class){
if(mInstance == null){
mInstance = new DaoManage();
}
}
}
return mInstance;
}
//初始化上下文
public void init(Context context){
this.mContext = context;
}
//创建(若没有)并获取数据库
public DaoMaster getDaoMaster(){
if(mDaoMaster == null){
//创建一个数据库
mHelper = new DaoMaster.DevOpenHelper(mContext, DB_NAME, null);
mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());
}
return mDaoMaster;
}
//获取DaoSession对象,完成增删改查操作
public DaoSession getDaoSession(){
if(null == mDaoSession){
//若表为空,new一个
if(null == mDaoMaster){
//若数据库为空,则创建数据库
mDaoMaster = getDaoMaster();
}
mDaoSession = mDaoMaster.newSession();
}
return mDaoSession;
}
//关闭连接
public void closeConnection(){
if(mHelper != null){
mHelper.close();
mHelper = null;
}
if(mDaoSession != null){
mDaoSession.clear();
mDaoSession = null;
}
}
}
实际上,GreenDao的数据库操作已经十分简便,我们是可以直接进行使用的,但是为了更加整洁的使用,我还是将增删改查的操作进行了封装,写在了DBHelper类中
private UserInfoDao userInfoDao = DaoManage.getInstance().getDaoSession().getUserInfoDao();
//查找(按id查找)
public UserInfo queryById(Long id){
List<UserInfo> list = userInfoDao.queryBuilder().where(UserInfoDao.Properties.Id.eq(id)).build().list();
UserInfo userInfo = list.isEmpty() ? null : list.get(0);
return userInfo;
}
//查找全部
public List<UserInfo> queryAll(){
return userInfoDao.queryBuilder().build().list();
}
查询还可以批量查询,多条件查询,模糊搜索等等内容,由于太多,就不全部列出来了,可以查阅相关文档按照需要进行使用。
//增加
public void add(UserInfo userInfo){
if (queryById(userInfo.getId()) == null){
userInfoDao.insert(userInfo);
}else{
userInfoDao.update(userInfo);
}
}
//批量增加
public void add(List<UserInfo> userInfoList){
userInfoDao.insertInTx(userInfoList);
}
//删除一个对象
public void delete(UserInfo userInfo){
userInfoDao.delete(userInfo);
}
//删除一个列表的对象
public void deleteByList(List<UserInfo> userInfoList){
userInfoDao.deleteInTx(userInfoList);
}
//按主键删除
public void delteByKey(long key){
userInfoDao.deleteByKey(key);
}
//按主键列表删除
public void deleteByKeyList(List<Long> idList){
userInfoDao.deleteByKeyInTx(idList);
}
//删除所有
public void deleteAll(){
userInfoDao.deleteAll();
}
//修改
public boolean update(UserInfo userInfo){
UserInfo findUser = userInfoDao.queryBuilder().where(UserInfoDao.Properties.Id.eq(userInfo)).build().unique();
if (findUser != null){
userInfoDao.update(userInfo);
return true;
}else{
return false;
}
}
在Android6.0之后,我们需要在代码中先对权限进行检查,即检查有没有文件的读写权限,如果没有权限,要申请权限,所以在onCreate()函数中,在前面要先加入一段代码:
//检查当前权限,如果没有,申请request,
if(ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//申请一个或多个权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
}, 100);
}
在类中添加DBHelper类的成员对象,并进行初始化
DBHelper dbHelper = new DBHelper();
之后可以在onCreate()函数中进行使用
先增加一个数据
UserInfo userInfo1 = new UserInfo(null, "laichangping1", "12345678901", "longyan");
dbHelper.add(userInfo1);
进行查找,并查看结果
//查找
List<UserInfo> userInfos = dbHelper.queryAll();
for(UserInfo userInfo : userInfos){
Log.i("add>>", userInfo.toString());
}
添加成功
之后,再添加userInfo2和userInfo3,将他们按列表添加,再进行查找
List<UserInfo> userInfoList = new ArrayList<>();
userInfoList.add(userInfo2);
userInfoList.add(userInfo3);
dbHelper.add(userInfoList);
//查找
List<UserInfo> userInfos = dbHelper.queryAll();
for(UserInfo userInfo : userInfos){
Log.i("add>>", userInfo.toString());
}
//按主键删除
dbHelper.deleteByKey(userInfo1.getId());
//查找
List<UserInfo> userInfos = dbHelper.queryAll();
for(UserInfo userInfo : userInfos){
Log.i("add>>", userInfo.toString());
}
//按列表删除
List<UserInfo> deleteInfos = new ArrayList<>();
deleteInfos.add(userInfo2);
deleteInfos.add(userInfo3);
dbHelper.deleteByList(deleteInfos);
//查找
List<UserInfo> userInfos = dbHelper.queryAll();
for(UserInfo userInfo : userInfos){
Log.i("add>>", userInfo.toString());
}
则数据全部被删除干净
同样也可以用Key列表进行删除,效果一样
List<Long> idList = new ArrayList<>();
idList.add(userInfo2.getId());
idList.add(userInfo3.getId());
dbHelper.deleteByKeyList(idList);
接下来新增一条数据并将它进行修改,就添加userInfo1罢,然后将userInfo1改为userInfo2
UserInfo userInfo1 = new UserInfo((long)1,"laichangping1","12345678901", "longyan");
UserInfo userInfo2 = new UserInfo((long)2,"laichangping2","45678912345", "fuzhou");
//添加userInfo1
dbHelper.add(userInfo1);
//查找修改前
List<UserInfo> userInfos1 = dbHelper.queryAll();
for(UserInfo userInfo : userInfos1){
Log.i("修改前", userInfo.toString());
}
//修改为UserInfo2
userInfo1.setUserName(userInfo2.getUserName());
userInfo1.setAddress(userInfo2.getAddress());
userInfo1.setPhoneNumber(userInfo2.getPhoneNumber());
dbHelper.update(userInfo2);
//查找修改后
List<UserInfo> userInfos2 = dbHelper.queryAll();
for(UserInfo userInfo : userInfos2){
Log.i("修改后", userInfo.toString());
}
以上就是GreenDao数据库的基本使用方法,本人才疏学浅,也借鉴了不少网上的资料,仅作学习记录之用,如若有误,欢迎各位批评指正
GreenDao是一个对Android设计的对象关系映射(ORM)工具,具有很强的性能,并且操作丰富多样,大大降低了编写代码的时间成本,除了上述提到的操作外,还可以自定义sql语句进行数据库操作以及其他的操作。
并且功能也十分强大,通过注解可以自动生成代码,既可以减少代码编写时间,也可以减少代码量。通过调用api函数的形式进行增删改查,也无需重复进行sql语句的编写,节省了时间。本次的实践也受益匪浅。
@author 068赖昌平
原文:原文地址