当前位置:   article > 正文

Android之 常用数据库框架整理_安卓数据库

安卓数据库

一 简介

1.1 上节说了关系型数据库有以下几种:

Oracle、Microsoft SQL Server、Microsoft Access、MySQL、SQLite

1.2 各自的领域也不一样

java,C#,php等用Oracle,Microsoft SQL Server,MySQL比较多。

移动端Android,IOS等用SQLite比较多

1.3 SQLite是一种轻量型数据库,有以下优点:

  • 不需要一个单独的服务器进程或操作的系统(无服务器的)。

  • SQLite 不需要配置,这意味着不需要安装或管理。

  • 一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘文件。

  • SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于250KiB。

  • SQLite 是自给自足的,这意味着不需要任何外部的依赖。

  • SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问。

  • SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能。

  • SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API。

  • SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运行。

二 Android 本地数据库框架 

2.1 android数据库框架有Room,Relam,GreenDAO,ObjectBox,SQLDelight等等。

2.2 常用的有Room,GreenDAO等,在前两个没出现之前主要用的Android官方原生框架SQLiteOpenHelper。

三 SQLiteOpenHelper 框架的使用

3.1 SQLiteOpenHelper是官方api,因此不需要引入其它库。如下可以看到,SQLiteOpenHelper在android.database.sqlite包下面

 3.2 SQLiteOpenHelper的使用,自定义DatabaseHelper,继承SQLiteOpenHelper,来管理数据库的创建和数据库表的创建

  1. public class DatabaseHelper extends SQLiteOpenHelper {
  2. public static final String DATABASE_NAME = "SMSManager.db";//数据库名字
  3. private static final int DATABASE_VERSION = 1; // 数据库的版本号
  4. public static final String CONTACTS_TABLE_NAME = "contacts_table";//联系人表名
  5. //创建联系人表SQL语句
  6. public static final String CREATE_CONTACTS_TABLE =
  7. "create table " +
  8. CONTACTS_TABLE_NAME +
  9. "(" +
  10. "cid integer primary key autoincrement," +
  11. "sendPhone varchar(50),name varchar(50) not null," +
  12. "phone varchar(50) not null" +
  13. ")";
  14. /**
  15. * DatabaseHelper构造函数,传参数据库名,数据库版本,会自动创建数据库
  16. * @param context
  17. */
  18. public DatabaseHelper(Context context) {
  19. super(context, DATABASE_NAME, null, DATABASE_VERSION);
  20. }
  21. /**
  22. * onCreate 回调SQLiteDatabase对象,自动执行创建表语句
  23. * @param db
  24. */
  25. @Override
  26. public void onCreate(SQLiteDatabase db) {
  27. db.execSQL(CREATE_CONTACTS_TABLE);
  28. }
  29. /**
  30. * 升级数据库。执行表结构变更语句
  31. * @param db
  32. * @param oldVersion
  33. * @param newVersion
  34. */
  35. @Override
  36. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  37. // if (newVersion > 1) {
  38. // //Android的ALTER命令不支持一次添加多列,只能分多次添加
  39. // String alter_sql = "ALTER TABLE " + CONTACTS_TABLE_NAME + " ADD COLUMN " + "phone_new2 VARCHAR;";
  40. // db.execSQL(alter_sql);
  41. // alter_sql = "ALTER TABLE " + CONTACTS_TABLE_NAME + " ADD COLUMN " + "phone_new3 VARCHAR;";
  42. // db.execSQL(alter_sql); // 执行完整的SQL语句
  43. // }
  44. }
  45. }

