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的对象,并且通过公共方法对外能够直接获取DaoMaster和DaoSession的对象,在私有构造中我们做了一些初始化的操作,代码如下:
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
- greenDAO基本使用详解
- greenDao的基本使用及用法详解
- GreenDao 的基本使用
- GreenDao 基本使用
- greenDao--3.2基本使用
- GreenDao-基本使用
- GreenDAO 3.0 基本使用
- greenDao 3.0基本使用
- greenDao的基本使用
- GreenDao基本使用
- Android GreenDao基本使用
- Android GreenDao基本使用
- GreenDao基本使用_
- greenDao的基本使用
- GreenDao的基本使用
- greenDao的基本使用
- Android GreenDao使用详解
- GreenDao的使用详解
- Oracle Linux 6.4安装Oracle 11g R2+RAC+ASM图文详解
- Android-性能优化-UI优化
- Milkway DataBase
- Kotlin Servlet
- python再复习(2)list、tuple、条件判断和循环、字典和set
- greenDAO基本使用详解
- JavaScript中的闭包
- MySQL添加字段和修改字段的方法
- define my data variable
- WOJ1208-Sherlock's Code
- JVM的栈内存
- OpenCV简单操作-图像均值滤波
- 【跟着imooc重学java】Java SE 与 Java Me 、Java EE之间的关系
- tensorflow 报错内容总结