greenDAO基本使用详解

来源:互联网 发布:知米软件取英文名 编辑:程序博客网 时间:2024/04/25 20:08

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

一、什么是greendao?

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

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

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


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

二、为什么要使用greendao?

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


三、导入依赖库

其实关于这方面大家经常使用开源项目的应该都是很熟悉的,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. * 实体类 */@Entitypublic 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,如图所示:


2、数据库增删改查操作

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

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <EditText        android:id="@+id/edit_name"        android:layout_width="match_parent"        android:layout_height="40dp"        android:hint="请输入用户名"/>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:orientation="horizontal">        <Button            android:id="@+id/btn_add"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:text="增加用户" />        <Button            android:id="@+id/btn_delete"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:text="删除用户" />        <Button            android:id="@+id/btn_update"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:text="修改用户" />        <Button            android:id="@+id/btn_query"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:text="查询用户" />    </LinearLayout>    <android.support.v7.widget.RecyclerView        android:id="@+id/user_list"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginTop="10dp"        android:padding="5dp"/></LinearLayout>

然后再做一些基本的准备工作,这里创建一个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<User> 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<User> 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<UserAdapter.ViewHolder> {    private List<User> mList;    private Context mContext;    public UserAdapter(Context context, List<User> 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方法:


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


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


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


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


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

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

原创粉丝点击