3.3 创建联系人表的实体类ContactsInfo

  1. public class ContactsInfo implements Serializable{
  2. int cid;
  3. String name;
  4. String phone;
  5. String sendPhone;
  6. boolean isChoosed=false;
  7. public int getCid() {
  8. return cid;
  9. }
  10. public void setCid(int cid) {
  11. this.cid = cid;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getPhone() {
  20. return phone;
  21. }
  22. public void setPhone(String phone) {
  23. this.phone = phone;
  24. }
  25. public String getSendPhone() {
  26. return sendPhone;
  27. }
  28. public void setSendPhone(String sendPhone) {
  29. this.sendPhone = sendPhone;
  30. }
  31. public boolean isChoosed() {
  32. return isChoosed;
  33. }
  34. public void setChoosed(boolean choosed) {
  35. isChoosed = choosed;
  36. }
  37. }

3.4 创建联系人表的管理类ContactsDatabase,进行表的增删改查操作

  1. public class ContactsDatabase {
  2. private final DatabaseHelper dbHelper;
  3. public ContactsDatabase(Context context) {
  4. super();
  5. dbHelper = new DatabaseHelper(context);
  6. }
  7. /**
  8. * 增
  9. *
  10. * @param data
  11. */
  12. public void insert(ContactsInfo data) {
  13. String sql = "insert into " + DatabaseHelper.CONTACTS_TABLE_NAME;
  14. sql += "(sendPhone, name, phone) values(?,?,?)";
  15. SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
  16. sqlite.execSQL(sql, new String[] {data.getSendPhone() + "",data.getName() + "", data.getPhone() + ""});
  17. sqlite.close();
  18. }
  19. /**
  20. * 删
  21. *
  22. * @param where
  23. */
  24. public void delete(String where) {
  25. SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
  26. String sql = "delete from " + DatabaseHelper.CONTACTS_TABLE_NAME + where;
  27. sqlite.execSQL(sql);
  28. sqlite.close();
  29. }
  30. /**
  31. * 改
  32. *
  33. * @param data
  34. */
  35. public void update(ContactsInfo data) {
  36. SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
  37. String sql = ("update " + DatabaseHelper.CONTACTS_TABLE_NAME +" set sendPhone=?,name=?,phone=? where cid=?");
  38. sqlite.execSQL(sql,
  39. new String[] { data.getSendPhone() + "", data.getName() + "", data.getPhone()+ "", data.getCid()+ ""});
  40. sqlite.close();
  41. }
  42. /**
  43. * 查一条数据
  44. *
  45. * @param where
  46. * @return
  47. */
  48. public ContactsInfo queryContactsInfo(String where) {
  49. ContactsInfo contactsInfo = null;
  50. SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
  51. String sql= "select * from "
  52. + DatabaseHelper.CONTACTS_TABLE_NAME + where;
  53. Cursor cursor = sqlite.rawQuery(sql, null);
  54. for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
  55. contactsInfo= new ContactsInfo();
  56. contactsInfo.setCid(cursor.getInt(0));
  57. contactsInfo.setSendPhone(cursor.getString(1));
  58. contactsInfo.setName(cursor.getString(2));
  59. contactsInfo.setPhone(cursor.getString(3));
  60. }
  61. if (!cursor.isClosed()) {
  62. cursor.close();
  63. }
  64. sqlite.close();
  65. return contactsInfo;
  66. }
  67. /**
  68. * 查
  69. *
  70. * @param where
  71. * @return
  72. */
  73. public List<ContactsInfo> query(String where) {
  74. SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
  75. ArrayList<ContactsInfo> data = null;
  76. data = new ArrayList<ContactsInfo>();
  77. String sql="select * from "
  78. + DatabaseHelper.CONTACTS_TABLE_NAME + where;
  79. Cursor cursor = sqlite.rawQuery(sql, null);
  80. for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
  81. ContactsInfo contactsInfo = new ContactsInfo();
  82. contactsInfo.setSendPhone(cursor.getString(1));
  83. contactsInfo.setName(cursor.getString(2));
  84. contactsInfo.setPhone(cursor.getString(3));
  85. data.add(contactsInfo);
  86. }
  87. if (!cursor.isClosed()) {
  88. cursor.close();
  89. }
  90. sqlite.close();
  91. return data;
  92. }
  93. /**
  94. * 查
  95. *
  96. * @param where
  97. * @return
  98. */
  99. public int queryCount(String where) {
  100. SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
  101. String sql="select count(*) from "
  102. + DatabaseHelper.CONTACTS_TABLE_NAME+where ;
  103. Cursor cursor = sqlite.rawQuery(sql, null);
  104. cursor.moveToFirst();
  105. int count = cursor.getInt(0);
  106. sqlite.close();
  107. return count;
  108. }
  109. /**
  110. * 重置
  111. *
  112. * @param datas
  113. */
  114. public void reset(List<ContactsInfo> datas) {
  115. if (datas != null) {
  116. SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
  117. // 删除全部
  118. sqlite.execSQL("delete from " + DatabaseHelper.CONTACTS_TABLE_NAME);
  119. // 重新添加
  120. for (ContactsInfo data : datas) {
  121. insert(data);
  122. }
  123. sqlite.close();
  124. }
  125. }
  126. public void destroy() {
  127. dbHelper.close();
  128. }
  129. }

3.5 总结:

第一步:SQLiteOpenHelper的构造函数创建数据库

  1. public DatabaseHelper(Context context) {
  2. super(context, DATABASE_NAME, null, 1);
  3. }

第二步:SQLiteOpenHelper的onCreate里面执行创建表的sql语句

  1. @Override
  2. public void onCreate(SQLiteDatabase db) {
  3. db.execSQL(CREATE_CONTACTS_TABLE);
  4. }

第三步:获取当前数据库对象实例,打开数据库,进行增删改查操作

  1. SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
  2. sqlite .insert(TABLE_NAME, "",entity);
  3. sqlite .delete(TABLE_NAME, entity, null);
  4. sqlite .update(TABLE_NAME, entity, "name=?", new String[]{info.name});
  5. sqlite .rawQuery(sql, null);

第四步:关闭数据库

  1. if (sqlite != null && sqlite .isOpen()) {
  2.     sqlite .close();
  3.     sqlite = null;
  4. }

四 GreenDAO 框架的使用

4.1 GreenDAO 是一种轻量级快速ORM 框架,可将对象映射到 SQLite 数据库中

4.2 ORM 框架,即 Object-Relational Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体操作数据库的时候,就不需要再去和复杂的 SQL 语句打交道,只是像平时操作对象一样操作它就可以了

