ddu-dao

GreenDao 介绍:
  greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。如下图所示:


  官网地址:http://greenrobot.org/greendao/
  github:https://github.com/greenrobot/greenDAO
  GreenDao 优点:
  性能高,号称Android最快的关系型数据库
  内存占用小
  库文件比较小,小于100K,编译时间低,而且可以避免65K方法限制
  支持数据库加密 greendao支持SQLCipher进行数据库加密 有关SQLCipher可以参考这篇博客 Android数据存储之Sqlite采用SQLCipher数据库加密实战
  简洁易用的API
  GreenDao 3.0改动:
  使用过GreenDao的同学都知道,3.0之前需要通过新建GreenDaoGenerator工程生成Java数据对象(实体)和DAO对象,非常的繁琐而且也加大了使用成本。
  GreenDao 3.0最大的变化就是采用注解的方式通过编译方式生成Java数据对象和DAO对象。
  GreenDao 3.0使用方式:
  1.)在build.gradle添加如下配置
  buildscript {
  repositories {
  mavenCentral()
  }
  dependencies {
  classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
  }
  }
  apply plugin: 'org.greenrobot.greendao'
  dependencies {
  compile 'org.greenrobot:greendao:3.0.1'
  }
  2.)新建实体
  @Entity
  public class User {
  @Id
  private long id;
  private String name;
  private int age;
  //下面省去了 setter/getter
  }
  此时编译一下自动生成DaoMaster 、DaoSession、Dao,如图所示 默认位置:

  3.) Gradle 插件配置
  比如上面想指定生成DaoMaster 、DaoSession、Dao位置
  greendao {
  targetGenDir 'src/main/java'
  }
  schemaVersion : 数据库schema版本,也可以理解为数据库版本号
  daoPackage :设置DaoMaster 、DaoSession、Dao包名
  targetGenDir :设置DaoMaster 、DaoSession、Dao目录
  targetGenDirTest :设置生成单元测试目录
  generateTests :设置自动生成单元测试用例
  4.)实体 @Entity注解
  schema :告知GreenDao当前实体属于哪个schema
  active: 标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
  nameInDb: 在数据中使用的别名,默认使用的是实体的类名
  indexes: 定义索引,可以跨越多个列
  createInDb: 标记创建数据库表
  5.)基础属性注解
  @Id : 主键 long/Long型,可以通过@Id(autoincrement = true)设置自增长
  @Property: 设置一个非默认关系映射所对应的列名,默认是的使用字段名 举例:@Property (nameInDb="name")
  @NotNul: 设置数据库表当前列不能为空
  @Transient :添加次标记之后不会生成数据库表的列
  6.)索引注解
  @Index: 使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
  @Unique: 向数据库列添加了一个唯一的约束
  7.)关系注解
  @ToOne: 定义与另一个实体(一个实体对象)的关系
  @ToMany: 定义与多个实体对象的关系
  GreenDao 3.0简单实战:
  1.)通过上面使用方式我们可以获取DaoMaster 、DaoSession、Dao类
  这里声明一个数据库管理者单例
  public class DBManager {
  private final static String dbName = "test_db";
  private static DBManager mInstance;
  private DaoMaster.DevOpenHelper openHelper;
  private Context context;
  public DBManager(Context context) {
  this.context = context;
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  /**
  * 获取单例引用
  *
  * @param context
  * @return
  /
  public static DBManager getInstance(Context context) {
  if (mInstance == null) {
  synchronized (DBManager.class) {
  if (mInstance == null) {
  mInstance = new DBManager(context);
  }
  }
  }
  return mInstance;
  }
  }
  2.)获取可读可写数据库
  可读数据库
  /
*
  * 获取可读数据库
  /
  private SQLiteDatabase getReadableDatabase() {
  if (openHelper == null) {
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  SQLiteDatabase db = openHelper.getReadableDatabase();
  return db;
  }
  可写数据库
  /
*
  * 获取可写数据库
  /
  private SQLiteDatabase getWritableDatabase() {
  if (openHelper == null) {
  openHelper = new DaoMaster.DevOpenHelper(context, dbName, null);
  }
  SQLiteDatabase db = openHelper.getWritableDatabase();
  return db;
  }
  3.)插入数据
  /
*
  * 插入一条记录
  *
  * @param user
  /
  public void insertUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.insert(user);
  }
  /
*
  * 插入用户集合
  *
  * @param users
  /
  public void insertUserList(List users) {
  if (users == null || users.isEmpty()) {
  return;
  }
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.insertInTx(users);
  }
  4.)删除数据
  /
*
  * 删除一条记录
  *
  * @param user
  /
  public void deleteUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.delete(user);
  }
  5.)更新数据
  /
*
  * 更新一条记录
  *
  * @param user
  /
  public void updateUser(User user) {
  DaoMaster daoMaster = new DaoMaster(getWritableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  userDao.update(user);
  }
  6.)查询数据
  /
*
  * 查询用户列表
  /
  public List queryUserList() {
  DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  QueryBuilder qb = userDao.queryBuilder();
  List list = qb.list();
  return list;
  }
  /
*
  * 查询用户列表
  */
  public List queryUserList(int age) {
  DaoMaster daoMaster = new DaoMaster(getReadableDatabase());
  DaoSession daoSession = daoMaster.newSession();
  UserDao userDao = daoSession.getUserDao();
  QueryBuilder qb = userDao.queryBuilder();
  qb.where(UserDao.Properties.Age.gt(age)).orderAsc(UserDao.Properties.Age);
  List list = qb.list();
  return list;
  }
  7.)测试程序
  DBManager dbManager = DBManager.getInstance(this);
  for (int i = 0; i < 5; i++) {
  User user = new User();
  user.setId(i);
  user.setAge(i * 3);
  user.setName("第" + i + "人");
  dbManager.insertUser(user);
  }
  List userList = dbManager.queryUserList();
  for (User user : userList) {
  Log.e("TAG", "queryUserList--before-->" + user.getId() + "--" + user.getName() +"--"+user.getAge());
  if (user.getId() == 0) {
  dbManager.deleteUser(user);
  }
  if (user.getId() == 3) {
  user.setAge(10);
  dbManager.updateUser(user);
  }
  }
  userList = dbManager.queryUserList();
  for (User user : userList) {
  Log.e("TAG", "queryUserList--after--->" + user.getId() + "---" + user.getName()+"--"+user.getAge());
  }

-----------------------------------3.0-----------------
GreenDao 3.X之注解已经了解到GreenDao 3.0的改动及注解。对于数据库的操作,无异于增删改查等四个操作。下面我们将了解GreenDao 3.X如何使用?
AbstractDao
所有的自动生成的XXDao都是继承于AbstractDao,此类中基本上封装了所有的增删改操作,包括数据库的事务操作。常用的API如下:

void attachEntity(T entity):

long count():获取数据库中数据的数量

// 数据删除相关
void delete(T entity):从数据库中删除给定的实体
void deleteAll() :删除数据库中全部数据
void deleteByKey(K key):从数据库中删除给定Key所对应的实体
void deleteByKeyInTx(java.lang.Iterable<K> keys):使用事务操作删除数据库中给定的所有key所对应的实体
void deleteByKeyInTx(K... keys):使用事务操作删除数据库中给定的所有key所对应的实体
void deleteInTx(java.lang.Iterable<T> entities):使用事务操作删除数据库中给定实体集合中的实体
void deleteInTx(T... entities):使用事务操作删除数据库中给定的实体

// 数据插入相关
long insert(T entity):将给定的实体插入数据库
void insertInTx(java.lang.Iterable<T> entities):使用事务操作,将给定的实体集合插入数据库
void insertInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事务操作,将给定的实体集合插入数据库,
并设置是否设定主键
void insertInTx(T... entities):将给定的实体插入数据库
long insertOrReplace(T entity):将给定的实体插入数据库,若此实体类存在,则覆盖
void insertOrReplaceInTx(java.lang.Iterable<T> entities):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖
void insertOrReplaceInTx(java.lang.Iterable<T> entities, boolean setPrimaryKey):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖
并设置是否设定主键
void insertOrReplaceInTx(T... entities):使用事务操作,将给定的实体插入数据库,若此实体类存在,则覆盖
long insertWithoutSettingPk(T entity):将给定的实体插入数据库,但不设定主键

// 新增数据插入相关API
void save(T entity):将给定的实体插入数据库,若此实体类存在,则更新
void saveInTx(java.lang.Iterable<T> entities):将给定的实体插入数据库,若此实体类存在,则更新
void saveInTx(T... entities):使用事务操作,将给定的实体插入数据库,若此实体类存在,则更新

// 加载相关
T load(K key):加载给定主键的实体
java.util.List<T> loadAll():加载数据库中所有的实体
protected java.util.List<T> loadAllAndCloseCursor(android.database.Cursor cursor) :从cursor中读取、返回实体的列表,并关闭该cursor
protected java.util.List<T> loadAllFromCursor(android.database.Cursor cursor):从cursor中读取、返回实体的列表
T loadByRowId(long rowId) :加载某一行并返回该行的实体
protected T loadUnique(android.database.Cursor cursor) :从cursor中读取、返回唯一实体
protected T loadUniqueAndCloseCursor(android.database.Cursor cursor) :从cursor中读取、返回唯一实体,并关闭该cursor

//更新数据
void update(T entity) :更新给定的实体
protected void updateInsideSynchronized(T entity, DatabaseStatement stmt, boolean lock)
protected void updateInsideSynchronized(T entity, android.database.sqlite.SQLiteStatement stmt, boolean lock)
void updateInTx(java.lang.Iterable<T> entities) :使用事务操作,更新给定的实体
void updateInTx(T... entities):使用事务操作,更新给定的实体

QueryBuilder、Query
基本查询
GreenDao中,使用QueryBuilder自定义查询实体,而不是再写繁琐的SQL语句,避免了SQL语句的出错率。大家都知道写SQL语句时,非常容易出错,出错后又十分的难查。QueryBuilder真是帮忙解决了一个大麻烦。具体该如何使用呢?

List joes = userDao.queryBuilder()
// 查询的条件
.where(Properties.FirstName.eq("Joe"))
// 返回实体集合升序排列
.orderAsc(Properties.LastName)
.list();
QueryBuilder qb = userDao.queryBuilder();
// 查询的条件
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
List youngJoes = qb.list(); </span>

    上面是官方给出的两个列子,不仅满足了查询语句的易写,同时使用了流式写法,提高了代码的可阅读性。

Limit、Offset、Pagination
在实际开发过程中,大家肯定碰到这样的问题,当数据过多在一页显示不出来的时候,要么选择前面十条显示,要么分页显示,但是数据总是获取全部的。其实,刚接触GreenDao的时候,也是这么干,获取全部的实体集合,然后再根据实际情况截取。看了API以后,豁然开朗,大神们已经帮我们解决了这件事。此时不得不说,QueryBuilder中的Limit(限制)、Offset(偏移),limit(int)和offset(int)协同设置,可以完美解决分页显示。

limit(int):限制查询返回结果的数目
offset(int):设置查询结果的偏移量,此查询需与limit(int)结合使用,而不能够脱离limit(int)单独使用

Query
当执行多次查询时,实际是QueryBuilder多次调用Query类。如果执行多次相同的查询,应使用QueryBuilder的build()方法来创建Query,而不是直接使用Query类。如果查询返回的结果是唯一性的,可以使用操作符方法,如果不希望此唯一性不返回 null,此时可调用uniqOrThrow()方法。如果查询返回的结果是多个,可以使返回的结果是一个集合,有如下方法:

list():所有实体加载至内存,结果通常是一个ArrayList
listLazy():实体在需要时,加载至内存,表中的第一个元素被第一次访问时会被缓存,下次访问时,使用缓存
listLazyUncached():任何对列表实体的访问懂事从数据库中加载
listIterator():以按需加载的方式来遍历结果,数据没有被缓存

     一旦使用QueryBuilder创建了一个query,那么这个Query对象就可以就可以被复用来执行查询显然这种方式逼重新创建一次Query效率要高。        

如果Query的参数没有变更,你只需要再次调用List/unuque方法即可
如果参数发生了变化,那么就需要通过setParameter方法来处理每一个发生改变的参数

Query query = userDao.queryBuilder().where(Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)).build();
List joesOf1970 = query.list();

