ORM(Object Relational Mapping)框架采用元数据来描述对象一关系映射细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中。是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的. 两者之间是不匹配的.而ORM作为项目中间件形式实现数据在不同场景下数据关系映射. 对象关系映射是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.ORM就是这样而来的。
GreenDAO是一个开源的安卓ORM框架,能够使SQLite数据库的开发再次变得有趣。它减轻开发人员处理低级数据库需求,同时节省开发时间。 SQLite是一个令人敬畏的内嵌的关系数据库,编写SQL和解析查询结果是相当乏味和耗时的任务。通过将Java对象映射到数据库表(称为ORM,“对象/关系映射”),GreenDAO可以将它们从这些映射中释放出来,这样,您可以使用简单的面向对象的API来存储,更新,删除和查询数据库。
简单的讲,GreenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。
官网设计目标:
是Android的一个轻快的ORM,它将对象映射到SQLite数据库。 针对Android的高度优化,greenDAO提供了卓越的性能,并且占用最少的内存。
Maximum performance (probably the fastest ORM for Android):系能最大化
Easy to use APIs:便于使用
Highly optimized for Android:对于Android高度优化
Minimal memory consumption:最小化内存开销
Small library size, focus on the essentials:较小的文件体积,只集中在必要的部分上。
优点:
坚如磐石:greenDAO自2011年以来一直在使用,并被无数的着名应用程序使用
超级简单:在V3中带有注释的简洁而直接的API
小:库是<150K,它只是简单的Java jar(不依赖于CPU的本机部分)
快速:可能是Android智能代码生成驱动的最快的ORM
安全和富有表现力的查询API:QueryBuilder使用属性常量来避免拼写错误
强大的连接:跨实体查询,甚至是复杂关系的连锁连接
灵活的属性类型:使用自定义类或枚举来表示实体中的数据
加密:支持SQLCipher加密数据库
整体来说,集成后一共会有至少6个类文件,三个自动生成,三个手动配置创建,以下内容均是根据这些类来操作,结构不清楚请参考下图:
// In your root build.gradle file:项目project根目录下的的build.gradle文件
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:APPmodule下的build.gradle文件
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
compile 'org.greenrobot:greendao:3.2.2' // add library
}
另外,在APPmodule下的build.gradle文件的android{}同级目录下添加配置:
/**
* schemaVersion:指定数据库schema版本号,迁移等操作会用到;
* daoPackage:通过gradle插件生成的数据库相关文件的包名,默认为你的entity所在的包名;
* targetGenDir:自定义生成数据库文件的目录,可以将生成的文件放到我们的java目录中,而不是build中,
* 这样就不用额外的设置资源目录了。
*/
greendao {
schemaVersion 1
// daoPackage 'com.ping.greendao.gen'
daoPackage 'com.lab.web.entity.greendao'
targetGenDir 'src/main/java'
}
注意,此处我们只需要定义类名,加上@Entity注解和参数名即可,不用手动生成构造函数和get,set方法。
此时点击AS中的MakeProject按钮,GreenDao会为我们的实体类生成对应的Getter、Setter方法以及两个构造函数,同时在我们配置的com.ping.greendao.gen包下生成了三个对应类文件DaoMaster、DaoSession和MeiziDao,之后所有相关的数据库操作都依靠这三个文件了;
这里再提一下,生成的三个类文件的路径和APPmodule的build.gradle文件中的greendao{}配置的路径有关系,如果没有配置就会生成在APP下的build文件夹中,这样多少有些膈应,所以还是配置一下路径比较安心。此步骤完成效果后如下图:
其中实体类完成代码:
package com.lab.web.entity.greendaoentity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
/**
* Created by ytf on 2018/2/8.
*/
@Entity
public class SearchHistroyEntry {
@Id(autoincrement = true)
private Long search_id;
private String histry_searchStr;
@Generated(hash = 250291344)
public SearchHistroyEntry(Long search_id, String histry_searchStr) {
this.search_id = search_id;
this.histry_searchStr = histry_searchStr;
}
@Generated(hash = 237453182)
public SearchHistroyEntry() {
}
public Long getSearch_id() {
return this.search_id;
}
public void setSearch_id(Long search_id) {
this.search_id = search_id;
}
public String getHistry_searchStr() {
return this.histry_searchStr;
}
public void setHistry_searchStr(String histry_searchStr) {
this.histry_searchStr = histry_searchStr;
}
}
PS :DaoMaster、DaoSession、实体类DAO的作用:
DaoMaster:使用greenDAO的切入点。DaoMaster保存数据库对象(SQLiteDatabase)并管理特定模式的DAO类(而不是对象)。 它具有静态方法来创建表或将它们删除。 其内部类OpenHelper和DevOpenHelper是在SQLite数据库中创建模式的SQLiteOpenHelper实现。一个DaoMaster就代表着一个数据库的连接。
DaoSession:管理特定模式的所有可用DAO对象,您可以使用其中一个getter方法获取。 DaoSession还为实体提供了一些通用的持久性方法,如插入,加载,更新,刷新和删除。 DaoSession可以让我们使用一些Entity的基本操作和获取Dao操作类,DaoSession可以创建多个,每一个都是属于同一个数据库连接的。
实体类DAO:数据访问对象(DAO)持续存在并查询实体。 对于每个实体,GreenDAO生成一个DAO。 它比DaoSession有更多的持久化方法,例如:count,loadAll和insertInTx。
package com.lab.web.entity.greendaoentity;
import android.content.Context;
import com.lab.web.entity.greendao.DaoMaster;
import com.lab.web.entity.greendao.DaoSession;
import org.greenrobot.greendao.query.QueryBuilder;
/**
* 用于创建数据库、创建数据库表、包含增删改查的操作以及数据库的升级。
* Created by ytf on 2018/2/8.
*/
public class GreenDaoManager {
private static final String TAG = GreenDaoManager.class.getSimpleName();
private static final String DB_NAME = "search_history";
private Context context;
//多线程中要被共享的使用volatile关键字修饰
private volatile static GreenDaoManager manager = new GreenDaoManager();
private static DaoMaster sDaoMaster;
private static DaoMaster.DevOpenHelper sHelper;
private static DaoSession sDaoSession;
public void init(Context context){
this.context = context;
}
/**
* 单例模式获得操作数据库对象
* @return
*/
public static GreenDaoManager getInstance(){
return manager;
}
/**
* 判断是否有存在数据库,如果没有则创建
* @return
*/
public DaoMaster getDaoMaster(){
if(sDaoMaster == null) {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
com.orhanobut.logger.Logger.i("context="+context.toString());
sDaoMaster = new DaoMaster(helper.getWritableDatabase());
}
return sDaoMaster;
}
/**
* 完成对数据库的添加、删除、修改、查询操作,仅仅是一个接口
* @return
*/
public DaoSession getDaoSession(){
if(sDaoSession == null){
if(sDaoMaster == null){
sDaoMaster = getDaoMaster();
}
sDaoSession = sDaoMaster.newSession();
}
return sDaoSession;
}
/**
* 打开输出日志,默认关闭
*/
public void setDebug(){
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
}
public void closeHelper(){
if(sHelper != null){
sHelper.close();
sHelper = null;
}
}
public void closeDaoSession(){
if(sDaoSession != null){
sDaoSession.clear();
sDaoSession = null;
}
}
/**
* 关闭所有的操作,数据库开启后,使用完毕要关闭
*/
public void closeConnection(){
closeHelper();
closeDaoSession();
}
}
package com.lab.web.entity.greendaoentity;
import android.content.Context;
import com.lab.web.entity.greendao.DaoMaster;
import com.lab.web.entity.greendao.SearchHistroyEntryDao;
import com.orhanobut.logger.Logger;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.List;
/**
* Created by ppg on 2018/2/8.
*/
public class SearchHistoryDaoUtil {
private static final String TAG = SearchHistoryDaoUtil.class.getSimpleName();
private GreenDaoManager mManager;
public SearchHistoryDaoUtil(Context context) {
this.mManager =GreenDaoManager.getInstance() ;
//不要忘记初始化GreenDaoManager
this.mManager.init(context);
}
/**
* 完成搜索记录的插入,如果表未创建,先创建Meizi表
* @param searchHistroyEntry
* @return
*/
public boolean insertSearchHistroyEntry(SearchHistroyEntry searchHistroyEntry){
boolean flag = false;
flag = mManager.getDaoSession().getSearchHistroyEntryDao().insert(searchHistroyEntry) == -1 ? false : true;
Logger.i(TAG, "insert SearchHistroyEntry :" + flag + "-->" + searchHistroyEntry.toString());
return flag;
}
/**
* 插入多条数据,在子线程操作
* @param sheList
* @return
*/
public boolean insertMultSearchHistroyEntry(final List sheList) {
boolean flag = false;
try {
mManager.getDaoSession().runInTx(new Runnable() {
@Override
public void run() {
for (SearchHistroyEntry searchHistroyEntry : sheList) {
mManager.getDaoSession().insertOrReplace(searchHistroyEntry);
}
}
});
flag = true;
Logger.i(TAG, "insert SearchHistroyEntry :" + flag + "-->" + sheList.toString());
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/**
* 修改一条数据
* @param searchHistroyEntry
* @return
*/
public boolean updateSearchHistroyEntry(SearchHistroyEntry searchHistroyEntry){
boolean flag = false;
try {
mManager.getDaoSession().update(searchHistroyEntry);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 删除单条记录
* @param searchHistroyEntry
* @return
*/
public boolean deleteSearchHistroyEntry(SearchHistroyEntry searchHistroyEntry){
boolean flag = false;
try {
//按照id删除
mManager.getDaoSession().delete(searchHistroyEntry);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 删除所有记录
* @return ture为删除成功
*/
public boolean deleteAll(){
boolean flag = false;
try {
//按照id删除
mManager.getDaoSession().deleteAll(SearchHistroyEntry.class);
flag = true;
}catch (Exception e){
e.printStackTrace();
}
return flag;
}
/**
* 使用native sql进行查询操作
*/
public List querySearchHistroyEntryByNativeSql(String sql, String[] conditions){
return mManager.getDaoSession().queryRaw(SearchHistroyEntry.class, sql, conditions);
}
/**
* 使用queryBuilder进行查询
* @return
*/
public List querySearchHistroyEntryByQueryBuilder(long id){
QueryBuilder queryBuilder = mManager.getDaoSession().queryBuilder(SearchHistroyEntry.class);
return queryBuilder.where(SearchHistroyEntryDao.Properties.Search_id.eq(id)).list();
}
/**
* 查询所有搜索记录
* @return
*/
public List queryAllSearchHistroyEntry(){
return mManager.getDaoSession().loadAll(SearchHistroyEntry.class);
}
/**
* 根据主键id查询记录
* @param key
* @return
*/
public SearchHistroyEntry querySearchHistroyEntryById(long key){
return mManager.getDaoSession().load(SearchHistroyEntry.class, key);
}
}
至此集成和配置工作就可以说结束了,然后就是初始化创建数据库文件和操作数据库的问题了,说白了就是各种调方法。示例如下:
/GreenDao初始化
searchHistoryDaoUtil=new SearchHistoryDaoUtil(this);
searchHistoryDaoUtil.deleteAll();
searchHistoryDaoUtil.insertSearchHistroyEntry(new SearchHistroyEntry(1001L,"碰碰购"));
Logger.i("插入一条碰碰购");
List searchHistroyEntriesList = new ArrayList<>();
searchHistroyEntriesList.add(new SearchHistroyEntry(1002L,"画江湖"));
searchHistroyEntriesList.add(new SearchHistroyEntry(1003L,"侠岚"));
searchHistroyEntriesList.add(new SearchHistroyEntry(1004L,"若森"));
searchHistroyEntriesList.add(new SearchHistroyEntry(1005L,"秦时明月"));
searchHistroyEntriesList.add(new SearchHistroyEntry(1006L,"天行九歌"));
searchHistoryDaoUtil.insertMultSearchHistroyEntry(searchHistroyEntriesList);
Logger.i("当前数据库条目数量:"+searchHistroyEntriesList.size());
private void checkAllSearchCode() {
List searchHistroyEntries = MyApplication.getInstance().searchHistoryDaoUtil.queryAllSearchHistroyEntry();
mVals = new String[searchHistroyEntries.size()];
for (int i = 0; i < searchHistroyEntries.size(); i++) {
mVals[i] = searchHistroyEntries.get(i).getHistry_searchStr();
Logger.i("条目ID:"+searchHistroyEntries.get(i).getSearch_id());
}
Logger.i("数据库总条目:"+searchHistroyEntries.size());
}
如果你是要在项目启动的时候就初始化数据库,那么要考虑一个问题,就是你的项目中是否集成了别的基于反射的安卓框架,比如说腾讯的Bugly热修复等等,因为既然是基于反射,那么application类中的onCreate方法就不会只执行一次,所以如果在此处初始化数据库并添加内容的话,就要酌情考虑你的数据库内容会不会重复,如果没有指定主键ID的值就会重复内容,如果指定了ID的值就会因为重复加载相同ID的内容而在二次启动时候报错,所以如果数据量不是很大,建议写入数据库之前先清除里边内容,以防万一。毕竟写个删除数据的操作还是很简单的。
GreenDao官网
GreenDao的GitHub网址