在这里插入图片描述

 4.3 GreenDAO主要类介绍

  • DaoMaster:DaoMaster保存数据库对象(SQLiteDatabase)并管理特定模式的DAO类(而不是对象)。它有静态方法来创建表或删除它们。它的内部类OpenHelper和DevOpenHelper是SQLiteOpenHelper实现,它们在SQLite数据库中创建模式。
  • DaoSession:管理特定模式的所有可用DAO对象,您可以使用其中一个getter方法获取该对象。DaoSession还提供了一些通用的持久性方法,如实体的插入,加载,更新,刷新和删除。
  • DAO:数据访问对象(DAO)持久存在并查询实体。对于每个实体,greenDAO生成实体XXDAO。它具有比DaoSession更多的持久性方法,例如:count,loadAll和insert等。
  • Entities :可持久化对象。通常, 实体对象代表一个数据库行使用标准 Java 属性(如一个POJO 或 JavaBean )。

4.4 GreenDAO的使用

工程目录build.gradle里面引入greenDao的插件

  1. dependencies {
  2. classpath "com.android.tools.build:gradle:7.0.0"
  3. classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0'
  4. }

app的build.gradle里面使用插件,配置数据库,并引入greenDao的依赖库

  1. plugins {
  2. id 'com.android.application'
  3. id 'org.greenrobot.greendao'
  4. }
  5. android {
  6. compileSdk 32
  7. defaultConfig {
  8. applicationId "com.greendao.demo"
  9. minSdk 21
  10. targetSdk 32
  11. versionCode 1
  12. versionName "1.0"
  13. }
  14. }
  15. greendao {
  16. //指定数据库schema版本号,迁移等操作会用到
  17. schemaVersion 1
  18. //设置生成数据库文件的目录,默认是在build中,可以将生成的文件放到我们的java目录中
  19. targetGenDir 'src/main/java'
  20. //设置生成的数据库相关文件的包名,默认为entity所在的包名
  21. daoPackage 'com.greendao.demo.greendao.database'
  22. }
  23. dependencies {
  24. implementation 'org.greenrobot:greendao:3.3.0'
  25. }

4.5 封装数据库管理器DaoManager,用来创建数据库、创建数据库表、包含增删改查的操作以及数据库的升级

  1. /**
  2. * 创建数据库、创建数据库表、包含增删改查的操作以及数据库的升级
  3. */
  4. public class DaoManager
  5. {
  6. private static final String TAG = DaoManager.class.getSimpleName();
  7. private static final String DB_NAME = "diary.db";
  8. private Context context;
  9. //多线程中要被共享的使用volatile关键字修饰
  10. private volatile static DaoManager manager ;
  11. private static DaoMaster sDaoMaster;
  12. private static DaoMaster.DevOpenHelper sHelper;
  13. private static DaoSession sDaoSession;
  14. /**
  15. * 单例模式获得操作数据库对象
  16. *
  17. * @return
  18. */
  19. public static DaoManager getInstance()
  20. {
  21. synchronized (DaoManager.class) {
  22. if (manager == null) {
  23. manager = new DaoManager();
  24. }
  25. }
  26. return manager;
  27. }
  28. private DaoManager()
  29. {
  30. setDebug();
  31. }
  32. public void init(Context context)
  33. {
  34. this.context = context;
  35. }
  36. /**
  37. * 判断是否有存在数据库,如果没有则创建
  38. *
  39. * @return
  40. */
  41. public DaoMaster getDaoMaster()
  42. {
  43. if (sDaoMaster == null)
  44. {
  45. sHelper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
  46. sDaoMaster = new DaoMaster(sHelper.getWritableDatabase());
  47. }
  48. return sDaoMaster;
  49. }
  50. /**
  51. * 完成对数据库的添加、删除、修改、查询操作,仅仅是一个接口
  52. *
  53. * @return
  54. */
  55. public DaoSession getDaoSession()
  56. {
  57. if (sDaoSession == null)
  58. {
  59. if (sDaoMaster == null)
  60. {
  61. sDaoMaster = getDaoMaster();
  62. }
  63. sDaoSession = sDaoMaster.newSession();
  64. }
  65. return sDaoSession;
  66. }
  67. /**
  68. * 打开输出日志,默认关闭
  69. */
  70. public void setDebug()
  71. {
  72. if (BuildConfig.DEBUG)
  73. {
  74. QueryBuilder.LOG_SQL = true;
  75. QueryBuilder.LOG_VALUES = true;
  76. }
  77. }
  78. /**
  79. * 关闭所有的操作,数据库开启后,使用完毕要关闭
  80. */
  81. public void closeConnection()
  82. {
  83. closeHelper();
  84. closeDaoSession();
  85. }
  86. public void closeHelper()
  87. {
  88. if (sHelper != null)
  89. {
  90. sHelper.close();
  91. sHelper = null;
  92. }
  93. }
  94. public void closeDaoSession()
  95. {
  96. if (sDaoSession != null)
  97. {
  98. sDaoSession.clear();
  99. sDaoSession = null;
  100. }
  101. }
  102. }

