greenDAO基本使用详解

这篇文章创建于九月份,但是一直拖到现在才去写,真是惭愧,懒真的很可怕。这是关于Android中使用greenDao进行数据库的CRUD操作的介绍,参考了不少大神的作品,这里做一个总结。

一、什么是greendao?

GreenDao官网地址:http://greenrobot.org/greendao/

GitHub地址:https://github.com/greenrobot/greenDAO

我在这里直接截取官网上的一段说明,介绍的也是简洁明了啊:

greenDAO基本使用详解_第1张图片

大致意思是:greenDAO是一款开源的Android 对象关系映射库,使SQLite数据库的开发变得有趣。它减轻开发人员处理低级数据库需求,同时节省开发时间。 SQLite是一个很棒的嵌入式关系数据库。不过,编写SQL和解析查询结果是相当乏味和耗时的任务。通过将Java对象映射到数据库表(称为ORM“对象/关系映射”),greenDAO可以将它们从这些映射释放出来。这样,您可以使用简单的面向对象的API来存储,更新,删除和查询Java对象。

二、为什么要使用greendao?

根据其官网上的描述它的性能要高于其他几个同类的库,同时我也对比了它和Realm这个库,发现性能可能要比Realm低一些,但是它比Realm轻,简言之就是它的体积比较小,Realm太大了,这样综合性的比较下来,发现greenDao是最好的选择,效率高,体积小,并且GitHub上面的star数也是相当高,更新也比较频繁,有专门的团队在维护。

greenDAO基本使用详解_第2张图片

三、导入依赖库

其实关于这方面大家经常使用开源项目的应该都是很熟悉的,github上面都是有相关的引入方法和Wiki的,在这里为了以后自己使用方便,还是记录一下,下次直接从这里Copy即可:

1、首先在项目工程的gradle文件中添加以下依赖(红色标注):

buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}
2、然后在项目moudle的gradle文件中添加以下依赖(红色标注):

apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:26.0.0-alpha1'
    compile 'org.greenrobot:greendao:3.2.2'
    // add library
    compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
}
3、添加完以上依赖之后同步项目,然后它会去maven仓库中下载一个专门用于greendao的gradle插件,通过这个插件我们可以自动生成相关数据库代码。我们在生成代码时会先点击AS中的make project,就是那个锤子一样的绿色按钮,然后开始扫描项目中的数据库实体类,根据实体类生成DaoMaster、DaoSession和各个实体的Dao类,这些文件的默认路径在build/generated/source/greendao 这里,但是实际开发中推荐自定义目录,方便查找,具体方法是在app的gradle文件的根目录中进行配置,定义一个greendao闭包,在里面添加相关属性和属性值即可:

greendao{
    schemaVersion 1
    daoPackage 'com.jarchie.greendao.gen'
    targetGenDir 'src/main/java'
}
简单说明:schemaVersion:数据库schema版本号,迁移等操作会用到;daoPackage:通过gradle插件生成的数据库相关文件的包名,默认为你的entity所在的包名;targetGenDir:自定义生成数据库文件的目录;好了,添加完以上代码,我们的配置实际上就已经完成了。

四、使用过程详解

1、编写数据库实体类

新建一个JavaBean,然后定义几个属性,利用greendao注解的语法进行定义,然后点击make project,编译完成之后会自动生成相关代码。下面简单介绍一下几个属性相关的注解(这部分是引用别人的):

@Id:通过这个注解标记的字段必须是Long类型的,这个字段在数据库中表示它就是主键,并且它默认就是自增的
@Property:设置一个非默认关系映射所对应的列名,默认是使用字段名,例如:@Property(nameInDb = "name")
@NotNull:设置数据库表当前列不能为空
@Transient:添加此标记后不会生成数据库表的列,只是作为一个普通的java类字段,用来临时存储数据的,不会被持久化

具体代码为:

package com.jarchie.greendao.entity;

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Generated;

/**
 * Created by Jarchie on 2017\10\30 0030.
 * 实体类
 */
@Entity
public class User {
    @Id
    private Long id;
    private String name;
    @Transient
    private int tempUsageCount;
    @Generated(hash = 873297011)
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }
    @Generated(hash = 586692638)
    public User() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

然后,你会发现在我们之前指定的目录 com.jarchie.greendao.gen 下面也生成了数据库相关的操作类:DaoMaster、DaoSession、UserDao,如图所示:

