赞
踩
一 简介
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,来管理数据库的创建和数据库表的创建
- public class DatabaseHelper extends SQLiteOpenHelper {
-
- public static final String DATABASE_NAME = "SMSManager.db";//数据库名字
-
- private static final int DATABASE_VERSION = 1; // 数据库的版本号
-
- public static final String CONTACTS_TABLE_NAME = "contacts_table";//联系人表名
-
- //创建联系人表SQL语句
- public static final String CREATE_CONTACTS_TABLE =
- "create table " +
- CONTACTS_TABLE_NAME +
- "(" +
- "cid integer primary key autoincrement," +
- "sendPhone varchar(50),name varchar(50) not null," +
- "phone varchar(50) not null" +
- ")";
-
-
- /**
- * DatabaseHelper构造函数,传参数据库名,数据库版本,会自动创建数据库
- * @param context
- */
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- /**
- * onCreate 回调SQLiteDatabase对象,自动执行创建表语句
- * @param db
- */
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(CREATE_CONTACTS_TABLE);
- }
-
- /**
- * 升级数据库。执行表结构变更语句
- * @param db
- * @param oldVersion
- * @param newVersion
- */
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // if (newVersion > 1) {
- // //Android的ALTER命令不支持一次添加多列,只能分多次添加
- // String alter_sql = "ALTER TABLE " + CONTACTS_TABLE_NAME + " ADD COLUMN " + "phone_new2 VARCHAR;";
- // db.execSQL(alter_sql);
- // alter_sql = "ALTER TABLE " + CONTACTS_TABLE_NAME + " ADD COLUMN " + "phone_new3 VARCHAR;";
- // db.execSQL(alter_sql); // 执行完整的SQL语句
- // }
- }
- }
3.3 创建联系人表的实体类ContactsInfo
- public class ContactsInfo implements Serializable{
- int cid;
- String name;
- String phone;
- String sendPhone;
- boolean isChoosed=false;
-
- public int getCid() {
- return cid;
- }
-
- public void setCid(int cid) {
- this.cid = cid;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getPhone() {
- return phone;
- }
-
- public void setPhone(String phone) {
- this.phone = phone;
- }
-
- public String getSendPhone() {
- return sendPhone;
- }
-
- public void setSendPhone(String sendPhone) {
- this.sendPhone = sendPhone;
- }
-
- public boolean isChoosed() {
- return isChoosed;
- }
-
- public void setChoosed(boolean choosed) {
- isChoosed = choosed;
- }
- }
3.4 创建联系人表的管理类ContactsDatabase,进行表的增删改查操作
- public class ContactsDatabase {
- private final DatabaseHelper dbHelper;
-
- public ContactsDatabase(Context context) {
- super();
- dbHelper = new DatabaseHelper(context);
- }
-
- /**
- * 增
- *
- * @param data
- */
- public void insert(ContactsInfo data) {
- String sql = "insert into " + DatabaseHelper.CONTACTS_TABLE_NAME;
-
- sql += "(sendPhone, name, phone) values(?,?,?)";
-
- SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
- sqlite.execSQL(sql, new String[] {data.getSendPhone() + "",data.getName() + "", data.getPhone() + ""});
- sqlite.close();
- }
-
- /**
- * 删
- *
- * @param where
- */
- public void delete(String where) {
- SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
- String sql = "delete from " + DatabaseHelper.CONTACTS_TABLE_NAME + where;
- sqlite.execSQL(sql);
- sqlite.close();
- }
-
- /**
- * 改
- *
- * @param data
- */
- public void update(ContactsInfo data) {
- SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
- String sql = ("update " + DatabaseHelper.CONTACTS_TABLE_NAME +" set sendPhone=?,name=?,phone=? where cid=?");
- sqlite.execSQL(sql,
- new String[] { data.getSendPhone() + "", data.getName() + "", data.getPhone()+ "", data.getCid()+ ""});
- sqlite.close();
- }
- /**
- * 查一条数据
- *
- * @param where
- * @return
- */
- public ContactsInfo queryContactsInfo(String where) {
- ContactsInfo contactsInfo = null;
- SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
- String sql= "select * from "
- + DatabaseHelper.CONTACTS_TABLE_NAME + where;
- Cursor cursor = sqlite.rawQuery(sql, null);
- for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
- contactsInfo= new ContactsInfo();
- contactsInfo.setCid(cursor.getInt(0));
- contactsInfo.setSendPhone(cursor.getString(1));
- contactsInfo.setName(cursor.getString(2));
- contactsInfo.setPhone(cursor.getString(3));
- }
- if (!cursor.isClosed()) {
- cursor.close();
- }
- sqlite.close();
- return contactsInfo;
- }
-
- /**
- * 查
- *
- * @param where
- * @return
- */
- public List<ContactsInfo> query(String where) {
- SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
- ArrayList<ContactsInfo> data = null;
- data = new ArrayList<ContactsInfo>();
- String sql="select * from "
- + DatabaseHelper.CONTACTS_TABLE_NAME + where;
- Cursor cursor = sqlite.rawQuery(sql, null);
- for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
- ContactsInfo contactsInfo = new ContactsInfo();
- contactsInfo.setSendPhone(cursor.getString(1));
- contactsInfo.setName(cursor.getString(2));
- contactsInfo.setPhone(cursor.getString(3));
- data.add(contactsInfo);
- }
- if (!cursor.isClosed()) {
- cursor.close();
- }
- sqlite.close();
- return data;
- }
- /**
- * 查
- *
- * @param where
- * @return
- */
- public int queryCount(String where) {
- SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
- String sql="select count(*) from "
- + DatabaseHelper.CONTACTS_TABLE_NAME+where ;
- Cursor cursor = sqlite.rawQuery(sql, null);
- cursor.moveToFirst();
- int count = cursor.getInt(0);
- sqlite.close();
- return count;
- }
-
- /**
- * 重置
- *
- * @param datas
- */
- public void reset(List<ContactsInfo> datas) {
- if (datas != null) {
- SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
- // 删除全部
- sqlite.execSQL("delete from " + DatabaseHelper.CONTACTS_TABLE_NAME);
- // 重新添加
- for (ContactsInfo data : datas) {
- insert(data);
- }
- sqlite.close();
- }
- }
-
- public void destroy() {
- dbHelper.close();
- }
- }
3.5 总结:
第一步:SQLiteOpenHelper的构造函数创建数据库
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, 1);
- }
第二步:SQLiteOpenHelper的onCreate里面执行创建表的sql语句
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(CREATE_CONTACTS_TABLE);
- }
第三步:获取当前数据库对象实例,打开数据库,进行增删改查操作
- SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
-
- sqlite .insert(TABLE_NAME, "",entity);
-
- sqlite .delete(TABLE_NAME, entity, null);
-
- sqlite .update(TABLE_NAME, entity, "name=?", new String[]{info.name});
-
- sqlite .rawQuery(sql, null);
第四步:关闭数据库
- if (sqlite != null && sqlite .isOpen()) {
- sqlite .close();
- sqlite = null;
- }
四 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的插件
- dependencies {
- classpath "com.android.tools.build:gradle:7.0.0"
- classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0'
- }
app的build.gradle里面使用插件,配置数据库,并引入greenDao的依赖库
- plugins {
- id 'com.android.application'
- id 'org.greenrobot.greendao'
- }
-
- android {
- compileSdk 32
-
- defaultConfig {
- applicationId "com.greendao.demo"
- minSdk 21
- targetSdk 32
- versionCode 1
- versionName "1.0"
- }
- }
-
- greendao {
- //指定数据库schema版本号,迁移等操作会用到
- schemaVersion 1
- //设置生成数据库文件的目录,默认是在build中,可以将生成的文件放到我们的java目录中
- targetGenDir 'src/main/java'
- //设置生成的数据库相关文件的包名,默认为entity所在的包名
- daoPackage 'com.greendao.demo.greendao.database'
- }
-
-
- dependencies {
- implementation 'org.greenrobot:greendao:3.3.0'
- }
4.5 封装数据库管理器DaoManager,用来创建数据库、创建数据库表、包含增删改查的操作以及数据库的升级
- /**
- * 创建数据库、创建数据库表、包含增删改查的操作以及数据库的升级
- */
- public class DaoManager
- {
- private static final String TAG = DaoManager.class.getSimpleName();
- private static final String DB_NAME = "diary.db";
-
- private Context context;
-
- //多线程中要被共享的使用volatile关键字修饰
- private volatile static DaoManager manager ;
- private static DaoMaster sDaoMaster;
- private static DaoMaster.DevOpenHelper sHelper;
- private static DaoSession sDaoSession;
-
- /**
- * 单例模式获得操作数据库对象
- *
- * @return
- */
- public static DaoManager getInstance()
- {
- synchronized (DaoManager.class) {
- if (manager == null) {
- manager = new DaoManager();
- }
- }
- return manager;
- }
-
- private DaoManager()
- {
- setDebug();
- }
-
- public void init(Context context)
- {
- this.context = context;
- }
-
- /**
- * 判断是否有存在数据库,如果没有则创建
- *
- * @return
- */
- public DaoMaster getDaoMaster()
- {
- if (sDaoMaster == null)
- {
- sHelper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
- sDaoMaster = new DaoMaster(sHelper.getWritableDatabase());
- }
- return sDaoMaster;
- }
-
- /**
- * 完成对数据库的添加、删除、修改、查询操作,仅仅是一个接口
- *
- * @return
- */
- public DaoSession getDaoSession()
- {
- if (sDaoSession == null)
- {
- if (sDaoMaster == null)
- {
- sDaoMaster = getDaoMaster();
- }
- sDaoSession = sDaoMaster.newSession();
- }
- return sDaoSession;
- }
-
- /**
- * 打开输出日志,默认关闭
- */
- public void setDebug()
- {
- if (BuildConfig.DEBUG)
- {
- QueryBuilder.LOG_SQL = true;
- QueryBuilder.LOG_VALUES = true;
- }
- }
-
- /**
- * 关闭所有的操作,数据库开启后,使用完毕要关闭
- */
- public void closeConnection()
- {
- closeHelper();
- closeDaoSession();
- }
-
- public void closeHelper()
- {
- if (sHelper != null)
- {
- sHelper.close();
- sHelper = null;
- }
- }
-
- public void closeDaoSession()
- {
- if (sDaoSession != null)
- {
- sDaoSession.clear();
- sDaoSession = null;
- }
- }
- }
4.6 在项目Application里面初始化GreenDAO
DaoManager.getInstance().init(this);
4.7 以Uer表为例,创建一个User实体类。实体类开头必须加 @Entity 注解
- @Entity
- public class User {
- @Id(autoincrement = true)
- Long id;
- String account;
- String password;
- String name="tom";
- String avatar;
- int gender=0;
- String mobile;
- @Generated(hash = 998056223)
- public User(Long id, String account, String password, String name,
- String avatar, int gender, String mobile) {
- this.id = id;
- this.account = account;
- this.password = password;
- this.name = name;
- this.avatar = avatar;
- this.gender = gender;
- this.mobile = mobile;
- }
- }
编译后User实体类目会自动生成GET,SET方法
- @Entity
- public class User {
- @Id(autoincrement = true)
- Long id;
- String account;
- String password;
- String name="tom";
- String avatar;
- int gender=0;
- String mobile;
- @Generated(hash = 998056223)
- public User(Long id, String account, String password, String name,
- String avatar, int gender, String mobile) {
- this.id = id;
- this.account = account;
- this.password = password;
- this.name = name;
- this.avatar = avatar;
- this.gender = gender;
- this.mobile = mobile;
- }
- @Generated(hash = 586692638)
- public User() {
- }
- public Long getId() {
- return this.id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getAccount() {
- return this.account;
- }
- public void setAccount(String account) {
- this.account = account;
- }
- public String getPassword() {
- return this.password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getName() {
- return this.name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAvatar() {
- return this.avatar;
- }
- public void setAvatar(String avatar) {
- this.avatar = avatar;
- }
- public int getGender() {
- return this.gender;
- }
- public void setGender(int gender) {
- this.gender = gender;
- }
- public String getMobile() {
- return this.mobile;
- }
- public void setMobile(String mobile) {
- this.mobile = mobile;
- }
-
- }
同时编译后还会在 build 目录下生成XXXDao实体类,通过DAO实体就能操作数据库了
4.7 可以封装一个通用的增删改查工具类,这样像正常操作对象那样就可以了
- /**
- * 通用greendao工具
- * @param <T>
- */
- public class CommonDaoUtils<T> {
-
- private static final String TAG = CommonDaoUtils.class.getSimpleName();
-
- private DaoSession daoSession;
- private Class<T> entityClass;
- private AbstractDao<T, Long> entityDao;
-
- public CommonDaoUtils(Class<T> pEntityClass, AbstractDao<T, Long> pEntityDao)
- {
- DaoManager mManager = DaoManager.getInstance();
- daoSession = mManager.getDaoSession();
- entityClass = pEntityClass;
- entityDao = pEntityDao;
- }
-
- public DaoSession getDaoSession() {
- return daoSession;
- }
-
- /**
- * 插入记录,如果表未创建,先创建表
- *
- * @param pEntity
- * @return
- */
- public boolean insert(T pEntity)
- {
- boolean flag = entityDao.insert(pEntity) == -1 ? false : true;
- return flag;
- }
-
- /**
- * 插入记录数据存在则替换,数据不存在则插入
- *
- * @param pEntity
- * @return
- */
- public boolean insertOrReplace(T pEntity)
- {
- boolean flag = entityDao.insertOrReplace(pEntity) == -1 ? false : true;
- return flag;
- }
-
-
- /**
- * 插入多条数据,在子线程操作
- *
- * @param pEntityList
- * @return
- */
- public boolean insertMulti(final List<T> pEntityList)
- {
- try
- {
- daoSession.runInTx(new Runnable()
- {
- @Override
- public void run()
- {
- for (T meizi : pEntityList)
- {
- daoSession.insertOrReplace(meizi);
- }
- }
- });
- return true;
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return false;
- }
-
- /**
- * 修改一条数据
- *
- * @param pEntity
- * @return
- */
- public boolean update(T pEntity)
- {
- try
- {
- daoSession.update(pEntity);
- return true;
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return false;
- }
-
- /**
- * 删除单条记录
- *
- * @param pEntity
- * @return
- */
- public boolean delete(T pEntity)
- {
- try
- {
- //按照id删除
- daoSession.delete(pEntity);
- return true;
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return false;
- }
-
- /**
- * 删除所有记录
- *
- * @return
- */
- public boolean deleteAll()
- {
- try
- {
- //按照id删除
- daoSession.deleteAll(entityClass);
- return true;
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return false;
- }
-
- /**
- * 查询所有记录
- *
- * @return
- */
- public List<T> queryAll()
- {
- return daoSession.loadAll(entityClass);
- }
-
- /**
- * 根据主键id查询记录
- *
- * @param key
- * @return
- */
- public T queryById(long key)
- {
- return daoSession.load(entityClass, key);
- }
-
- /**
- * 使用native sql进行查询操作
- */
- public List<T> queryByNativeSql(String sql, String[] conditions)
- {
- return daoSession.queryRaw(entityClass, sql, conditions);
- }
-
-
- /**
- * 使用queryBuilder进行查询
- *
- * @return
- */
- public List<T> queryByQueryBuilder(WhereCondition cond, WhereCondition... condMore)
- {
- QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
- return queryBuilder.where(cond, condMore).list();
- }
- /**
- * 使用queryBuilder进行查询
- *
- * @return
- */
- public List<T> queryByBuilder(WhereCondition cond)
- {
- QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
- return queryBuilder.where(cond).list();
- }
-
- }
4.8 再定义具体的Dao操作类,实现单独管理
- public class DaoUserUtils
- {
- private volatile static DaoUserUtils instance;
-
- public CommonDaoUtils<User> userCommonDaoUtils;
-
-
- public static DaoUserUtils getInstance()
- {
- synchronized (DaoUserUtils.class) {
- if(instance==null){
- instance = new DaoUserUtils();
- }
- }
-
- return instance;
- }
-
- private DaoUserUtils()
- {
- DaoManager mManager = DaoManager.getInstance();
-
- userCommonDaoUtils = new CommonDaoUtils(User.class,mManager.getDaoSession().getUserDao());
-
- }
-
-
- //新建用户
- public void daoInsertDefaultUser(){
- String account="boss1";
- String password="123456";
- if(daoQueryAllUser().size()==0){
- User user= new User();
- user.setAccount(account);
- user.setPassword(password);
- userCommonDaoUtils.insert(user);
- }
- }
-
- //查询用户
- public List<User> daoQueryAllUser(){
- return userCommonDaoUtils.queryAll();
- }
-
- //查询用户
- public User daoQueryUser(long id){
- return userCommonDaoUtils.queryById(id);
- }
-
-
- //删除用户
- public boolean deleteAllUser(){
- return userCommonDaoUtils.deleteAll();
- }
-
- //更新用户
- public boolean updateUser(User user){
- return userCommonDaoUtils.update(user);
- }
- }
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语句查询
- /**
- * @param sql 查询语句
- * @param conditions 位字段赋值
- * @return
- */
- public List<T> queryByNativeSql(String sql, String[] conditions)
- {
- DaoMaster.DevOpenHelper sHelper= new DaoMaster.DevOpenHelper(context, DB_NAME, null);
- DaoSession daoSession = new DaoMaster(sHelper.getWritableDatabase());
-
- return daoSession.queryRaw(entityClass, sql, conditions);
- }
比如:
queryByNativeSql("where columnName=?", new String[]{coverId});
4.11 queryBuilder()纯api查询,不用写任何sql语句
- /**
- * @param cond 一个条件
- * @param condMore 多个条件
- * @return
- */
- public List<T> queryByQueryBuilder(WhereCondition cond, WhereCondition... condMore)
- {
- DaoMaster.DevOpenHelper sHelper= new DaoMaster.DevOpenHelper(context, DB_NAME, null);
- DaoSession daoSession = new DaoMaster(sHelper.getWritableDatabase());
-
- QueryBuilder<T> queryBuilder = daoSession.queryBuilder(entityClass);
- return queryBuilder.where(cond, condMore).list();
- }
比如:
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方法。
- @Entity(
- schema = "myschema",
- active = true,
- nameInDb = "AWESOME_USERS",
- indexes = {
- @Index(value = "message DESC", unique = true)
- },
- createInDb = false,
- generateConstructors = true,
- generateGettersSetters = true
- )
- public class User{
-
- }
基础属性注解
@Id
@Id注解选择 long / Long属性作为实体ID。在数据库方面,它是主键。参数autoincrement = true 表示自增,id不给赋值或者为赋值为null即可(这里需要注意,如果要实现自增,id必须是Long)
- @Entity
- public class User{
- @Id(autoincrement = true)
- Long uid;
- }
@Property
允许您定义属性映射到的非默认列名。如果不存在,GreenDAO将使用字段名称。会生成大写列名,如 name将成为 NAME
- @Entity
- public class User{
- @Id(autoincrement = true)
- Long id;
-
- //设置了,数据库中的表格属性名为"name",如果不设置,数据库中表格属性名为"NAME"
- @Property (nameInDb="name")
- String name;
- }
@NotNull
设置数据库表当前列不能为空
- @Entity
- public class User{
- @NotNull
- String password;
- }
@Transient
添加次标记之后不会生成数据库表的列。标记要从持久性中排除的属性。将它们用于临时状态等。或者,您也可以使用Java中的transient关键字
- @Entity
- public class User{
- @Transient
- boolean isChecked;
- }
索引注解
@Index
创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束。
@Unique
向索引添加UNIQUE约束,强制所有值都是唯一的。
- @Entity
- public class User{
- @Id(autoincrement = true)
- Long id;
-
- @Index(unique = true)
- String account;
- }
关系注解
@ToOne:
定义与另一个实体(一个实体对象)的关系
创建用户表和身份证表,一个人对应一个身份证
- @Entity
- public class Student {
- @Id(autoincrement = true)
- Long uid;
-
- String name;
-
- Long cardId;
-
- @ToOne(joinProperty = "cardId")
- Card card;
- }
- @Entity
- public class Card {
- @Id(autoincrement = true)
- Long cardId;
-
- String carNo;
- }
@ToMany:
定义与多个实体对象的关系
创建用户表和银行卡表,一个人对应多张银行卡
- @Entity
- public class Student {
- @Id(autoincrement = true)
- Long uid;
-
- @Property (nameInDb="name")
- String newm;
-
- //这个 uid是对应在 BankCard 中的 uid
- @ToMany(referencedJoinProperty = "uid")
- List<BankCard> bankCardList;
- }
- @Entity
- public class BanKCard {
- @Id(autoincrement = true)
- Long cardId;
- String carNo;
-
- Long uid;
- }
五 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等
如下用户表示例:
- @Entity
- public class User {
- @PrimaryKey(autoGenerate = true)
- Long uid;
- @ColumnInfo(name = "account")
- String account;
- @ColumnInfo(name = "password")
- String password;
- @ColumnInfo(name = "name")
- String name;
- @Ignore
- String avatar;
-
- @NonNull
- boolean isChecked;
-
- public Long getUid() {
- return uid;
- }
-
- public void setUid(Long uid) {
- this.uid = uid;
- }
-
- public String getAccount() {
- return account;
- }
-
- public void setAccount(String account) {
- this.account = account;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getAvatar() {
- return avatar;
- }
-
- public void setAvatar(String avatar) {
- this.avatar = avatar;
- }
-
- public boolean isChecked() {
- return isChecked;
- }
-
- public void setChecked(boolean checked) {
- isChecked = checked;
- }
- }
5.3 使用Room,可以配合LiveData使用,也可以配合Rxjava使用。下面配合Rxjava示例:
添加Room依赖库,和Rxjava依赖库
- ependencies {
- implementation "androidx.room:room-runtime:2.5.0"
- annotationProcessor "androidx.room:room-compiler:2.5.0"
- implementation "androidx.room:room-rxjava2:2.4.2"
- implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
- }
5.4 定一个Dao管理类AppDatabase,继承自RoomDatabase
- @Database(entities = {User.class , Asset.class , Bill.class , Community.class , Ping.class}, version = 1)
- public abstract class AppDatabase extends RoomDatabase {
- public abstract UserDao userDao();
- public abstract AssetDao assetDao();
- public abstract BillDao billDao();
- public abstract CommunityDao communityDao();
- public abstract PingDao pingDao();
- }
5.5 封装Room数据库管理工具类DBHelper,管理AppDatabase
- public class DBHelper {
- private static AppDatabase appDatabase;
-
- //初始化数据库
- public static AppDatabase initDB() {
- if (appDatabase == null) {
- appDatabase = Room.databaseBuilder(App.getInstance(),
- AppDatabase.class, "finance.db").build();
- }
- return appDatabase;
- }
-
- //获取表管理类AppDatabase
- public static AppDatabase getDB() {
- if(appDatabase==null){
- initDB();
- }
- return appDatabase;
- }
-
-
- //关闭数据库
- public static void closeDB() {
- if (appDatabase != null && appDatabase.isOpen()) {
- appDatabase.close();
- }
- }
-
- }
5.5 在Application里面初始化Room数据库
- public class App extends Application {
- private static App app;
-
- @Override
- public void onCreate() {
- super.onCreate();
- if (app == null) {
- app = this;
- }
-
- //初始化Room数据库
- DBHelper.initDB();
- }
-
- public static App getInstance() {
- return app;
- }
- }
5.6 上面已经建了一个用户表User,可以再建一个UserDao来管理用户表的增删改查操作
以查询全部用户为例,不使用rxjava的写法
- @Dao
- public interface UserDao {
- //查询全部用户
- @Query("SELECT * FROM user")
- List<User> getAll();
- }
配合rxjava的写法 ,这个Single是rxjava里面的一个监听回调方法
- @Dao
- public interface UserDao {
- //查询全部数据
- @Query("SELECT * FROM user")
- Single<List<User>> getAll();
- }
5.7 完整的增删改查Rxjava写法,跟平时用Retrofit+Rxjava差不多
- @Dao
- public interface UserDao {
-
- //插入一条或多条用户数据
- @Insert
- Single<List<Long>> insert(User... users);
-
- //删除一条数据
- @Delete
- Single<Integer> delete(User user);
-
- //查询全部数据
- @Query("SELECT * FROM user")
- Single<List<User>> getAll();
-
- //查询指定账户数据
- @Query("SELECT * FROM user where account=:account")
- Single<List<User>> getOnUser(String account);
-
- //查询指定id数据
- @Query("SELECT * FROM user where uid=:uid")
- Single<User> getOnUserById(long uid);
- }
异步插入一条数据
- private void daoInsertUser(String account , String password){
- User user=new User();
- user.setAccount(account);
- user.setPassword(password);
- DBHelper.getDB().userDao().insert(user)
- .compose(DBHelper.singleSchedulers())
- .subscribe(new ObserverListener<List<Long>>() {
- @Override
- public void success(List<Long> longs) {
-
- }
-
- @Override
- public void onError(String msg) {
-
- }
- });
-
- }
异步获取全部用户
- private void daoGetUser(){
- DBHelper.getDB().userDao().getAll()
- .compose(DBHelper.singleSchedulers())
- .subscribe(new ObserverListener<List<User>>() {
- @Override
- public void success(List<User> users) {
- if(users.size()<=0){
- daoInsertUser("admin","123456");
- }
- }
-
- @Override
- public void onError(String msg) {
- ToastHelp.showToast(msg);
- }
- });
- }
里面的compose(DBHelper.singleSchedulers())是rxjava的一个线程调度,执行任务在子线程,返回结果更新UI在主线程
- public class DBHelper {
- public static <T> ObservableTransformer<T, T> schedulers() {
- return new ObservableTransformer<T, T>() {
- @Override
- public ObservableSource<T> apply(Observable<T> upstream) {
- return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
- }
- };
- }
-
- public static <T> SingleTransformer<T, T> singleSchedulers() {
- return new SingleTransformer<T, T>() {
- @Override
- public SingleSource<T> apply(Single<T> upstream) {
- return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
- }
- };
- }
- }
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 配置
- android {
- namespace 'com.dinghe.financeapp'
- compileSdk 33
-
- defaultConfig {
- applicationId "com.dinghe.financeapp"
- minSdk 21
- targetSdk 33
- versionCode 1
- versionName "1.0"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-
-
- javaCompileOptions {
- annotationProcessorOptions {
- arguments = ["room.schemaLocation" : "$projectDir/schemas".toString()]
- }
- }
- }
方法二:在数据库注解中添加exportSchema = false
- @Database(entities = {User.class},version = 1,exportSchema = false)
- public abstract class AppDatabase extends RoomDatabase {
- public abstract UserDao userDao();
-
- }
六 总结
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:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。