4.6 在项目Application里面初始化GreenDAO

DaoManager.getInstance().init(this);

4.7 以Uer表为例,创建一个User实体类。实体类开头必须加 @Entity 注解

  1. @Entity
  2. public class User {
  3. @Id(autoincrement = true)
  4. Long id;
  5. String account;
  6. String password;
  7. String name="tom";
  8. String avatar;
  9. int gender=0;
  10. String mobile;
  11. @Generated(hash = 998056223)
  12. public User(Long id, String account, String password, String name,
  13. String avatar, int gender, String mobile) {
  14. this.id = id;
  15. this.account = account;
  16. this.password = password;
  17. this.name = name;
  18. this.avatar = avatar;
  19. this.gender = gender;
  20. this.mobile = mobile;
  21. }
  22. }

编译后User实体类目会自动生成GET,SET方法

  1. @Entity
  2. public class User {
  3. @Id(autoincrement = true)
  4. Long id;
  5. String account;
  6. String password;
  7. String name="tom";
  8. String avatar;
  9. int gender=0;
  10. String mobile;
  11. @Generated(hash = 998056223)
  12. public User(Long id, String account, String password, String name,
  13. String avatar, int gender, String mobile) {
  14. this.id = id;
  15. this.account = account;
  16. this.password = password;
  17. this.name = name;
  18. this.avatar = avatar;
  19. this.gender = gender;
  20. this.mobile = mobile;
  21. }
  22. @Generated(hash = 586692638)
  23. public User() {
  24. }
  25. public Long getId() {
  26. return this.id;
  27. }
  28. public void setId(Long id) {
  29. this.id = id;
  30. }
  31. public String getAccount() {
  32. return this.account;
  33. }
  34. public void setAccount(String account) {
  35. this.account = account;
  36. }
  37. public String getPassword() {
  38. return this.password;
  39. }
  40. public void setPassword(String password) {
  41. this.password = password;
  42. }
  43. public String getName() {
  44. return this.name;
  45. }
  46. public void setName(String name) {
  47. this.name = name;
  48. }
  49. public String getAvatar() {
  50. return this.avatar;
  51. }
  52. public void setAvatar(String avatar) {
  53. this.avatar = avatar;
  54. }
  55. public int getGender() {
  56. return this.gender;
  57. }
  58. public void setGender(int gender) {
  59. this.gender = gender;
  60. }
  61. public String getMobile() {
  62. return this.mobile;
  63. }
  64. public void setMobile(String mobile) {
  65. this.mobile = mobile;
  66. }
  67. }

同时编译后还会在 build 目录下生成XXXDao实体类,通过DAO实体就能操作数据库了

 4.7 可以封装一个通用的增删改查工具类,这样像正常操作对象那样就可以了

  1. /**
  2. * 通用greendao工具
  3. * @param <T>
  4. */
  5. public class CommonDaoUtils<T> {
  6. private static final String TAG = CommonDaoUtils.class.getSimpleName();
  7. private DaoSession daoSession;
  8. private Class<T> entityClass;
  9. private AbstractDao<T, Long> entityDao;
  10. public CommonDaoUtils(Class<T> pEntityClass, AbstractDao<T, Long> pEntityDao)
  11. {
  12. DaoManager mManager = DaoManager.getInstance();
  13. daoSession = mManager.getDaoSession();
  14. entityClass = pEntityClass;
  15. entityDao = pEntityDao;
  16. }
  17. public DaoSession getDaoSession() {
  18. return daoSession;
  19. }
  20. /**
  21. * 插入记录,如果表未创建,先创建表
  22. *
  23. * @param pEntity
  24. * @return
  25. */
  26. public boolean insert(T pEntity)
  27. {
  28. boolean flag = entityDao.insert(pEntity) == -1 ? false : true;
  29. return flag;
  30. }
  31. /**
  32. * 插入记录数据存在则替换,数据不存在则插入
  33. *
  34. * @param pEntity
  35. * @return
  36. */
  37. public boolean insertOrReplace(T pEntity)
  38. {
  39. boolean flag = entityDao.insertOrReplace(pEntity) == -1 ? false : true;
  40. return flag;
  41. }
  42. /**
  43. * 插入多条数据,在子线程操作
  44. *
  45. * @param pEntityList
  46. * @return
  47. */
  48. public boolean insertMulti(final List<T> pEntityList)
  49. {
  50. try
  51. {
  52. daoSession.runInTx(new Runnable()
  53. {
  54. @Override
  55. public void run()
  56. {
  57. for (T meizi : pEntityList)
  58. {
  59. daoSession.insertOrReplace(meizi);
  60. }
  61. }
  62. });
  63. return true;
  64. }
  65. catch (Exception e)
  66. {
  67. e.printStackTrace();
  68. }
  69. return false;
  70. }
  71. /**
  72. * 修改一条数据
  73. *
  74. * @param pEntity
  75. * @return
  76. */
  77. public boolean update(T pEntity)
  78. {
  79. try
  80. {
  81. daoSession.update(pEntity);
  82. return true;
  83. }
  84. catch (Exception e)
  85. {
  86. e.printStackTrace();
  87. }
  88. return false;
  89. }
  90. /**
  91. * 删除单条记录
  92. *
  93. * @param pEntity
  94. * @return
  95. */
  96. public boolean delete(T pEntity)
  97. {
  98. try
  99. {
  100. //按照id删除
  101. daoSession.delete(pEntity);
  102. return true;
  103. }
  104. catch (Exception e)
  105. {
  106. e.printStackTrace();
  107. }
  108. return false;
  109. }
  110. /**
  111. * 删除所有记录
  112. *
  113. * @return
  114. */
  115. public boolean deleteAll()
  116. {
  117. try
  118. {
  119. //按照id删除
  120. daoSession.deleteAll(entityClass);
  121. return true;
  122. }
  123. catch (Exception e)
  124. {
  125. e.printStackTrace();
  126. }
  127. return false;
  128. }
  129. /**
  130. * 查询所有记录
  131. *
  132. * @return
  133. */
  134. public List<T> queryAll()
  135. {
  136. return daoSession.loadAll(entityClass);
  137. }
  138. /**
  139. * 根据主键id查询记录
  140. *
  141. * @param key
  142. * @return
  143. */
  144. public T queryById(long key)
  145. {
  146. return daoSession.load(entityClass, key);
  147. }
  148. /**
  149. * 使用native sql进行查询操作
  150. */
  151. public List<T> queryByNativeSql(String sql, String[] conditions)
  152. {
  153. return daoSession.queryRaw(entityClass, sql, conditions);
  154. }
  155. /**
  156. * 使用queryBuilder进行查询
  157. *
  158. * @return
  159. */
  160. public List<T> queryByQueryBuilder(WhereCondition cond, WhereCondition... condMore)
  161. {
  162. QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
  163. return queryBuilder.where(cond, condMore).list();
  164. }
  165. /**
  166. * 使用queryBuilder进行查询
  167. *
  168. * @return
  169. */
  170. public List<T> queryByBuilder(WhereCondition cond)
  171. {
  172. QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
  173. return queryBuilder.where(cond).list();
  174. }
  175. }