greenDAO基本使用详解_第3张图片

2、数据库增删改查操作

这里我做了个例子:界面中放了四个按钮,分别进行增删改查操作,主界面布局如下图所示:




    

    
        
greenDAO基本使用详解_第4张图片
然后再做一些基本的准备工作,这里创建一个GreenDaoManager.java类,在这个类里面我们通过单例模式来获取GreenDao的对象,并且通过公共方法对外能够直接获取DaoMasterDaoSession的对象,在私有构造中我们做了一些初始化的操作,代码如下:

package com.jarchie.greendao;

import com.jarchie.greendao.gen.DaoMaster;
import com.jarchie.greendao.gen.DaoSession;

/**
 * Created by Jarchie on 2017\10\30 0030.
 * GreenDao管理类
 */

public class GreenDaoManager {
    private static GreenDaoManager mInstance;
    private DaoMaster mDaoMaster;
    private DaoSession mDaoSession;

    private GreenDaoManager(){
        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(MyApplication.getContext(), "test-db", null);
        DaoMaster mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
        mDaoSession = mDaoMaster.newSession();
    }

    public static GreenDaoManager getInstance(){
        if (mInstance == null){
            mInstance = new GreenDaoManager();
        }
        return mInstance;
    }

    public DaoMaster getMaster(){
        return mDaoMaster;
    }

    public DaoSession getDaoSession(){
        return mDaoSession;
    }

    public DaoSession getNewSession(){
        mDaoSession = mDaoMaster.newSession();
        return mDaoSession;
    }

}
“test-db”是自定的数据库名称,一个DaoMaster就代表着一个数据库的连接,DaoSession可以让我们使用一些Entity的基本操作和获取Dao操作类,DaoSession可以创建多个,每一个都是属于同一个数据库连接的。我们通过单例类可以拿到UserDao,然后通过UserDao就可以操作User这张表。

然后我们在MyApplication中进行初始化,代码如下:

package com.jarchie.greendao;

import android.app.Application;
import android.content.Context;

/**
 * Created by Jarchie on 2017\10\30 0030.
 * App全局配置类
 */

public class MyApplication extends Application {
    private static Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        GreenDaoManager.getInstance();
    }

    public static Context getContext() {
        return mContext;
    }
}
准备工作完成了,下面正式进入CRUD四大操作:

增加操作insert(User entity):插入一条记录

首先拿到UserDao对象,可以直接操作这张表,然后调用insert的api,传入一个数据对象,这样就新增了一条数据,id可以直接传入null,因为主键默认为自增的,name就是User的属性姓名,代码如下:

UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
User user = new User(id, name);
userDao.insert(user);
删除操作
  • deleteBykey(Long key) :根据主键删除一条记录。
  • delete(User entity) :根据实体类删除一条记录,一般结合查询方法,查询出一条记录之后删除。
  • deleteAll(): 删除所有记录。
UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
User findUser = userDao.queryBuilder().where(UserDao.Properties.Name.eq(name)).build().unique();
if (findUser != null) {
    userDao.deleteByKey(findUser.getId());
}
修改操作update(User entity):更新一条记录

UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
User findUser = userDao.queryBuilder().where(UserDao.Properties.Name.eq(prevName)).build().unique();
if (findUser != null) {
    findUser.setName(newName);
    GreenDaoManager.getInstance().getDaoSession().getUserDao().update(findUser);
    Toast.makeText(MyApplication.getContext(), "修改成功", Toast.LENGTH_SHORT).show();
} else {
    Toast.makeText(MyApplication.getContext(), "用户不存在", Toast.LENGTH_SHORT).show();
}
查询操作
  • loadAll():查询所有记录
  • load(Long key):根据主键查询一条记录
  • queryBuilder().list():返回:List
  • queryBuilder().where(UserDao.Properties.Name.eq("")).list():返回:List
  • queryRaw(String where,String selectionArg):返回:List
UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
List<User> list = userDao.queryBuilder()
        .where(UserDao.Properties.Id.notEq(999))
        .orderDesc(UserDao.Properties.Id)
        .limit(3)
        .build().list();
这里是按照id不等于999降序查询3条数据,拿到一个List集合,然后我们可以将数据展示到界面上。

详细代码如下:

