一 簡介
1.1 上節(jié)說了關(guān)系型數(shù)據(jù)庫有以下幾種:
Oracle、Microsoft SQL Server、Microsoft Access、MySQL、SQLite
1.2 各自的領(lǐng)域也不一樣
java,C#,php等用Oracle,Microsoft SQL Server,MySQL比較多。
移動端Android,IOS等用SQLite比較多
1.3?SQLite是一種輕量型數(shù)據(jù)庫,有以下優(yōu)點:
不需要一個單獨的服務(wù)器進程或操作的系統(tǒng)(無服務(wù)器的)。
SQLite 不需要配置,這意味著不需要安裝或管理。
一個完整的 SQLite 數(shù)據(jù)庫是存儲在一個單一的跨平臺的磁盤文件。
SQLite 是非常小的,是輕量級的,完全配置時小于 400KiB,省略可選功能配置時小于250KiB。
SQLite 是自給自足的,這意味著不需要任何外部的依賴。
SQLite 事務(wù)是完全兼容 ACID 的,允許從多個進程或線程安全訪問。
SQLite 支持 SQL92(SQL2)標(biāo)準(zhǔn)的大多數(shù)查詢語言的功能。
SQLite 使用 ANSI-C 編寫的,并提供了簡單和易于使用的 API。
SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中運行。
二 Android 本地數(shù)據(jù)庫框架?
2.1 android數(shù)據(jù)庫框架有Room,Relam,GreenDAO,ObjectBox,SQLDelight等等。
2.2 常用的有Room,GreenDAO等,在前兩個沒出現(xiàn)之前主要用的Android官方原生框架SQLiteOpenHelper。
三?SQLiteOpenHelper 框架的使用
3.1?SQLiteOpenHelper是官方api,因此不需要引入其它庫。如下可以看到,SQLiteOpenHelper在android.database.sqlite包下面
?3.2?SQLiteOpenHelper的使用,自定義DatabaseHelper,繼承SQLiteOpenHelper,來管理數(shù)據(jù)庫的創(chuàng)建和數(shù)據(jù)庫表的創(chuàng)建
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "SMSManager.db";//數(shù)據(jù)庫名字
private static final int DATABASE_VERSION = 1; // 數(shù)據(jù)庫的版本號
public static final String CONTACTS_TABLE_NAME = "contacts_table";//聯(lián)系人表名
//創(chuàng)建聯(lián)系人表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構(gòu)造函數(shù),傳參數(shù)據(jù)庫名,數(shù)據(jù)庫版本,會自動創(chuàng)建數(shù)據(jù)庫
* @param context
*/
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* onCreate 回調(diào)SQLiteDatabase對象,自動執(zhí)行創(chuàng)建表語句
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_CONTACTS_TABLE);
}
/**
* 升級數(shù)據(jù)庫。執(zhí)行表結(jié)構(gòu)變更語句
* @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); // 執(zhí)行完整的SQL語句
// }
}
}
3.3 創(chuàng)建聯(lián)系人表的實體類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 創(chuàng)建聯(lián)系人表的管理類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();
}
/**
* 查一條數(shù)據(jù)
*
* @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 總結(jié):
第一步:SQLiteOpenHelper的構(gòu)造函數(shù)創(chuàng)建數(shù)據(jù)庫
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
第二步:SQLiteOpenHelper的onCreate里面執(zhí)行創(chuàng)建表的sql語句
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_CONTACTS_TABLE);
}
第三步:獲取當(dāng)前數(shù)據(jù)庫對象實例,打開數(shù)據(jù)庫,進行增刪改查操作
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);
第四步:關(guān)閉數(shù)據(jù)庫
if (sqlite != null && sqlite .isOpen()) {
?? ?sqlite .close();
?? ?sqlite = null;
}
四?GreenDAO 框架的使用
4.1?GreenDAO 是一種輕量級快速ORM 框架,可將對象映射到 SQLite 數(shù)據(jù)庫中
4.2?ORM 框架,即 Object-Relational Mapping,它的作用是在關(guān)系型數(shù)據(jù)庫和對象之間作一個映射,這樣,我們在具體操作數(shù)據(jù)庫的時候,就不需要再去和復(fù)雜的 SQL 語句打交道,只是像平時操作對象一樣操作它就可以了
?4.3?GreenDAO主要類介紹
- DaoMaster:DaoMaster保存數(shù)據(jù)庫對象(SQLiteDatabase)并管理特定模式的DAO類(而不是對象)。它有靜態(tài)方法來創(chuàng)建表或刪除它們。它的內(nèi)部類OpenHelper和DevOpenHelper是SQLiteOpenHelper實現(xiàn),它們在SQLite數(shù)據(jù)庫中創(chuàng)建模式。
- DaoSession:管理特定模式的所有可用DAO對象,您可以使用其中一個getter方法獲取該對象。DaoSession還提供了一些通用的持久性方法,如實體的插入,加載,更新,刷新和刪除。
- DAO:數(shù)據(jù)訪問對象(DAO)持久存在并查詢實體。對于每個實體,greenDAO生成實體XXDAO。它具有比DaoSession更多的持久性方法,例如:count,loadAll和insert等。
- Entities :可持久化對象。通常, 實體對象代表一個數(shù)據(jù)庫行使用標(biāo)準(zhǔn) 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里面使用插件,配置數(shù)據(jù)庫,并引入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 {
//指定數(shù)據(jù)庫schema版本號,遷移等操作會用到
schemaVersion 1
//設(shè)置生成數(shù)據(jù)庫文件的目錄,默認是在build中,可以將生成的文件放到我們的java目錄中
targetGenDir 'src/main/java'
//設(shè)置生成的數(shù)據(jù)庫相關(guān)文件的包名,默認為entity所在的包名
daoPackage 'com.greendao.demo.greendao.database'
}
dependencies {
implementation 'org.greenrobot:greendao:3.3.0'
}
4.5 封裝數(shù)據(jù)庫管理器DaoManager,用來創(chuàng)建數(shù)據(jù)庫、創(chuàng)建數(shù)據(jù)庫表、包含增刪改查的操作以及數(shù)據(jù)庫的升級
/**
* 創(chuàng)建數(shù)據(jù)庫、創(chuàng)建數(shù)據(jù)庫表、包含增刪改查的操作以及數(shù)據(jù)庫的升級
*/
public class DaoManager
{
private static final String TAG = DaoManager.class.getSimpleName();
private static final String DB_NAME = "diary.db";
private Context context;
//多線程中要被共享的使用volatile關(guān)鍵字修飾
private volatile static DaoManager manager ;
private static DaoMaster sDaoMaster;
private static DaoMaster.DevOpenHelper sHelper;
private static DaoSession sDaoSession;
/**
* 單例模式獲得操作數(shù)據(jù)庫對象
*
* @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;
}
/**
* 判斷是否有存在數(shù)據(jù)庫,如果沒有則創(chuàng)建
*
* @return
*/
public DaoMaster getDaoMaster()
{
if (sDaoMaster == null)
{
sHelper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);
sDaoMaster = new DaoMaster(sHelper.getWritableDatabase());
}
return sDaoMaster;
}
/**
* 完成對數(shù)據(jù)庫的添加、刪除、修改、查詢操作,僅僅是一個接口
*
* @return
*/
public DaoSession getDaoSession()
{
if (sDaoSession == null)
{
if (sDaoMaster == null)
{
sDaoMaster = getDaoMaster();
}
sDaoSession = sDaoMaster.newSession();
}
return sDaoSession;
}
/**
* 打開輸出日志,默認關(guān)閉
*/
public void setDebug()
{
if (BuildConfig.DEBUG)
{
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
}
}
/**
* 關(guān)閉所有的操作,數(shù)據(jù)庫開啟后,使用完畢要關(guān)閉
*/
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表為例,創(chuàng)建一個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實體就能操作數(shù)據(jù)庫了
?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;
}
/**
* 插入記錄,如果表未創(chuàng)建,先創(chuàng)建表
*
* @param pEntity
* @return
*/
public boolean insert(T pEntity)
{
boolean flag = entityDao.insert(pEntity) == -1 ? false : true;
return flag;
}
/**
* 插入記錄數(shù)據(jù)存在則替換,數(shù)據(jù)不存在則插入
*
* @param pEntity
* @return
*/
public boolean insertOrReplace(T pEntity)
{
boolean flag = entityDao.insertOrReplace(pEntity) == -1 ? false : true;
return flag;
}
/**
* 插入多條數(shù)據(jù),在子線程操作
*
* @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;
}
/**
* 修改一條數(shù)據(jù)
*
* @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);
}
/**
* 根據(jù)主鍵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操作類,實現(xiàn)單獨管理
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提供有豐富的操作數(shù)據(jù)庫接口,比如查詢常用的三種方式:
- load(entityClass, dataKey); 主鍵查詢單條數(shù)據(jù)
- loadAll():查詢所有數(shù)據(jù)。
- queryRaw():根據(jù)條件查詢。
- queryBuilder() : 方便查詢的創(chuàng)建,后面詳細講解。
而且queryBuilder功能非常強大,比如下面常見的方法:
- where(WhereCondition cond, WhereCondition... condMore): 查詢條件,參數(shù)為查詢的條件!
- or(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore): 嵌套條件或者,用法同or。
- and(WhereCondition cond1, WhereCondition cond2, WhereCondition... condMore): 嵌套條件且,用法同and。
- join(Property sourceProperty, Class<J> destinationEntityClass):多表查詢,后面會講。
輸出結(jié)果有四種方式,選擇其中一種最適合的即可,list()返回值是List,而其他三種返回值均實現(xiàn)Closeable,需要注意的不使用數(shù)據(jù)時游標(biāo)的關(guān)閉操作:- list ()所有實體都加載到內(nèi)存中。結(jié)果通常是一個沒有魔法的 ArrayList。最容易使用。
- listLazy ()實體按需加載到內(nèi)存中。首次訪問列表中的元素后,將加載并緩存該元素以供將來使用。必須關(guān)閉。
- listLazyUncached ()實體的“虛擬”列表:對列表元素的任何訪問都會導(dǎo)致從數(shù)據(jù)庫加載其數(shù)據(jù)。必須關(guān)閉。
- listIterator ()讓我們通過按需加載數(shù)據(jù)(懶惰)來迭代結(jié)果。數(shù)據(jù)未緩存。必須關(guān)閉。
- orderAsc() 按某個屬性升序排;
- orderDesc() 按某個屬性降序排;
以及Property中豐富的查詢函數(shù):
- 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才會創(chuàng)建對應(yīng)的表
@Entity配置:
- schema:如果你有多個架構(gòu),你可以告訴GreenDao當(dāng)前屬于哪個架構(gòu)。
- active:標(biāo)記一個實體處于活躍狀態(tài),活動實體有更新、刪除和刷新方法。
- nameInDb:在數(shù)據(jù)中使用的別名,默認使用的是實體的類名。
- indexes:標(biāo)記如果DAO應(yīng)該創(chuàng)建數(shù)據(jù)庫表(默認為true),如果您有多個實體映射到一個表,或者表的創(chuàng)建是在greenDAO之外進行的,那么將其設(shè)置為false。
- createInDb:標(biāo)記創(chuàng)建數(shù)據(jù)庫表。
- generateGettersSetters:如果缺少,是否應(yīng)生成屬性的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{
}
基礎(chǔ)屬性注解
@Id
@Id注解選擇 long / Long屬性作為實體ID。在數(shù)據(jù)庫方面,它是主鍵。參數(shù)autoincrement = true 表示自增,id不給賦值或者為賦值為null即可(這里需要注意,如果要實現(xiàn)自增,id必須是Long)
@Entity
public class User{
@Id(autoincrement = true)
Long uid;
}
@Property
允許您定義屬性映射到的非默認列名。如果不存在,GreenDAO將使用字段名稱。會生成大寫列名,如 name將成為 NAME
@Entity
public class User{
@Id(autoincrement = true)
Long id;
//設(shè)置了,數(shù)據(jù)庫中的表格屬性名為"name",如果不設(shè)置,數(shù)據(jù)庫中表格屬性名為"NAME"
@Property (nameInDb="name")
String name;
}
@NotNull
設(shè)置數(shù)據(jù)庫表當(dāng)前列不能為空
@Entity
public class User{
@NotNull
String password;
}
@Transient?
添加次標(biāo)記之后不會生成數(shù)據(jù)庫表的列。標(biāo)記要從持久性中排除的屬性。將它們用于臨時狀態(tài)等?;蛘?,您也可以使用Java中的transient關(guān)鍵字
@Entity
public class User{
@Transient
boolean isChecked;
}
索引注解
@Index
創(chuàng)建一個索引,通過name設(shè)置索引別名,也可以通過unique給索引添加約束。
@Unique
向索引添加UNIQUE約束,強制所有值都是唯一的。
@Entity
public class User{
@Id(autoincrement = true)
Long id;
@Index(unique = true)
String account;
}
關(guān)系注解
@ToOne:
定義與另一個實體(一個實體對象)的關(guān)系
創(chuàng)建用戶表和身份證表,一個人對應(yīng)一個身份證
@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:
定義與多個實體對象的關(guān)系
創(chuàng)建用戶表和銀行卡表,一個人對應(yīng)多張銀行卡
@Entity
public class Student {
@Id(autoincrement = true)
Long uid;
@Property (nameInDb="name")
String newm;
//這個 uid是對應(yīng)在 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架構(gòu)的解決方案框架,里面包含以下分類
UI 庫 : Animation , Transitions , Emoji , Layout , Palette …
架構(gòu)庫 : Data Binding , ViewModel , Lifecycles , LiveData , Navigation , Padding , Room …
行為庫 : Download Manager , Permissions , Notifications , Sharing …
基礎(chǔ)庫 : AppCompat , Android KTX , Multidex , Test …
5.2 Room使用跟greenDao非常相似,才采用大量注解生成表字段結(jié)構(gòu)。比如@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數(shù)據(jù)庫管理工具類DBHelper,管理AppDatabase
public class DBHelper {
private static AppDatabase appDatabase;
//初始化數(shù)據(jù)庫
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;
}
//關(guān)閉數(shù)據(jù)庫
public static void closeDB() {
if (appDatabase != null && appDatabase.isOpen()) {
appDatabase.close();
}
}
}
5.5 在Application里面初始化Room數(shù)據(jù)庫
public class App extends Application {
private static App app;
@Override
public void onCreate() {
super.onCreate();
if (app == null) {
app = this;
}
//初始化Room數(shù)據(jù)庫
DBHelper.initDB();
}
public static App getInstance() {
return app;
}
}
5.6 上面已經(jīng)建了一個用戶表User,可以再建一個UserDao來管理用戶表的增刪改查操作
以查詢?nèi)坑脩魹槔皇褂胷xjava的寫法
@Dao
public interface UserDao {
//查詢?nèi)坑脩? @Query("SELECT * FROM user")
List<User> getAll();
}
配合rxjava的寫法?,這個Single是rxjava里面的一個監(jiān)聽回調(diào)方法
@Dao
public interface UserDao {
//查詢?nèi)繑?shù)據(jù)
@Query("SELECT * FROM user")
Single<List<User>> getAll();
}
5.7? 完整的增刪改查Rxjava寫法,跟平時用Retrofit+Rxjava差不多?
@Dao
public interface UserDao {
//插入一條或多條用戶數(shù)據(jù)
@Insert
Single<List<Long>> insert(User... users);
//刪除一條數(shù)據(jù)
@Delete
Single<Integer> delete(User user);
//查詢?nèi)繑?shù)據(jù)
@Query("SELECT * FROM user")
Single<List<User>> getAll();
//查詢指定賬戶數(shù)據(jù)
@Query("SELECT * FROM user where account=:account")
Single<List<User>> getOnUser(String account);
//查詢指定id數(shù)據(jù)
@Query("SELECT * FROM user where uid=:uid")
Single<User> getOnUserById(long uid);
}
異步插入一條數(shù)據(jù)?
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的一個線程調(diào)度,執(zhí)行任務(wù)在子線程,返回結(jié)果更新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 會將數(shù)據(jù)庫的架構(gòu)信息導(dǎo)出為 JSON 文件(默認exportSchema = true導(dǎo)出架構(gòu))。要導(dǎo)出架構(gòu),請在 build.gradle 文件中設(shè)置 room.schemaLocation 注釋處理器屬性(設(shè)置將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()]
}
}
}
?方法二:在數(shù)據(jù)庫注解中添加exportSchema = false
@Database(entities = {User.class},version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
六 總結(jié)
6.1?SQLiteOpenHelper原生api相對較少,需要自己寫大量sql語句,開發(fā)維護成本較大。而且執(zhí)行效率速度上沒其它框架快,所有新項目還是以其它框架用的多,SQLiteOpenHelper小項目可以用。
6.2 GreenDao和Room的比較
- GreenDao和Room用法上很類似,都是用了大量注解,比如@Entity,@ID等
- GreenDao提供的api比Room多,GreenDao可以不寫sql完成數(shù)據(jù)庫的造作,但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架構(gòu)圖示對比
GreenDao:
?
Room:文章來源:http://www.zghlxwxcb.cn/news/detail-625490.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-625490.html
到了這里,關(guān)于Android之 常用數(shù)據(jù)庫框架整理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!