4.8 再定义具体的Dao操作类,实现单独管理

  1. public class DaoUserUtils
  2. {
  3. private volatile static DaoUserUtils instance;
  4. public CommonDaoUtils<User> userCommonDaoUtils;
  5. public static DaoUserUtils getInstance()
  6. {
  7. synchronized (DaoUserUtils.class) {
  8. if(instance==null){
  9. instance = new DaoUserUtils();
  10. }
  11. }
  12. return instance;
  13. }
  14. private DaoUserUtils()
  15. {
  16. DaoManager mManager = DaoManager.getInstance();
  17. userCommonDaoUtils = new CommonDaoUtils(User.class,mManager.getDaoSession().getUserDao());
  18. }
  19. //新建用户
  20. public void daoInsertDefaultUser(){
  21. String account="boss1";
  22. String password="123456";
  23. if(daoQueryAllUser().size()==0){
  24. User user= new User();
  25. user.setAccount(account);
  26. user.setPassword(password);
  27. userCommonDaoUtils.insert(user);
  28. }
  29. }
  30. //查询用户
  31. public List<User> daoQueryAllUser(){
  32. return userCommonDaoUtils.queryAll();
  33. }
  34. //查询用户
  35. public User daoQueryUser(long id){
  36. return userCommonDaoUtils.queryById(id);
  37. }
  38. //删除用户
  39. public boolean deleteAllUser(){
  40. return userCommonDaoUtils.deleteAll();
  41. }
  42. //更新用户
  43. public boolean updateUser(User user){
  44. return userCommonDaoUtils.update(user);
  45. }
  46. }

4.9 GreenDao提供有丰富的操作数据库接口,比如查询常用的三种方式:

  • load(entityClass, dataKey); 主键查询单条数据
  • loadAll():查询所有数据。
  • queryRaw():根据条件查询。
  • queryBuilder() : 方便查询的创建,后面详细讲解。

而且queryBuilder功能非常强大,比如下面常见的方法:

  • where(WhereCondition cond, WhereCondition... condMore): 查询条件,参数为查询的条件!
  • or(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore): 嵌套条件或者,用法同or。
  • and(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore): 嵌套条件且,用法同and。
  • join(Property sourceProperty, Class<J> destinationEntityClass):多表查询,后面会讲。
    输出结果有四种方式,选择其中一种最适合的即可,list()返回值是List,而其他三种返回值均实现Closeable,需要注意的不使用数据时游标的关闭操作:
  • list ()所有实体都加载到内存中。结果通常是一个没有魔法的 ArrayList。最容易使用。
  • listLazy ()实体按需加载到内存中。首次访问列表中的元素后,将加载并缓存该元素以供将来使用。必须关闭。
  • listLazyUncached ()实体的“虚拟”列表:对列表元素的任何访问都会导致从数据库加载其数据。必须关闭。
  • listIterator ()让我们通过按需加载数据(懒惰)来迭代结果。数据未缓存。必须关闭。
  • orderAsc() 按某个属性升序排;
  • orderDesc() 按某个属性降序排;