package com.jarchie.greendao;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.jarchie.greendao.adapter.UserAdapter;
import com.jarchie.greendao.entity.User;
import com.jarchie.greendao.gen.UserDao;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private RecyclerView mRecyclerView;
    private EditText mEditName;
    private Button mBtnAdd,mBtnDelete,mBtnUpdate,mBtnQuery;
    private List mUserList = new ArrayList<>();
    private UserAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListener();
        initData();
    }

    //初始化数据
    private void initData() {
        mUserList = GreenDaoManager.getInstance().getDaoSession().getUserDao().queryBuilder().build().list();
        mAdapter = new UserAdapter(this, mUserList);
        mRecyclerView.setAdapter(mAdapter);
    }

    //初始化监听事件
    private void initListener() {
        mBtnAdd.setOnClickListener(this);
        mBtnDelete.setOnClickListener(this);
        mBtnUpdate.setOnClickListener(this);
        mBtnQuery.setOnClickListener(this);
    }

    //初始化View
    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.user_list);
        mEditName = (EditText) findViewById(R.id.edit_name);
        mBtnAdd = (Button) findViewById(R.id.btn_add);
        mBtnDelete = (Button) findViewById(R.id.btn_delete);
        mBtnUpdate = (Button) findViewById(R.id.btn_update);
        mBtnQuery = (Button) findViewById(R.id.btn_query);
        //创建默认的线性LayoutManager
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));
        //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
        mRecyclerView.setHasFixedSize(true);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_add:
                insertUser(null, mEditName.getText().toString());
                break;
            case R.id.btn_delete:
                deleteUser(mEditName.getText().toString());
                break;
            case R.id.btn_update:
                updateUser("张三","张大大");
                break;
            case R.id.btn_query:
                queryUser();
                break;
        }
    }

    /**
     * 查询数据
     */
    private void queryUser(){
        UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
        List list = userDao.queryBuilder()
                .where(UserDao.Properties.Id.notEq(999))
                .orderDesc(UserDao.Properties.Id)
                .limit(3)
                .build().list();
        mUserList.clear();
        mUserList.addAll(list);
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 根据名字更新某条数据的名字
     */
    private void updateUser(String prevName, String newName) {
        UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
        User findUser = userDao.queryBuilder().where(UserDao.Properties.Name.eq(prevName)).build().unique();
        if (findUser != null) {
            findUser.setName(newName);
            GreenDaoManager.getInstance().getDaoSession().getUserDao().update(findUser);
            Toast.makeText(MyApplication.getContext(), "修改成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(MyApplication.getContext(), "用户不存在", Toast.LENGTH_SHORT).show();
        }
        mUserList.clear();
        mUserList.addAll(userDao.queryBuilder().build().list());
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 根据名字删除某个用户
     */
    private void deleteUser(String name) {
        UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
        User findUser = userDao.queryBuilder().where(UserDao.Properties.Name.eq(name)).build().unique();
        if (findUser != null) {
            userDao.deleteByKey(findUser.getId());
        }
        mEditName.setText("");
        mUserList.clear();
        mUserList.addAll(userDao.queryBuilder().build().list());
        mAdapter.notifyDataSetChanged();
    }

    /**
     * 向本地数据库里添加数据
     */
    private void insertUser(Long id, String name) {
        UserDao userDao = GreenDaoManager.getInstance().getDaoSession().getUserDao();
        User user = new User(id, name);
        userDao.insert(user);
        mEditName.setText("");

        mUserList.clear();
        mUserList.addAll(userDao.queryBuilder().build().list());
        mAdapter.notifyDataSetChanged();
    }

}
Adapter中的代码:

package com.jarchie.greendao.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.jarchie.greendao.R;
import com.jarchie.greendao.entity.User;

import java.util.List;

/**
 * Created by Jarchie on 2017\10\30 0030.
 * 适配器
 */

public class UserAdapter extends RecyclerView.Adapter {
    private List mList;
    private Context mContext;

    public UserAdapter(Context context, List list) {
        this.mList = list;
        this.mContext = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_user, parent, false);
        return new ViewHolder(view);
    }

       @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tv_name.setText(mList.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return mList == null ? 0 : mList.size();
    }

    //自定义的ViewHolder,持有每个Item的的所有界面元素
    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView tv_name;

        ViewHolder(View view) {
            super(view);
            tv_name = (TextView) view.findViewById(R.id.tv_name);
        }
    }

}

