編輯:關於Android編程
今天我們來介紹一款性能非常好的orm數據庫框架GreenDao,相信大家一定對它有所耳聞,或者已經在項目中在使用它了,雖然我在去年就開始使用這款框架,但是一直沒有做過系統的整理和梳理,有些地方也是含糊不清,今天就和大家一起來揭開GreenDao的神秘面紗。
GreenDao github地址:https://github.com/greenrobot/greenDAO GreenDao官網地址:http://greenrobot.org/greendao/,包含詳細的使用方式介紹;下面是官網對greendao以及其他常見的orm數據庫的性能測試圖:
vc/QoaOs1bzTw7j8ydm1xMTatOYgo6yy2df3yrXM5cHpu+6jrMv8v8nS1LDv1vpBbmRyb2lkv6q3otXfv+zL2b2rSmF2YbbUz/PTs8nktb1TUUxpdGXK/b7dv+LW0KOszai5/cq508PSu7j2vPK1pbXEw+bP8rbUz/NBUEmjrL+qt6LV37/J0tS21EphdmG21M/zvfjQ0LTmtKKhorj80MKhosm+s/26zbLp0a+hozwvcD4NCjxwPiZuYnNwOzwvcD4NCjxoMiBpZD0="2集成greendao">2.集成greendao
下面我以eclipse開發工具為例講解,至於android studio一句話即可搞定:
compile 'org.greenrobot:greendao:2.2.0'
值得注意的是:【greendao在使用的使用需要兩個工程,一個是java工程,負責生成需要的實體類和數據庫管理類,一個是android工程,執行具體的數據庫操作,後面我們會分別介紹】
一、android工程
新建android工程,指定自己的包名,此處我的包名為com.greendao.use,在com.greendao.use路徑下新建package,com.greendao.use.db.localdb用於存放生成的數據庫文件,此處的包名大家可以隨意指定,但是在java工程中需要指定對應的包路徑,方便引入的時候不會產生包名錯誤;
二、java工程
首先我們新建java工程,在工程根目錄新建libs目錄,把需要的包復制到libs下,這兩個包在文章結尾的源碼裡會有,需要的可以去下載:
此處我們准備在數據庫中添加一個student表,那麼現在我們新建一個java類,並添加如下方法:
/**
* <學生表>
*/
private static void addStudent(Schema schema)
{
// 設置表名,此處的對應android工程中的實體類名稱
Entity student = schema.addEntity("Student");
// 設置表名,此處的對應數據庫中的表名
student.setTableName("t_student");
// 設置主鍵為默認增長的id,也可以使用primaryKey指定任意屬性為主鍵
student.addIdProperty().primaryKey().autoincrement();
// 學號,notNull指定為非空
student.addStringProperty("stuNum").columnName("stu_num").notNull();
// 名字
student.addStringProperty("name").columnName("name");
// 性別
student.addStringProperty("sex").columnName("sex");
// 年齡
student.addStringProperty("age").columnName("age");
// 學分score
student.addStringProperty("score").columnName("score");
// school名稱
student.addStringProperty("school").columnName("school");
}
然後我們在java類的main方法中添加如下代碼:
public static void main(String[] args)
throws IOException, Exception
{
Schema schema = new Schema(1, "com.greendao.use.db.localdb");
addStudent(schema);
new DaoGenerator().generateAll(schema, "./blog");
}
注意:此處的com.greendao.use.db.localdb就是我android工程中用來存放數據庫映射實體類的目錄!blog是我在java工程中新建的一個用於存放生成實體類的目錄:
此時我們運行java類,然後右鍵工程,Refresh一下工程,在blog目錄下就會生成對應的數據庫實體類文件:
—–Student.java類就是對應t_student表的實體類文件,
核心類介紹
DaoMaster:
daomaster以一定的模式持有數據庫對象(SQLiteDatabase)並管理一些DAO類(而不是對象)。
有一個靜態的方法創建和drop數據庫表。它的內部類OpenHelper和DevOpenHelper是SQLiteOpenHelper的實現類,用於創建SQLite數據庫的模式。
DaoSession:
管理指定模式下所有可用的DAO對象,你可以通過某個get方法獲取到。DaoSession提供一些通用的持久化方法,比如對實體進行插入,加載,更新,刷新和刪除。最後DaoSession對象會跟蹤identity scope,更多細節,可以參看 session文檔。
DAOs(Data access objects):
數據訪問對象,用於實體的持久化和查詢。對於每一個實體,greenDao會生成一個DAO,相對於DaoSession它擁有更多持久化的方法。
當然在DaoMaster類中還有一個比較重要的內部類DevOpenHelper,代碼如下:
/** WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
咦,onUpgrade方法,不是處理數據庫升級的嘛,是的,此類就是處理數據庫升級的類,但是注意看上面的警告 WARNING: Drops all table on Upgrade! Use only during development.意思就是如果使用默認生成的代碼進行greedDao的升級,會刪除所有的表之後重新創建,是無法保留老版本數據庫中的數據的,所以實際情況下我們需要自己處理升級邏輯;
下面我們把生成的代碼復制到android工程下
此處我們簡單封裝了一個數據庫操作類DBController,方便進行數據庫操作,代碼都很簡單,主要是獲取DaoSession實例,大家也可以根據自己項目的實際需求封裝一些常用的增刪查改的方法,DBController.java類代碼如下:
/**
* 數據庫控制類
*/
public class DBController
{
private static DaoMaster daoMasterEcmc;
private static DaoSession daoSessionEcmc;
/**
* 數據庫名稱:localdata
*/
public static final String DATABASE_NAME = "localdata.db";
private static DaoMaster obtainMaster(Context context, String dbName)
{
return new DaoMaster(new DaoMaster.DevOpenHelper(context, dbName, null).getWritableDatabase());
}
private static DaoMaster getDaoMaster(Context context, String dbName)
{
if (dbName == null)
return null;
if (daoMasterEcmc == null)
{
daoMasterEcmc = obtainMaster(context, dbName);
}
return daoMasterEcmc;
}
/**
* 取得DaoSession
*
* @return
*/
public static DaoSession getDaoSession(String dbName)
{
if (daoSessionEcmc == null)
{
daoSessionEcmc = getDaoMaster(MainApplication.getIns(), dbName).newSession();
}
return daoSessionEcmc;
}
/**
* 默認操作localdata數據庫
*/
public static DaoSession getDaoSession()
{
if (daoSessionEcmc == null)
{
daoSessionEcmc = getDaoMaster(MainApplication.getIns(), DATABASE_NAME).newSession();
}
return daoSessionEcmc;
}
}
在Android項目中使用
在libs下添加需要greendao庫文件:
下面我們在MainActivity的onCreate中獲取StudentDao實例,一句話:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
然後我們先不進行任何操作,直接運行,然後去DDMS中查看我們的數據庫有沒有生成成功,路徑為data/data/包名/databases下:
我們使用sqllitemanager工具打開localdata.db文件,看看咱們的t_student表有沒有創建成功,可以看到表創建成功:
對應的屬性:
至此,我們的數據庫創建階段已經完成,下面我們將學習一下基本的增刪查改的使用,請各位備好紙巾!
/**
* <插入數據>
*
* @see [類、類#方法、類#成員]
*/
private void addData()
{
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
//新建一個Student對象就相當於一條數據庫的記錄
Student student = new Student();
student.setStuNum("1001");
student.setName("劉德華");
student.setAge("22");
student.setSex("男");
student.setScore("3");
student.setSchool("清華大學");
//插入到數據庫
studentDao.insert(student);
Student student1 = new Student();
student1.setStuNum("1002");
student1.setName("劉亦菲");
student1.setAge("26");
student1.setSex("女");
student1.setScore("5");
student1.setSchool("北京大學");
// 開啟事務插入
studentDao.insertInTx(student1);
Student student2 = new Student();
student2.setStuNum("1003");
student2.setName("黃渤");
student2.setAge("30");
student2.setSex("男");
student2.setScore("12");
student2.setSchool("南京大學");
// 插入,如果存在覆蓋之前的記錄
studentDao.insertOrReplace(student2);
}
打開db文件看下有麼有插入成功:
OK,成功!
至於插入操作,greendao還提供了其他的插入方法,比如批量插入等,大家可以自己去嘗試使用下,以便做出更好的選擇:
查詢操作1.查詢所有數據庫所有記錄:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
//list()方法查詢所有記錄
List students = studentDao.queryBuilder().list();
2.查詢指定條件(此處為性別為男的記錄)的記錄:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
List students = studentDao.queryBuilder().where(StudentDao.Properties.Sex.eq("男")).list();
3.使用sql語句進行查詢:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
List students = studentDao.queryRaw("where name = ?", "劉德華");
我們再插入兩條數據:
4.limit用法是取出查詢記錄的N條:
//查詢前四條limit(4)
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
List students = studentDao.queryBuilder().limit(4).list();
4.offset是設置偏移量,下面是從第二個開始,查詢三條數據:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
List students = studentDao.queryBuilder().limit(3).offset(1).list();
5.orderAsc是對查詢的數據進行升序排序,orderDesc是降序排序,此處根據年齡進行升序排序:
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
List students = studentDao.queryBuilder().orderAsc(StudentDao.Properties.Age).list();
關於greendao的查詢功能,除了上述查詢之外,還有一些其他的功能,大家可以自行嘗試:
修改操作
//把劉德華修改成周星馳,如果有多個,此處只修改第一個
List students = studentDao.queryBuilder().where(StudentDao.Properties.Name.eq("劉德華")).list();
Student entity = students.get(0);
entity.setName("周星馳");
studentDao.update(entity);
其他的更新方法:
刪除操作
//刪除周星馳的第一條記錄
StudentDao studentDao = DBController.getDaoSession().getStudentDao();
QueryBuilder builder = studentDao.queryBuilder().where(StudentDao.Properties.Name.eq("周星馳"));
List students = builder.list();
studentDao.delete(students.get(0));
其他的刪除方法:
升級沒有什麼好說的,就像前面講到的那樣,現在描述一下基本流程,比如我們添加個表或者修改某些字段,之後需要提高數據庫版本,當執行程序的時候一旦發現新版本大於老版本,就會執行數據庫更新操作,執行onUpgrade方法,我們的就在此處處理升級邏輯;
比如如果我們要給t_stduent表添加個字段的話,就可以這樣來寫:
public void onUpgrade(SQLiteDatabase db) {
db.execSQL("ALTER TABLE 't_student' ADD favorite TEXT");
}
運行查看數據表:
添加一張t_school表,我們可以這樣寫:
db.execSQL("CREATE TABLE 't_school' ('_id' INTEGER PRIMARY KEY AUTOINCREMENT ,'name' TEXT,'address' TEXT)");
查看數據庫,添加成功:
雖然這樣可以添加成功,別忘記使用java工程生成對應的實體類和Dao類等數據庫操作類,不然是無法操作數據表的;寫到這,大家說,麻煩死了,還得寫sql語句,復雜的話又比較容易出問題,所以下面推薦一種好的方式來進行更新(代碼來自:Pedro Okawa):
首先創建一個MyMigrationHelper數據庫更新的工具類,具體代碼如下:
/**
*
* please call {@link #migrate(SQLiteDatabase, Class[])}
*
*/
public final class MyMigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MyMigrationHelper instance;
public static MyMigrationHelper getInstance() {
if(instance == null) {
instance = new MyMigrationHelper();
}
return instance;
}
public void migrate(SQLiteDatabase db, Class>... daoClasses) {
//創建臨時表保存數據
generateTempTables(db, daoClasses);
//刪除所有
DaoMaster.dropAllTables(db, true);
//創建所有
DaoMaster.createAllTables(db, false);
//恢復數據,刪除臨時表
restoreData(db, daoClasses);
}
private void generateTempTables(SQLiteDatabase db, Class>... daoClasses) {
for(int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for(int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if(getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
// Crashlytics.logException(exception);
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if(daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private void restoreData(SQLiteDatabase db, Class>... daoClasses) {
for(int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if(getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class type) throws Exception {
if(type.equals(String.class)) {
return "TEXT";
}
if(type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
}
if(type.equals(Boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
// Crashlytics.logException(exception);
throw exception;
}
private static List getColumns(SQLiteDatabase db, String tableName) {
List columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
使用時我們只需要在onUpgrade方法中調用migrate方法指定數據庫中所有的Dao-class即可:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//注意:class只需要添加已經存在的表,新增的表不需要添加
MyMigrationHelper.getInstance().migrate(db,StudentDao.class,SchoolDao.class);
}
我們現在添加一個t_teacher表,提高數據庫版本,把生成的代碼復制到android 工程,運行工程,執行後就會發現數據庫裡t_teacher表已經添加成功了。
而且比較重要的是原來stduent表中的信息依然被保留了下來:
只需簡單的一句話即可完成數據庫的升級操作;
總結:至此,關於greenDao的基本使用到這裡已經完成了,本篇博文主要是記錄了數據庫的基本使用 ,都是對單表的一些基本操作,如果你仔細看了這篇博文,相信會對你有所幫助,如果你有任何問題,歡迎下方評論討論,關於數據表的關聯關系等操作,下篇會重點介紹;
源碼下載:博文工程源碼,需要jar包的也可以下載
android軟件 可以查詢動車余票 [1].[圖片] 1.jpg 跳至 [1] [2] [3] [4] [5] [2].[圖片] 2.jpg 跳至 [1
引言最近在研究Android的變形,Android的2D變形(包括縮放,扭曲,平移,旋轉等)可以通過Matrix來實現,3D變形可以通過Camera來實現。接下來就將我這
spinner組件有點類型於HTML中的下拉框<Select></select>的樣子,讓用戶每次從下拉框中選取一個,本文為大家分享了Androi
一、前言現在主流的加固平台有:梆梆加固,愛加密,360加固,騰訊加固,在之前的一篇文章中介紹了:如何脫掉“愛加密”的殼,現在這裡要脫掉另外一個平台