以及Property中丰富的查询函数:

  • eq():"equal ('=?')" 等于;
  • notEq() :"not equal ('<>?')" 不等于;
  • like():" LIKE ?" 值等于;
  • between():" BETWEEN ? AND ?" 取中间范围;
  • in():" IN (" in命令;
  • notIn():" NOT IN (" not in 命令;
  • gt():">?" 大于;
  • lt():"<? " 小于;
  • ge():">=?" 大于等于;
  • le():"<=? " 小于等于;
  • isNull():" IS NULL" 为空;
  • isNotNull():" IS NOT NULL" 不为空;

4.10 queryRaw()原始sql语句查询

  1. /**
  2. * @param sql 查询语句
  3. * @param conditions 位字段赋值
  4. * @return
  5. */
  6. public List<T> queryByNativeSql(String sql, String[] conditions)
  7. {
  8. DaoMaster.DevOpenHelper sHelper= new DaoMaster.DevOpenHelper(context, DB_NAME, null);
  9. DaoSession daoSession = new DaoMaster(sHelper.getWritableDatabase());
  10. return daoSession.queryRaw(entityClass, sql, conditions);
  11. }

比如:

queryByNativeSql("where columnName=?", new String[]{coverId});

4.11 queryBuilder()纯api查询,不用写任何sql语句

  1. /**
  2. * @param cond 一个条件
  3. * @param condMore 多个条件
  4. * @return
  5. */
  6. public List<T> queryByQueryBuilder(WhereCondition cond, WhereCondition... condMore)
  7. {
  8. DaoMaster.DevOpenHelper sHelper= new DaoMaster.DevOpenHelper(context, DB_NAME, null);
  9. DaoSession daoSession = new DaoMaster(sHelper.getWritableDatabase());
  10. QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
  11. return queryBuilder.where(cond, condMore).list();
  12. }

比如:

queryByQueryBuilder(DiaryDao.Properties.Time.ge(startTime),DiaryDao.Properties.Time.le(endTime));

4.12 常用注解

表名字段注解,实体类注解,必须加在类前才起用

@Entity注解

只有在实体类中使用了@Entity注解GreenDao才会创建对应的表

@Entity配置:

  • schema:如果你有多个架构,你可以告诉GreenDao当前属于哪个架构。
  • active:标记一个实体处于活跃状态,活动实体有更新、删除和刷新方法。
  • nameInDb:在数据中使用的别名,默认使用的是实体的类名。
  • indexes:标记如果DAO应该创建数据库表(默认为true),如果您有多个实体映射到一个表,或者表的创建是在greenDAO之外进行的,那么将其设置为false。
  • createInDb:标记创建数据库表。
  • generateGettersSetters:如果缺少,是否应生成属性的getter和setter方法。
  1. @Entity(
  2. schema = "myschema",
  3. active = true,
  4. nameInDb = "AWESOME_USERS",
  5. indexes = {
  6. @Index(value = "message DESC", unique = true)
  7. },
  8. createInDb = false,
  9. generateConstructors = true,
  10. generateGettersSetters = true
  11. )
  12. public class User{
  13. }

基础属性注解

@Id
@Id注解选择 long / Long属性作为实体ID。在数据库方面,它是主键。参数autoincrement = true 表示自增,id不给赋值或者为赋值为null即可(这里需要注意,如果要实现自增,id必须是Long)

  1. @Entity
  2. public class User{
  3. @Id(autoincrement = true)
  4. Long uid;
  5. }

@Property
允许您定义属性映射到的非默认列名。如果不存在,GreenDAO将使用字段名称。会生成大写列名,如 name将成为 NAME

  1. @Entity
  2. public class User{
  3. @Id(autoincrement = true)
  4. Long id;
  5. //设置了,数据库中的表格属性名为"name",如果不设置,数据库中表格属性名为"NAME"
  6. @Property (nameInDb="name")
  7. String name;
  8. }

@NotNull

设置数据库表当前列不能为空

  1. @Entity
  2. public class User{
  3. @NotNull
  4. String password;
  5. }

@Transient 

添加次标记之后不会生成数据库表的列。标记要从持久性中排除的属性。将它们用于临时状态等。或者,您也可以使用Java中的transient关键字

  1. @Entity
  2. public class User{
  3. @Transient
  4. boolean isChecked;
  5. }

索引注解

@Index

创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束。

@Unique

向索引添加UNIQUE约束,强制所有值都是唯一的。

  1. @Entity
  2. public class User{
  3. @Id(autoincrement = true)
  4. Long id;
  5. @Index(unique = true)
  6. String account;
  7. }

关系注解

@ToOne:

定义与另一个实体(一个实体对象)的关系

创建用户表和身份证表,一个人对应一个身份证

  1. @Entity
  2. public class Student {
  3. @Id(autoincrement = true)
  4. Long uid;
  5. String name;
  6. Long cardId;
  7. @ToOne(joinProperty = "cardId")
  8. Card card;
  9. }
  1. @Entity
  2. public class Card {
  3. @Id(autoincrement = true)
  4. Long cardId;
  5. String carNo;
  6. }

