Markdown版本筆記 | 我的GitHub首頁 | 我的博客 | 我的微信 | 我的郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
ORM數據庫框架 SQLite ORMLite
目錄
目錄
簡介
注解
@DatabaseTable
@DatabaseField
@ForeignCollectionField
常用API
添加數據
刪除數據
更新數據
查詢數據
Builder
事物管理
完整案例
SqliteOpenHelper
User
測試代碼
簡介
注解
@DatabaseTable
@DatabaseField
@ForeignCollectionField
常用API
添加數據
刪除數據
更新數據
查詢數據
Builder
事物管理
完整案例
SqliteOpenHelper
User
測試代碼
簡介
Android中現在最常見、最常用的SQLite數據庫框架是ORMLite和GreenDAO
,相比GreenDAO來說,ORMLite是一個更加輕量級
的框架,而且學習成本更低。
Gradle配置:
implementation 'com.j256.ormlite:ormlite-core:4.48' //核心包,不知道什么原因,新版本5.0和5.1用不了
implementation 'com.j256.ormlite:ormlite-android:4.48' //Android端專用
也可以手動下載並添加 ormlite-core
包,根據需要添加 ormlite-jdbc
包(服務器端使用)或 ormlite-android
包(Android端使用)。
注解
@DatabaseTable
標記要存儲在數據庫中的類
的注解。僅在您要標記類[mark the class]或更改其默認tableName
時才需要使用它。您可以在要保留到數據庫的類上方指定此注解。
需要持久化的類必須具有至少包級可見
[package visibility]的無參數構造函數
,以便在執行查詢時可以創建此類的對象。
此注解的定義:
@Target(TYPE)
@Retention(RUNTIME)
public @interface DatabaseTable {
String tableName() default ""; //數據庫中表的名稱。如果未設置,則名稱為類名的小寫形似。
Class<?> daoClass() default Void.class; //與此類對應的DAO類。DaoManager 在內部構造DAO時使用它。
}
@DatabaseField
用於標識一個類中與數據庫中的列
對應、且將被持久化的字段
。
瞬態[transient]字段或其他臨時[temporary]字段不應被持久化。
此注解的定義:
@Target(FIELD)
@Retention(RUNTIME)
public @interface DatabaseField {
public static final String DEFAULT_STRING = "__ormlite__ no default value string was specified";
public static final int NO_MAX_FOREIGN_AUTO_REFRESH_LEVEL_SPECIFIED = -1;
public static final int DEFAULT_MAX_FOREIGN_AUTO_REFRESH_LEVEL = 2;
String columnName() default ""; //數據庫中列的名稱。如果未設置,則從字段名稱中獲取名稱
DataType dataType() default DataType.UNKNOWN; //
String defaultValue() default DEFAULT_STRING; //用於創建表的字段的默認值
int width() default 0; //
boolean canBeNull() default true; //是否可以為空
boolean id() default false; //當前字段是不是id字段,一個實體類中只能設置一個id字段
boolean generatedId() default false; //是否自增長,id、generatedId、generatedIdSequence 只能指定一個
String generatedIdSequence() default ""; //
boolean foreign() default false; //當前字段是否是外鍵
boolean useGetSet() default false; //是否使用Getter/Setter方法來訪問這個字段
String unknownEnumName() default ""; // //
boolean throwIfNull() default false; //
boolean persisted() default true; //
String format() default ""; //
boolean unique() default false; //是否唯一
boolean uniqueCombo() default false; //
boolean index() default false; //將此設置為true以使數據庫為此字段添加索引。這將創建一個名為 columnName + "_ idx" 的索引
boolean uniqueIndex() default false; //
String indexName() default ""; //給此值設置為一個字符串可使數據庫使用此名稱為此字段添加索引
String uniqueIndexName() default ""; //
boolean foreignAutoRefresh() default false; //如果設置為true,在關聯查詢的時候就不需要再調用refresh()了
int maxForeignAutoRefreshLevel() default NO_MAX_FOREIGN_AUTO_REFRESH_LEVEL_SPECIFIED; //
Class<? extends DataPersister> persisterClass() default VoidType.class; //
boolean allowGeneratedIdInsert() default false; //
String columnDefinition() default ""; //
boolean foreignAutoCreate() default false; //
boolean version() default false; //
String foreignColumnName() default ""; //外鍵約束指向的類中的屬性名
boolean readOnly() default false; //
}
以上那么多字段基本都沒用過,也基本用不到
@ForeignCollectionField
一對多關聯,表示一個UserBean關聯着多個ArticleBean(必須使用ForeignCollection集合)
此注解的定義:
@Target(FIELD)
@Retention(RUNTIME)
public @interface ForeignCollectionField {
public static final int MAX_EAGER_LEVEL = 1;
boolean eager() default false;
@Deprecated
int maxEagerForeignCollectionLevel() default MAX_EAGER_LEVEL;
int maxEagerLevel() default MAX_EAGER_LEVEL;
String columnName() default "";
String orderColumnName() default "";
boolean orderAscending() default true;
@Deprecated
String foreignColumnName() default "";
String foreignFieldName() default "";
}
常用API
添加數據
int create(T t) throws SQLException;
int create(Collection<T> var1) throws SQLException;
T createIfNotExists(T t) throws SQLException;
刪除數據
int delete(T t) throws SQLException;
int deleteById(Intenger id) throws SQLException;
int delete(Collection<T> var1) throws SQLException;
int deleteIds(Collection<Intenger> ids) throws SQLException;
更新數據
int update(T var1) throws SQLException;
int updateId(T var1, ID var2) throws SQLException;
查詢數據
T queryForId(ID var1) throws SQLException;
List<T> queryForAll() throws SQLException;
Builder
DAO 中提供了幾個相關的 Builder 方法,可以進行按條件操作,使用方式相似:
QueryBuilder<T, ID> queryBuilder();
UpdateBuilder<T, ID> updateBuilder();
DeleteBuilder<T, ID> deleteBuilder();
QueryBuilder對象常用方法
QueryBuilder<User, Integer> builder = userDao.queryBuilder()
.distinct()// 排重
.groupBy("id") //分組
.limit(10L)//限制數量
.offset(3L) //偏移
.orderBy("date", true); //排序
List<User> list = builder.where().like("string", "%包青天%").query();//條件查詢
事物管理
DatabaseConnection dc = userDao.startThreadConnection();//也可以 new AndroidDatabaseConnection
dc.setAutoCommit(false); //設置不自動提交
Savepoint savePoint = dc.setSavePoint("savePointName");//設置回滾點,參數是一個名字,沒什么影響
for (User user : new User[]{user, user}) {
userDao.createOrUpdate(user);
}
dc.commit(savePoint);//提交事務。保存大量數據時以事務的方式提交,可以大幅提高速度
userDao.endThreadConnection(dc);
完整案例
SqliteOpenHelper
public class DbHelper extends OrmLiteSqliteOpenHelper {
private static final String TABLE_NAME = "sqlite-test.db";
private static final int DATABASE_VERSION = 1;
private Dao<User, Integer> userDao = null;
private RuntimeExceptionDao<User, Integer> userRuntimeDao;
public DbHelper(Context context) {
super(context, TABLE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
Log.i("bqt", "onCreate,版本:" + DATABASE_VERSION);
TableUtils.createTable(connectionSource, User.class);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
try {
Log.i("bqt", "onUpgrade,舊版本:" + oldVersion + ",新版本:" + newVersion);
TableUtils.dropTable(connectionSource, User.class, true);//刪除舊版本
onCreate(database, connectionSource);//創建新版本
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void close() {
super.close();
userDao = null;
}
public Dao<User, Integer> getUserDao() throws SQLException {
return userDao == null ? getDao(User.class) : userDao;
}
public RuntimeExceptionDao<User, Integer> getUserRuntimeDao() {
return userRuntimeDao == null ? getRuntimeExceptionDao(User.class) : userRuntimeDao;
}
}
User
public class User {
@DatabaseField(generatedId = true) public int id;
@DatabaseField(index = true) public String string;
@DatabaseField public Date date;
public User() { //必須具有至少包機可見的無參數構造函數,以便在執行查詢時可以創建此類的對象
}
//...
}
測試代碼
public class ORMLiteActivity extends ListActivity {
private DbHelper helper;
private Dao<User, Integer> userDao;
private RuntimeExceptionDao<User, Integer> userRuntimeDao;
private User user;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = {"0、添加:create",
"1、添加:createIfNotExists",
"2、添加:createOrUpdate",
"3、事務操作:使用DatabaseConnection",
"4、事務操作:使用AndroidDatabaseConnection",
"5、更新:update、updateId",
"6、刪除:delete、deleteIds、deleteById",
"7、QueryBuilder、UpdateBuilder、DeleteBuilder",
"8、其他API",
"9、查詢並清除所有數據:queryForAll",};
setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, Arrays.asList(array)));
user = User.newBuilder().date(new Date()).date(new Date()).string("====包青天====").build();
try {
helper = new DbHelper(this);
userDao = helper.getUserDao();
userRuntimeDao = helper.getUserRuntimeDao();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
helper.close();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
user.string = "【包青天" + id + "】" + System.currentTimeMillis();
try {
switch (position) {
case 0:
int updatNum1 = userDao.create(user);
boolean isEqual1 = userDao.objectsEqual(user, userDao.queryForId(1));
int updatNum2 = userDao.create(user);//[注意]對於同一個對象,不管是否存在,每次就會添加一條新的數據
boolean isEqual2 = userDao.objectsEqual(user, userDao.queryForId(1));
boolean isEqual3 = userDao.objectsEqual(user, userDao.queryForId(2));
Log.i("bqt", "是否為同一對象:" + Arrays.asList(isEqual1, isEqual2, isEqual3));//[true, false, true]
int updatNum3 = userDao.create(User.newBuilder().id(100).string("包青天0").build());//[注意]設置id無效
Log.i("bqt", "更新數量:" + Arrays.asList(updatNum1, updatNum2, updatNum3));//[1, 1, 1]
break;
case 1://如果指定的對象不存在則插入,如果存在則不插入
User newUser1 = userDao.createIfNotExists(user);//[垃圾]上面添加了多個,但這里只返回了最后一個
//[注意]因為user已經存在,所以不會添加,也不更新數據庫中對象的數據;並且返回的是數據庫中的對象(舊的數據)
boolean isEqual11 = userDao.objectsEqual(newUser1, user);
boolean isEqual12 = userDao.objectsEqual(newUser1, userDao.queryForId(2));
Log.i("bqt", "是否為同一對象:" + Arrays.asList(isEqual11, isEqual12));//[false, true]
User newUser2 = userDao.createIfNotExists(User.newBuilder().string("包青天1").build());
Log.i("bqt", new Gson().toJson(Arrays.asList(newUser1, newUser2)));
break;
case 2:
Dao.CreateOrUpdateStatus status1 = userDao.createOrUpdate(user);//[注意]上面添加了多個,但這里只更改了最后一個
Log.i("bqt", "是否為同一對象:" + userDao.objectsEqual(user, userDao.queryForId(2)));//true
Dao.CreateOrUpdateStatus status2 = userDao.createOrUpdate(User.newBuilder().string("包青天2").build());
//[{"created":false,"numLinesChanged":1,"updated":true},{"created":true,"numLinesChanged":1,"updated":false}]
Log.i("bqt", new Gson().toJson(Arrays.asList(status1, status2)));
break;
case 3://使用DatabaseConnection
DatabaseConnection dc = userDao.startThreadConnection();//也可以 new AndroidDatabaseConnection
dc.setAutoCommit(false); //設置不自動提交
Savepoint savePoint = dc.setSavePoint("savePointName");//設置回滾點,參數是一個名字,沒什么影響
for (User user : new User[]{user, user}) {
userDao.createOrUpdate(user);
}
dc.commit(savePoint);//提交事務。保存大量數據時以事務的方式提交,可以大幅提高速度
userDao.endThreadConnection(dc);
break;
case 4://使用AndroidDatabaseConnection
AndroidDatabaseConnection adc = new AndroidDatabaseConnection(helper.getWritableDatabase(), true);
userRuntimeDao.setAutoCommit(adc, false);// 設置不自動提交
Savepoint savePoint4 = adc.setSavePoint("savePointName");//設置回滾點,參數是一個名字,沒什么影響
for (User user : new User[]{user, User.newBuilder().string("包青天4").build()}) {
userDao.createOrUpdate(user);
}
adc.commit(savePoint4);
adc.rollback(savePoint4); // 回滾事物。一般用於在發生異常時進行回滾
break;
case 5:
int uNum1 = userDao.update(user);//[注意]同樣更新的是最后添加的數據
int uNum2 = userDao.update(User.newBuilder().build());
int uNum3 = userDao.updateId(user, 100);//[注意]新添加的數據的id將從最大值開始
int uNum4 = userDao.updateId(userDao.queryForId(3), -100);//[注意]值可以為負值
Log.i("bqt", new Gson().toJson(Arrays.asList(uNum1, uNum2, uNum3, uNum4)));//[1,0,1,1]
break;
case 6:
int dNum1 = userDao.delete(user);//[注意]這個刪掉的也是最后一個添加的數據,前面添加的數據已經和user脫離關聯了
int dNum2 = userDao.delete(user);
int dNum3 = userDao.delete(Arrays.asList(user, User.newBuilder().build()));
int dNum4 = userDao.deleteById(3);
int dNum5 = userDao.deleteIds(Arrays.asList(5, 6, 7, 8));
Log.i("bqt", new Gson().toJson(Arrays.asList(dNum1, dNum2, dNum3, dNum4, dNum5)));//[1,0,0,1,1]
break;
case 7:
QueryBuilder<User, Integer> builder = userDao.queryBuilder()
.distinct()// 排重
.groupBy("id") //分組
.limit(10L)//限制數量
.offset(3L) //偏移
.orderBy("date", true); //排序
List<User> list = builder.where().like("string", "%包青天%").query();//條件查詢
Log.i("bqt", "查詢到的數據:" + new Gson().toJson(list));
break;
case 8:
User data = userDao.queryForId(1);//如果不存在則返回 null
long count = userDao.countOf();//總數量
Log.i("bqt", count + " " + new Gson().toJson(data));
Log.i("bqt", userDao.isTableExists() + " " + userDao.isUpdatable() + " " + userDao.idExists(1));
case 9:
userDao.delete(userDao.queryForAll());
break;
}
Log.i("bqt", "全部數據:" + new Gson().toJson(userDao.queryForAll()));
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2018-8-16