本文转自:http://www.jianshu.com/p/f2737d23cb2a
本例只介绍了 greenDAO 的基本用法与配置,更高级与详细的使用,请参见官方的API文档:http://greenrobot.org/greendao/documentation/javadoc/
greenDao 介绍
在平时的开发过程中,大家一定会或多或少地接触到 SQLite。然而在使用它时,我们往往需要做许多额外的工作,像编写 SQL 语句与解析查询结果等。
greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。
官网:http://greenrobot.org/greendao/
GitHub:https://github.com/greenrobot/greenDAO
之前发布的1.X和2.X版本是比较难用的。需要新建Java Module,然后再项目中配置各个实体的字段等相关属性,然后生成实体以及DAO操作相关的一些类。但是,当你修改了实体中的一些属性,并且这些属性又要在数据库中保存的时候,你会发现每次重新运行generator之前的改变都得重新再来一次。有兴趣的同学可以自行去了解,这里给出个学习链接:http://www.open-open.com/lib/view/open1438065400878.html
关于性能方面,greenDAO 性能远远高于同类的 ORMLite,具体测试结果可见官网:http://greenrobot.org/greendao/features/
实例讲解:
greenDAO3开始使用注解的方式定义实体类(entity),并且是通过安装gradle插件来生成代码。省去了新建项目的繁琐,使用起来也更加简洁明了,我们今天就来讲讲如何使用greenDao3。废话不多说,新手入门直接上Demo代码。
完整代码地址:https://github.com/hibernate3/GreenDaoDemo
环境:JDK 1.8,AndroidStudio 2.2.3
配置gradle
apply plugin: 'org.greenrobot.greendao'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
}
}
在gradle的根模块中加入上述代码后,sync project的时候,gradle会自动去maven仓库下载一个gradle的插件,当然了,这个插件就是为greenDAO服务的,用来生成数据库相关的代码。
简单的介绍下通过gradle插件生成数据库代码的步骤:每次在make project之前,它会扫描项目中所有的@Entity文件(greenDAO中数据库的实体类),根据实体类生成DaoSession、DaoMaster以及所有实体类的dao类,生成的文件默认目录为:build/generated/source/greendao,若不想修改生成的路径,可以将此路径设置为资源目录。我们也可以自定义这个路径,下面就来介绍如何在gradle中配置greenDAO的相关属性:
greendao {
schemaVersion 1
daoPackage 'com.example.greendaodemo.greendao.gen'
targetGenDir 'src/main/java'
}
在gradle的根模块中加入上述代码,就完成了我们的基本配置了。
schemaVersion---->指定数据库schema版本号,迁移等操作会用到
daoPackage-------->通过gradle插件生成的数据库相关文件的包名,默认为你的entity所在的包名
targetGenDir-------->这就是我们上面说到的自定义生成数据库文件的目录了,可以将生成的文件放到我们的java目录中,而不是build中,这样就不用额外的设置资源目录了
完整的gradle配置代码:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "25.0.1"
defaultConfig {
applicationId "com.example.greendaodemo"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
apply plugin: 'org.greenrobot.greendao'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
}
}
greendao {
schemaVersion 1
daoPackage 'com.example.greendaodemo.greendao.gen'
targetGenDir 'src/main/java'
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:23.4.0'
testCompile 'junit:junit:4.12'
//GreenDAO
compile 'org.greenrobot:greendao:3.0.1'
compile 'org.greenrobot:greendao-generator:3.0.0'
//ButterKnife
compile 'com.jakewharton:butterknife:8.4.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
}
编写实体类
package com.example.greendaodemo.greendao.entity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Unique;
/**
* Created by Steven on 16/12/20.
*/
@Entity
public class User {
@Id
private Long id;
@Unique
private String name;
@Transient
private int tempUsageCount;
}
编译项目,User实体类会自动编译,生成get、set方法并且会在com.example.greendaodemo.greendao.gen目录下生成三个文件,DaoMaster 、DaoSession、Dao类:
package com.example.greendaodemo.greendao.entity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Transient;
import org.greenrobot.greendao.annotation.Unique;
/**
* Created by Steven on 16/12/20.
*/
@Entity
public class User {
@Id
private Long id;
@Unique
private String name;
@Transient
private int tempUsageCount;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Generated(hash = 873297011)
public User(Long id, String name) {
this.id = id;
this.name = name;
}
@Generated(hash = 586692638)
public User() {
}
}
关于greenDao3的注解
1.实体注解:
@Entity:将我们的java普通类变为一个能够被greenDAO识别的数据库类型的实体类
schema:告知greenDao当前实体属于哪个schema
active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
nameInDb:在数据中使用的别名,默认使用的是实体的类名
indexes:定义索引,可以跨越多个列
createInDb:标记创建数据库表
@Entity(
// 如果你有超过一个的数据库结构,可以通过这个字段来区分
// 该实体属于哪个结构
schema = "myschema",
// 实体是否激活的标志,激活的实体有更新,删除和刷新的方法
active = true,
// 确定数据库中表的名称
// 表名称默认是实体类的名称
nameInDb = "AWESOME_USERS",
// Define indexes spanning multiple columns here.
indexes = {
@Index(value = "name DESC", unique = true)
},
// DAO是否应该创建数据库表的标志(默认为true)
// 如果你有多对一的表,将这个字段设置为false
// 或者你已经在GreenDAO之外创建了表,也将其置为false
createInDb = false
)
public class User {
...
}
2.基础属性注解:
@Id :主键 Long型,可以通过@Id(autoincrement = true)设置自增长
@Property:设置一个非默认关系映射所对应的列名,默认是的使用字段名 举例:@Property (nameInDb="name")
@NotNull:设置数据库表当前列不能为空
@Transient :添加次标记之后不会生成数据库表的列
3.索引注解:
@Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique:向数据库列添加了一个唯一的约束
4.关系注解:
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系
初始化数据库
创建GreenDaoManager.java:
package com.example.greendaodemo.greendao;
import com.example.greendaodemo.MainApplication;
import com.example.greendaodemo.greendao.gen.DaoMaster;
import com.example.greendaodemo.greendao.gen.DaoSession;
import com.example.greendaodemo.greendao.gen.UserDao;
/**
* Created by Steven on 16/12/20.
*/
public class GreenDaoManager {
private static GreenDaoManager mInstance;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
private GreenDaoManager() {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(MainApplication.getContext(), "users-db", null);
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 getSession() {
return mDaoSession;
}
public DaoSession getNewSession() {
mDaoSession = mDaoMaster.newSession();
return mDaoSession;
}
}
官方推荐将获取 DaoMaster 对象的方法放到 Application 层,这样将避免多次创建生成 Session 对象,不过也可以在代码中写好规避,看个人习惯。
package com.example.greendaodemo;
import android.app.Application;
import android.content.Context;
import com.example.greendaodemo.greendao.GreenDaoManager;
/**
* Created by Steven on 16/12/20.
*/
public class MainApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
GreenDaoManager.getInstance();
}
public static Context getContext() {
return mContext;
}
}
增删改查操作
这里就没有用MVP那一套定义interface和presenter那些东西了,直接在Activity中处理业务逻辑了。新手学习简单清晰一点。直接贴上Activity的代码,布局文件和Adapter请在GitHub上查看,这里主要关注业务处理函数:
package com.example.greendaodemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import com.example.greendaodemo.greendao.GreenDaoManager;
import com.example.greendaodemo.greendao.entity.User;
import com.example.greendaodemo.greendao.gen.UserDao;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.et_name) EditText mNameET;
@BindView(R.id.btn_add) Button mAddBtn;
@BindView(R.id.btn_query) Button mQueryBtn;
@BindView(R.id.btn_delete) Button mDeleteBtn;
@BindView(R.id.btn_update) Button mUpdateBtn;
@BindView(R.id.lv_user) ListView mUserLV;
private UserAdapter mUserAdapter;
private List<User> mUserList = new ArrayList<>();
private UserDao mUserDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initData();
}
private void initData() {
mUserDao = GreenDaoManager.getInstance().getSession().getUserDao();
mUserList = GreenDaoManager.getInstance()
.getSession().getUserDao().queryBuilder().build().list();
mUserAdapter = new UserAdapter(this, mUserList);
mUserLV.setAdapter(mUserAdapter);
}
//查询
private void queryUser(String name) {
List result = mUserDao.queryBuilder()
.where(UserDao.Properties.Name.eq(name)).build().list();
Toast.makeText(MainApplication.getContext(), "查询到:" + result.size() + "条结果",
Toast.LENGTH_SHORT).show();
}
//更新
private void updateUser(String prevName, String newName) {
User findUser = mUserDao.queryBuilder()
.where(UserDao.Properties.Name.eq(prevName)).build().unique();
if (findUser != null) {
findUser.setName(newName);
mUserDao.update(findUser);
Toast.makeText(MainApplication.getContext(), "修改成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainApplication.getContext(), "用户不存在", Toast.LENGTH_SHORT).show();
}
refreshListView();
}
//删除
private void deleteUser(String name) {
User findUser = mUserDao.queryBuilder()
.where(UserDao.Properties.Name.eq(name)).build().unique();
if(findUser != null) {
mUserDao.deleteByKey(findUser.getId());
Toast.makeText(MainApplication.getContext(), "删除成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainApplication.getContext(), "用户不存在", Toast.LENGTH_SHORT).show();
}
refreshListView();
}
//插入
private void insertUser(Long id, String name) {
User user = new User(id, name);
mUserDao.insertOrReplace(user);
refreshListView();
}
private void refreshListView() {
mNameET.setText("");
mUserList.clear();
mUserList.addAll(mUserDao.queryBuilder().build().list());
mUserAdapter.notifyDataSetChanged();
}
@OnClick({R.id.btn_add, R.id.btn_query, R.id.btn_update, R.id.btn_delete})
public void onButtonsClick(View v) {
int viewId = v.getId();
switch (viewId) {
case R.id.btn_add:
insertUser(null, mNameET.getText().toString());
break;
case R.id.btn_query:
queryUser(mNameET.getText().toString());
break;
case R.id.btn_update:
updateUser(mNameET.getText().toString(), "" + System.currentTimeMillis());
break;
case R.id.btn_delete:
deleteUser(mNameET.getText().toString());
break;
default:
break;
}
}
}
数据库升级
1.修改gradle文件
首先在module的gradle文件中修改版本号:
//这里改为最新的版本号 schemaVersion 2
2.修改实体类
@Entity
public class User {
@Property
private int age;
@Property
private String password;
@Id
private Long id;
@Property(nameInDb = "USERNAME")
private String username;
@Property(nameInDb = "NICKNAME")
private String nickname;
}
重新编译项目运行即可。一般的数据库升级这样就可以了,特殊情况可能需要自己编写数据库迁移脚本