query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();

    由此可见,Query在执行一次build之后会将查询结果进行缓存,方便下次继续使用。

执行原生SQL语句
两种方法:

Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();

如果这里的QueryBuilder没有提供你想要的特性,可以使用原始的queryRaw或queryRawCreate方法。
Query query = userDao.queryRawCreate( ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");

    注:写SQL语句时推荐定义常量来表示表名或者表项,这样可以防止出错,因为编译器会检查

基本使用
创建实体类

@Entity(generateConstructors = false)
public class Student {
@Id
private Long id;
private String name;
private int age;

public Student() {  
}  

@Keep  
public Student(String name, int age) {  
    this.name = name;  
    this.age = age;  
}  


public Student(Long id, String name, int age) {  
    this.id = id;  
    this.name = name;  
    this.age = age;  
}  

@Keep  
public Long getId() {  
    return id;  
}  

@Keep  
public void setId(Long id) {  
    this.id = id;  
}  

@Keep  
public String getName() {  
    return name;  
}  

@Keep  
public void setName(String name) {  
    this.name = name;  
}  

@Keep  
public int getAge() {  
    return age;  
}  

@Keep  
public void setAge(int age) {  
    this.age = age;  
}  

@Keep  
@Override  
public boolean equals(Object o) {  
    if (this == o) return true;  
    if (!(o instanceof Student)) return false;  

    Student student = (Student) o;  

    return name.equals(student.name);  

}  

@Keep  
@Override  
public int hashCode() {  
    return (int) (id ^ (id >>> 32));  
}  

@Keep  
@Override  
public String toString() {  
    return "Student{" +  
            "id=" + id +  
            ", name='" + name + '\'' +  
            ", age=" + age +  
            '}';  
}  

}

创建完实体类后,Rebuild Project生成DaoMaster、DaoSession。DaoMaster、DaoSession位于在Gradle设置的目录及文件夹里。
[图片上传中。。。(21)]

[图片上传中。。。(22)]
创建Database管理类

public class DbManager {

// 是否加密  
public static final boolean ENCRYPTED = true;  

private static final String DB_NAME = "tea.db";  
private static DbManager mDbManager;  
private static DaoMaster.DevOpenHelper mDevOpenHelper;  
private static DaoMaster mDaoMaster;  
private static DaoSession mDaoSession;  

private Context mContext;  

private DbManager(Context context) {  
    this.mContext = context;  
    // 初始化数据库信息  
    mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);  
    getDaoMaster(context);  
    getDaoSession(context);  
}  

public static DbManager getInstance(Context context) {  
    if (null == mDbManager) {  
        synchronized (DbManager.class) {  
            if (null == mDbManager) {  
                mDbManager = new DbManager(context);  
            }  
        }  
    }  
    return mDbManager;  
}  

/** 
 * @desc 获取可读数据库 
 **/  
public static SQLiteDatabase getReadableDatabase(Context context) {  
    if (null == mDevOpenHelper) {  
        getInstance(context);  
    }  
    return mDevOpenHelper.getReadableDatabase();  
}  

/** 
 * @desc 获取可写数据库 
 **/  
public static SQLiteDatabase getWritableDatabase(Context context) {  
    if (null == mDevOpenHelper) {  
        getInstance(context);  
    }  
    return mDevOpenHelper.getWritableDatabase();  
}  

/** 
 * @desc 获取DaoMaster 
 **/  
public static DaoMaster getDaoMaster(Context context) {  
    if (null == mDaoMaster) {  
        synchronized (DbManager.class) {  
            if (null == mDaoMaster) {  
                mDaoMaster = new DaoMaster(getWritableDatabase(context));  
            }  
        }  
    }  
    return mDaoMaster;  
}  

/** 
 * @desc 获取DaoSession 
 **/  
public static DaoSession getDaoSession(Context context) {  
    if (null == mDaoSession) {  
        synchronized (DbManager.class) {  
            mDaoSession = getDaoMaster(context).newSession();  
        }  
    }  

    return mDaoSession;  
}  

}

数据库操作类

public class StudentDaoOpe {

/** 
 * @desc 添加数据至数据库 
 **/  
public static void insertData(Context context, Student stu) {  

    DbManager.getDaoSession(context).getStudentDao().insert(stu);  
}  

/** 
 * @desc 将数据实体通过事务添加至数据库 
 **/  
public static void insertData(Context context, List<Student> list) {  
    if (null == list || list.size() <= 0) {  
        return;  
    }  
    DbManager.getDaoSession(context).getStudentDao().insertInTx(list);  
}  


  @desc 添加数据至数据库,如果存在,将原来的数据覆盖 

public static void saveData(Context context, Student student) {  
    DbManager.getDaoSession(context).getStudentDao().save(student);  
}  

/** 
 * @desc 查询所有数据 
 **/  
public static List<Student> queryAll(Context context) {  
    QueryBuilder<Student> builder = DbManager.getDaoSession(context).getStudentDao().queryBuilder();  

    return builder.build().list();  
}  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,511评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,495评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,595评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,558评论 0 190
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,715评论 3 270
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,672评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,112评论 2 291
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,837评论 0 181
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,417评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,928评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,316评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,773评论 2 234
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,253评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,827评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,440评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,523评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,583评论 2 249

推荐阅读更多精彩内容