@ToMany:

定义与多个实体对象的关系

创建用户表和银行卡表,一个人对应多张银行卡

  1. @Entity
  2. public class Student {
  3. @Id(autoincrement = true)
  4. Long uid;
  5. @Property (nameInDb="name")
  6. String newm;
  7. //这个 uid是对应在 BankCard 中的 uid
  8. @ToMany(referencedJoinProperty = "uid")
  9. List<BankCard> bankCardList;
  10. }
  1. @Entity
  2. public class BanKCard {
  3. @Id(autoincrement = true)
  4. Long cardId;
  5. String carNo;
  6. Long uid;
  7. }

五 Jetpack Room框架使用

5.1 Jetpack是google官方一套MVVM架构的解决方案框架,里面包含以下分类

UI 库 : Animation , Transitions , Emoji , Layout , Palette …
架构库 : Data Binding , ViewModel , Lifecycles , LiveData , Navigation , Padding , Room …
行为库 : Download Manager , Permissions , Notifications , Sharing …
基础库 : AppCompat , Android KTX , Multidex , Test …

5.2 Room使用跟greenDao非常相似,才采用大量注解生成表字段结构。比如@Entity,@PrimaryKey,@NonNull,@Ignore等

如下用户表示例:

  1. @Entity
  2. public class User {
  3. @PrimaryKey(autoGenerate = true)
  4. Long uid;
  5. @ColumnInfo(name = "account")
  6. String account;
  7. @ColumnInfo(name = "password")
  8. String password;
  9. @ColumnInfo(name = "name")
  10. String name;
  11. @Ignore
  12. String avatar;
  13. @NonNull
  14. boolean isChecked;
  15. public Long getUid() {
  16. return uid;
  17. }
  18. public void setUid(Long uid) {
  19. this.uid = uid;
  20. }
  21. public String getAccount() {
  22. return account;
  23. }
  24. public void setAccount(String account) {
  25. this.account = account;
  26. }
  27. public String getPassword() {
  28. return password;
  29. }
  30. public void setPassword(String password) {
  31. this.password = password;
  32. }
  33. public String getName() {
  34. return name;
  35. }
  36. public void setName(String name) {
  37. this.name = name;
  38. }
  39. public String getAvatar() {
  40. return avatar;
  41. }
  42. public void setAvatar(String avatar) {
  43. this.avatar = avatar;
  44. }
  45. public boolean isChecked() {
  46. return isChecked;
  47. }
  48. public void setChecked(boolean checked) {
  49. isChecked = checked;
  50. }
  51. }

5.3 使用Room,可以配合LiveData使用,也可以配合Rxjava使用。下面配合Rxjava示例:

添加Room依赖库,和Rxjava依赖库

  1. ependencies {
  2. implementation "androidx.room:room-runtime:2.5.0"
  3. annotationProcessor "androidx.room:room-compiler:2.5.0"
  4. implementation "androidx.room:room-rxjava2:2.4.2"
  5. implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
  6. }

5.4  定一个Dao管理类AppDatabase,继承自RoomDatabase

  1. @Database(entities = {User.class , Asset.class , Bill.class , Community.class , Ping.class}, version = 1)
  2. public abstract class AppDatabase extends RoomDatabase {
  3. public abstract UserDao userDao();
  4. public abstract AssetDao assetDao();
  5. public abstract BillDao billDao();
  6. public abstract CommunityDao communityDao();
  7. public abstract PingDao pingDao();
  8. }

5.5 封装Room数据库管理工具类DBHelper,管理AppDatabase

  1. public class DBHelper {
  2. private static AppDatabase appDatabase;
  3. //初始化数据库
  4. public static AppDatabase initDB() {
  5. if (appDatabase == null) {
  6. appDatabase = Room.databaseBuilder(App.getInstance(),
  7. AppDatabase.class, "finance.db").build();
  8. }
  9. return appDatabase;
  10. }
  11. //获取表管理类AppDatabase
  12. public static AppDatabase getDB() {
  13. if(appDatabase==null){
  14. initDB();
  15. }
  16. return appDatabase;
  17. }
  18. //关闭数据库
  19. public static void closeDB() {
  20. if (appDatabase != null && appDatabase.isOpen()) {
  21. appDatabase.close();
  22. }
  23. }
  24. }

5.5 在Application里面初始化Room数据库

  1. public class App extends Application {
  2. private static App app;
  3. @Override
  4. public void onCreate() {
  5. super.onCreate();
  6. if (app == null) {
  7. app = this;
  8. }
  9. //初始化Room数据库
  10. DBHelper.initDB();
  11. }
  12. public static App getInstance() {
  13. return app;
  14. }
  15. }

5.6 上面已经建了一个用户表User,可以再建一个UserDao来管理用户表的增删改查操作

以查询全部用户为例,不使用rxjava的写法

  1. @Dao
  2. public interface UserDao {
  3. //查询全部用户
  4. @Query("SELECT * FROM user")
  5. List<User> getAll();
  6. }