基本操作就说到这里,其实这里还有一个自定义sql语句查询,当我们需要用到group by或者left join等复杂的语句,可以调用android原生的sqlite去进行查询,这种使用暂时涉及的不多,所以并未做说明,需要的可以去网上查询相关资料(怪我咯)。

数据库升级

如果某张表修改了字段,或者新增了一张表,必须要修改build.gradle中的schemaVersion,否则当你升级app的时候,如果进行了数据库操作,会发现列不匹配或者表不存在等问题,直接会导致app闪退。但是如果仅仅是将schemaVersion加1,虽然程序不会崩溃,并且数据表的结构也会更新成功,但是之前表中的数据会全部清空。我们需要进行手动操作来进行数据库里面的数据迁移,过去的做法通常是:创建临时表(结构与上一版本的表结构相同),将旧数据移到临时表中,删除旧版本的表,创建新版本的表,将临时表中的数据转移到新表中,最后再删除临时表。这里我们使用一个开源库,手感真是不要太好,操作起来十分方便,很容易就做到既能保证原有数据不丢失又很自如的新增字段,项目地址:https://github.com/yuweiguocn/GreenDaoUpgradeHelper

使用方式:首先在项目工程的gradle文件中添加如下依赖(红色标注):

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
}
然后在app的module的gradle文件的dependencies闭包中添加以下依赖(红色标注):

//数据库更新依赖库
compile 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.0.0'

然后我们修改schemaVersion值为2,意思为更新数据库表(红色标注):

greendao{
    schemaVersion 2
    daoPackage 'com.jarchie.greendao.gen'
    targetGenDir 'src/main/java'
}
然后新建一个数据库帮助类MySQLiteOpenHelper,继承自DaoMaster.OpenHelper这个类,重写onUpgrade()方法,传入需要做升级操作的表,这里我们传入的是UserDao.class ,代码如下:

package com.jarchie.greendao;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.github.yuweiguocn.library.greendao.MigrationHelper;
import com.jarchie.greendao.gen.DaoMaster;
import com.jarchie.greendao.gen.UserDao;

import org.greenrobot.greendao.database.Database;

/**
 * Created by Jarchie on 2017\10\31 0031.
 * 数据库更新辅助操作类
 */

@SuppressWarnings("unchecked")
public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
    public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    public void onUpgrade(Database db, int oldVersion, int newVersion) {
        MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {

            @Override
            public void onCreateAllTables(Database db, boolean ifNotExists) {
                DaoMaster.createAllTables(db, ifNotExists);
            }

            @Override
            public void onDropAllTables(Database db, boolean ifExists) {
                DaoMaster.dropAllTables(db, ifExists);
            }
        }, UserDao.class);
    }
}

然后修改数据库管理类,将初始化操作中的DevOpenHelper改为我们自己的MySQLiteOpenHelper(绿色标注):

 private GreenDaoManager(){
//        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(MyApplication.getContext(), "test-db", null);
//        DaoMaster mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
        MySQLiteOpenHelper helper = new MySQLiteOpenHelper(MyApplication.getContext(),"test-db",null);
        mDaoMaster = new DaoMaster(helper.getWritableDatabase());
        mDaoSession = mDaoMaster.newSession();
    }

接着我们在User这个实体类中新增一个字段:age,表示年龄,然后点击make project重新编译一次,生成相关setter和getter方法:

greenDAO基本使用详解_第5张图片

然后在MainActivity.java中修改报错的代码,在增加操作中加入年龄这个参数:

greenDAO基本使用详解_第6张图片

然后我们到UserAdapter.java中做简单的修改,在显示姓名的后面添加上显示年龄的代码:

greenDAO基本使用详解_第7张图片

然后在逻辑代码里面新增用户的时候指定年龄这个字段值为“18”,并新增两个用户:


好了,到这里就已经完成了数据库的升级操作了,运行我们的项目,看一下效果吧:

greenDAO基本使用详解_第8张图片

以上就是greenDAO的基本使用过程,欢迎留言讨论,我已经把项目放到码云上面了,有需要的可以浏览查看。

项目地址:https://gitee.com/jarchie/GreenDaoDemo

你可能感兴趣的:(数据库)