配合rxjava的写法 ,这个Single是rxjava里面的一个监听回调方法

  1. @Dao
  2. public interface UserDao {
  3. //查询全部数据
  4. @Query("SELECT * FROM user")
  5. Single<List<User>> getAll();
  6. }

5.7  完整的增删改查Rxjava写法,跟平时用Retrofit+Rxjava差不多 

  1. @Dao
  2. public interface UserDao {
  3. //插入一条或多条用户数据
  4. @Insert
  5. Single<List<Long>> insert(User... users);
  6. //删除一条数据
  7. @Delete
  8. Single<Integer> delete(User user);
  9. //查询全部数据
  10. @Query("SELECT * FROM user")
  11. Single<List<User>> getAll();
  12. //查询指定账户数据
  13. @Query("SELECT * FROM user where account=:account")
  14. Single<List<User>> getOnUser(String account);
  15. //查询指定id数据
  16. @Query("SELECT * FROM user where uid=:uid")
  17. Single<User> getOnUserById(long uid);
  18. }

异步插入一条数据 

  1. private void daoInsertUser(String account , String password){
  2. User user=new User();
  3. user.setAccount(account);
  4. user.setPassword(password);
  5. DBHelper.getDB().userDao().insert(user)
  6. .compose(DBHelper.singleSchedulers())
  7. .subscribe(new ObserverListener<List<Long>>() {
  8. @Override
  9. public void success(List<Long> longs) {
  10. }
  11. @Override
  12. public void onError(String msg) {
  13. }
  14. });
  15. }

异步获取全部用户

  1. private void daoGetUser(){
  2. DBHelper.getDB().userDao().getAll()
  3. .compose(DBHelper.singleSchedulers())
  4. .subscribe(new ObserverListener<List<User>>() {
  5. @Override
  6. public void success(List<User> users) {
  7. if(users.size()<=0){
  8. daoInsertUser("admin","123456");
  9. }
  10. }
  11. @Override
  12. public void onError(String msg) {
  13. ToastHelp.showToast(msg);
  14. }
  15. });
  16. }

里面的compose(DBHelper.singleSchedulers())是rxjava的一个线程调度,执行任务在子线程,返回结果更新UI在主线程

  1. public class DBHelper {
  2. public static <T> ObservableTransformer<T, T> schedulers() {
  3. return new ObservableTransformer<T, T>() {
  4. @Override
  5. public ObservableSource<T> apply(Observable<T> upstream) {
  6. return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
  7. }
  8. };
  9. }
  10. public static <T> SingleTransformer<T, T> singleSchedulers() {
  11. return new SingleTransformer<T, T>() {
  12. @Override
  13. public SingleSource<T> apply(Single<T> upstream) {
  14. return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
  15. }
  16. };
  17. }
  18. }

5.8 使用注意:

第一次使用可能报以下错误:

Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide room.schemaLocation annotation processor argument OR set exportSchema to false.

原因:

在编译时,Room 会将数据库的架构信息导出为 JSON 文件(默认exportSchema = true导出架构)。要导出架构,请在 build.gradle 文件中设置 room.schemaLocation 注释处理器属性(设置将json存放的位置)。

解决方法:

方法一:在app的build.gradle中添加如下javaCompileOptions 配置

  1. android {
  2. namespace 'com.dinghe.financeapp'
  3. compileSdk 33
  4. defaultConfig {
  5. applicationId "com.dinghe.financeapp"
  6. minSdk 21
  7. targetSdk 33
  8. versionCode 1
  9. versionName "1.0"
  10. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  11. javaCompileOptions {
  12. annotationProcessorOptions {
  13. arguments = ["room.schemaLocation" : "$projectDir/schemas".toString()]
  14. }
  15. }
  16. }

 方法二:在数据库注解中添加exportSchema = false

  1. @Database(entities = {User.class},version = 1,exportSchema = false)
  2. public abstract class AppDatabase extends RoomDatabase {
  3. public abstract UserDao userDao();
  4. }

六 总结

6.1 SQLiteOpenHelper原生api相对较少,需要自己写大量sql语句,开发维护成本较大。而且执行效率速度上没其它框架快,所有新项目还是以其它框架用的多,SQLiteOpenHelper小项目可以用。

6.2 GreenDao和Room的比较

  • GreenDao和Room用法上很类似,都是用了大量注解,比如@Entity,@ID等
  • GreenDao提供的api比Room多,GreenDao可以不写sql完成数据库的造作,但Room的查询还是通过写sql语句操作的
  • GreenDao编译后自动生成Dao,Room通过注解@Dao定义Dao
  • GreenDao会自动生成Set,Get方法,Room需要手动生成
  • GreenDao的增删改查通过api,Room的增删改查通过注解就可以,比如@Insert,@Update,@Delete
  • GreenDao支持Rxjava,不支持LiveData,Room由于Jetpack家族的强大同时支持Rxjava和liveData

6.3  GreenDao和Room架构图示对比

GreenDao:

 

Room:

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/480484
推荐阅读
相关标签
  

闽ICP备14008679号