日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

一篇好文之Android数据库 GreenDao的完全解析

發布時間:2024/10/12 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一篇好文之Android数据库 GreenDao的完全解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
數據庫GreenDao.jpg

之前在開發過程中,數據庫基本上會使用Litepal或者SQlite自己寫,最近換新環境,公司原先使用的數據庫就是GreenDao,在各種情況的作用下,準備了解下GreenDao,順便寫一篇文章記錄下GreenDao的基本使用!


Android開發者聚集地

本文主要從如下幾個方面進行講解

  • 存儲的數據庫結構
  • GreenDao的優缺點
  • GreenDao的使用配置
  • 使用GreenDao實現數據的增刪改查
  • GreenDao的注解使用
  • GreenDao的關系處理
  • GreenDao的升級
  • GreenDao數據庫加密
  • 項目地址AserbaosAndroid
  • 總結
  • 參考博客
    簡書暫時不支持目錄,如果想看該文章帶目錄版本,請點擊跳轉該文章的CSDN地址
  • 咱們先看一波最終的效果圖:文章最后有項目地址;

    greendao

    1. 存儲的數據庫結構

    學習數據庫之前,我們先得設計自己的數據庫,不多廢話,下面是我此次學習的數據庫結構,后面所有的數據請參考這個圖進行學習:


    GreenDao關系圖.jpg

    2. GreenDao的介紹

    簡單的GreenDao的介紹,閑麻煩的可以直接跳到GreenDao使用開始看。

    什么是GreenDao?

    GreenDAO是一個開源的Android ORM(“對象/關系映射”),通過ORM(稱為“對象/關系映射”),在我們數據庫開發過程中節省了開發時間!


    GreenDao的原理.png

    GreenDao的官方文檔

  • GreenDao:適用于您的SQLite數據庫的Android ORM
  • GreenDao的github地址
  • GreenDao的Google討論區
  • GreenDao 加密SQLCipher for Android官方說明地址
  • GreenDao使用文檔
  • GreenDao的作用?

    通過GreenDao,我們可以更快速的操作數據庫,我們可以使用簡單的面相對象的API來存儲,更新,刪除和查詢Java對象。

    GreenDao的優缺點?

  • 高性能,下面是官方給出的關于GreenDao,OrmLite和ActiveAndroid三種ORM解決方案的數據統計圖:


    GreenDao性能對比圖.png
  • 易于使用的強大API,涵蓋關系和連接;

  • 最小的內存消耗;

  • 小庫大小(<100KB)以保持較低的構建時間并避免65k方法限制;

  • 數據庫加密:greenDAO支持SQLCipher,以確保用戶的數據安全;

  • 3. GreenDao的使用

    GreenDao的核心類有三個:分別是DaoMaster,DaoSession,XXXDao,這三個類都會自動創建,無需自己編寫創建!

    • DaoMaster::DaoMaster保存數據庫對象(SQLiteDatabase)并管理特定模式的DAO類(而不是對象)。它有靜態方法來創建表或刪除它們。它的內部類OpenHelper和DevOpenHelper是SQLiteOpenHelper實現,它們在SQLite數據庫中創建模式。
    • DaoSession:管理特定模式的所有可用DAO對象,您可以使用其中一個getter方法獲取該對象。DaoSession還提供了一些通用的持久性方法,如實體的插入,加載,更新,刷新和刪除。
    • XXXDao:數據訪問對象(DAO)持久存在并查詢實體。對于每個實體,greenDAO生成DAO。它具有比DaoSession更多的持久性方法,例如:count,loadAll和insertInTx。
    • Entities :可持久化對象。通常, 實體對象代表一個數據庫行使用標準 Java 屬性(如一個POJO 或 JavaBean )。


      GreenDao核心.png

    1. 導入Gradle插件和Dao代碼生成

    要在Android項目中使用GreenDao,您需要添加GreenDao Gradle插件并添加GreenDao庫:

  • 導入插件
  • // 在 Project的build.gradle 文件中添加: buildscript {repositories {jcenter()mavenCentral() // add repository}dependencies {classpath 'com.android.tools.build:gradle:3.1.2'classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin } }
  • 配置相關依賴
  • // 在 Moudle:app的 build.gradle 文件中添加: apply plugin: 'com.android.application' apply plugin: 'org.greenrobot.greendao' // apply plugin dependencies { implementation 'org.greenrobot:greendao:3.2.2' // add library }
  • 配置數據庫相關信息
  • greendao {schemaVersion 1 //數據庫版本號daoPackage 'com.aserbao.aserbaosandroid.functions.database.greenDao.db' // 設置DaoMaster、DaoSession、Dao 包名 targetGenDir 'src/main/java'//設置DaoMaster、DaoSession、Dao目錄 generateTests false //設置為true以自動生成單元測試。 targetGenDirTests 'src/main/java' //應存儲生成的單元測試的基本目錄。默認為 src / androidTest / java。 }

    配置完成,在Android Studio中使用Build> Make Project,重寫build項目,GreenDao集成完成!

    2. 創建存儲對象實體類

    使用GreenDao存儲數據只需要在存儲數據類前面聲明@Entity注解就讓GreenDao為其生成必要的代碼:

    @Entity public class Student {@Id(autoincrement = true) Long id; @Unique int studentNo;//學號 int age; //年齡 String telPhone;//手機號 String sex; //性別 String name;//姓名 String address;//家庭住址 String schoolName;//學校名字 String grade;//幾年級 ……getter and setter and constructor method…… }

    3. GreenDao初始化

    我們可以在Application中維持一個全局的會話。我們在Applicaiton進行數據庫的初始化操作:

    /*** 初始化GreenDao,直接在Application中進行初始化操作*/private void initGreenDao() { DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "aserbao.db"); SQLiteDatabase db = helper.getWritableDatabase(); DaoMaster daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession(); } private DaoSession daoSession; public DaoSession getDaoSession() { return daoSession; }

    初始化完成之后重新rebuild一下項目會發現在設置的targetGenDir的目錄生成三個類文件,這個是GreenDao自動生成的!說明數據庫已經連接好了,咱們接下來只需要進行數據庫的增刪改查操作就行了。Let's Go!

    4. 使用GreenDao實現增刪改查

    1. 增

    insert() 插入數據

    @Overridepublic void insertData(Thing s) { DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); for (int i = 0; i < 1000; i++) { Student student = new Student(); student.setStudentNo(i); int age = mRandom.nextInt(10) + 10; student.setAge(age); student.setTelPhone(RandomValue.getTel()); String chineseName = RandomValue.getChineseName(); student.setName(chineseName); if (i % 2 == 0) { student.setSex("男"); } else { student.setSex("女"); } student.setAddress(RandomValue.getRoad()); student.setGrade(String.valueOf(age % 10) + "年紀"); student.setSchoolName(RandomValue.getSchoolName()); daoSession.insert(student); } }

    insertOrReplace()數據存在則替換,數據不存在則插入

    @Overridepublic void insertData(Thing s) { DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); for (int i = 0; i < 1000; i++) { Student student = new Student(); student.setStudentNo(i); int age = mRandom.nextInt(10) + 10; student.setAge(age); student.setTelPhone(RandomValue.getTel()); String chineseName = RandomValue.getChineseName(); student.setName(chineseName); if (i % 2 == 0) { student.setSex("男"); } else { student.setSex("女"); } student.setAddress(RandomValue.getRoad()); student.setGrade(String.valueOf(age % 10) + "年紀"); student.setSchoolName(RandomValue.getSchoolName()); daoSession.insertOrReplace(student);//插入或替換 } }

    2. 刪

    刪除有兩種方式:delete()和deleteAll();分別表示刪除單個和刪除所有。

    @Overridepublic void deleteData(Student s) { DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); daoSession.delete(s); } @Overridepublic void deleteAll() { DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); daoSession.deleteAll(Student.class); }

    3. 改

    通過update來進行修改:

    @Overridepublic void updataData(Student s) { DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); daoSession.update(s); }

    4. 查

    查詢的方法有:

    • loadAll():查詢所有數據。
    • queryRaw():根據條件查詢。
    • queryBuilder() : 方便查詢的創建,后面詳細講解。
    public List queryAll(){List<Student> students = daoSession.loadAll(Student.class);return students; } @Overridepublic void queryData(String s) { List<Student> students = daoSession.queryRaw(Student.class, " where id = ?", s); mDataBaseAdapter.addNewStudentData(students); }

    4. QueryBuilder的使用

    編寫SQL可能很困難并且容易出現錯誤,這些錯誤僅在運行時才會被注意到。該QueryBuilder的類可以讓你建立你的實體,而不SQL自定義查詢,并有助于在編譯時已檢測錯誤。

    我們先講下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 ()讓我們通過按需加載數據(懶惰)來迭代結果。數據未緩存。必須關閉。

    GreenDao中SQL語句的縮寫,我們也了解下,源碼在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" 不為空;

    1. 使用QueryBuilder進行查詢操作

    1. 簡單條件查詢

    查詢當前Student表的所有的數據:

    public List queryAllList(){DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();QueryBuilder<Student> qb = daoSession.queryBuilder(Student.class);List<Student> list = qb.list(); // 查出所有的數據 return list; }

    查詢Name為“一”的所有Student:

    public List queryListByMessage(String name){DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();QueryBuilder<Student> qb = daoSession.queryBuilder(Student.class);QueryBuilder<Student> studentQueryBuilder = qb.where(StudentDao.Properties.Name.eq("一")).orderAsc(StudentDao.Properties.Name);List<Student> studentList = studentQueryBuilder.list(); //查出當前對應的數據 return list; }

    2. 原始查詢

    通過原始的SQL查詢語句進行查詢!其實上面有提到QueryBuilder的目的就是方便快捷的編寫SQL查詢語句,避免我們自己在編寫過程中出錯!簡單介紹下通過QueryBuilder編寫數據庫,方式方法如下 :

    public List queryListBySqL(){ // 查詢ID大于5的所有學生DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();Query<Student> query = daoSession.queryBuilder(Student.class).where(new WhereCondition.StringCondition("_ID IN " + "(SELECT _ID FROM STUDENT WHERE _ID > 5)") ).build(); List<Student> list = query.list(); return list; }

    3. 嵌套條件查詢

    查詢Id大于5小于10,且Name值為"一"的數據:

    public List queryList(){DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();QueryBuilder<Student> qb = daoSession.queryBuilder(Student.class);qb = daoSession.queryBuilder(Student.class);List<Student> list2 = qb.where(StudentDao.Properties.Name.eq("一"), qb.and(StudentDao.Properties.Id.gt(5), StudentDao.Properties.Id.le(50))).list(); return list2; }

    取10條Id大于1的數據,且偏移2條

    public List queryListByOther(){DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();QueryBuilder<Student> qb = daoSession.queryBuilder(Student.class);//搜索條件為Id值大于1,即結果為[2,3,4,5,6,7,8,9,10,11];// offset(2)表示往后偏移2個,結果為[4,5,6,7,8,9,10,11,12,13]; List<Student> list = qb.where(StudentDao.Properties.Id.gt(1)).limit(10).offset(2).list(); return list; }

    4. 多次執行查找

    使用QueryBuilder構建查詢后,可以重用 Query對象以便稍后執行查詢。這比始終創建新的Query對象更有效。如果查詢參數沒有更改,您可以再次調用list / unique方法。可以通過setParameter方法來修改條件參數值:

    public List queryListByMoreTime(){DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession();QueryBuilder<Student> qb = daoSession.queryBuilder(Student.class);//搜索條件為Id值大于1,即結果為[2,3,4,5,6,7,8,9,10,11];// offset(2)表示往后偏移2個,結果為[4,5,6,7,8,9,10,11,12,13]; Query<Student> query = qb.where(StudentDao.Properties.Id.gt(1)).limit(10).offset(2).build(); List<Student> list = query.list(); //通過SetParameter來修改上面的查詢條件,比如我們將上面條件修改取10條Id值大于5,往后偏移兩位的數據,方法如下! query.setParameter(0,5); List<Student> list1 = query.list(); return list1; }

    5. 在多個線程中使用QueryBuilder

    如果在多個線程中使用查詢,則必須調用 forCurrentThread ()以獲取當前線程的Query實例。Query的對象實例綁定到構建查詢的擁有線程。

    這使您可以安全地在Query對象上設置參數,而其他線程不會干擾。如果其他線程嘗試在查詢上設置參數或執行綁定到另一個線程的查詢,則會拋出異常。像這樣,您不需要同步語句。實際上,您應該避免鎖定,因為如果并發事務使用相同的Query對象,這可能會導致死鎖。

    每次調用forCurrentThread ()時, 參數都會在使用其構建器構建查詢時設置為初始參數。

    2. 使用QueryBuilder進行批量刪除操作

    使用QueryBuilder進行批量刪除操作,不會刪除單個實體,但會刪除符合某些條件的所有實體。要執行批量刪除,請創建QueryBuilder,調用其 buildDelete ()方法,然后執行返回的 DeleteQuery。

    例子:刪除數據庫中id大于5的所有其他數據

    public boolean deleteItem(){ DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); QueryBuilder<Student> where = daoSession.queryBuilder(Student.class).where(StudentDao.Properties.Id.gt(5)); DeleteQuery<Student> deleteQuery = where.buildDelete(); deleteQuery.executeDeleteWithoutDetachingEntities(); return false; }

    5. 注解講解

    從GreenDao 3 使用注解來定義模型和實體,前面也講過,通過注解的使用可以快速構建數據庫表,包括設置主鍵,自增,值是否唯一等等等……

    下面我們來看下注解的簡單使用:

    @Entity public class Student {@Id(autoincrement = true) Long id; @Unique int studentNo;//學號 int age; //年齡 String telPhone;//手機號 String sex; //性別 String name;//姓名 String address;//家庭住址 String schoolName;//學校名字 String grade;//幾年級 ……getter and setter and constructor method…… }

    1. @Entity注解

    @Entity是GreenDao必不可少的注解,只有在實體類中使用了@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 Student{ …… }

    2. 基礎屬性注解(@Id,@Property,@NotNull,@Transient)

    @Id
    @Id注解選擇 long / Long屬性作為實體ID。在數據庫方面,它是主鍵。參數autoincrement = true 表示自增,id不給賦值或者為賦值為null即可(這里需要注意,如果要實現自增,id必須是Long,為long不行!)。

    @Entity public class Student { @Id(autoincrement = true) Long id; …… }

    @Property
    允許您定義屬性映射到的非默認列名。如果不存在,GreenDAO將以SQL-ish方式使用字段名稱(大寫,下劃線而不是camel情況,例如 name將成為 NAME)。注意:您當前只能使用內聯常量來指定列名。

    @Entity public class Student {@Id(autoincrement = true)Long id;@Property (nameInDb="name") //設置了,數據庫中的表格屬性名為"name",如果不設置,數據庫中表格屬性名為"NAME" String name; …… }

    @NotNull :設置數據庫表當前列不能為空 。

    @Transient :添加次標記之后不會生成數據庫表的列。標記要從持久性中排除的屬性。將它們用于臨時狀態等。或者,您也可以使用Java中的transient關鍵字。

    3. 索引注解

    • @Index:使用@Index作為一個屬性來創建一個索引,通過name設置索引別名,也可以通過unique給索引添加約束。
    • @Unique:向索引添加UNIQUE約束,強制所有值都是唯一的。
    @Entity public class Student { @Id(autoincrement = true) Long id; @Property(nameInDb="name") @Index(unique = true) String name; …… }

    注意: 上面這種情況,約定name為唯一值,向數據庫中通過insert方法繼續添加已存在的name數據,會拋異常:

    10-08 20:59:46.274 31939-31939/com.example.aserbao.aserbaosandroid E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.aserbao.aserbaosandroid, PID: 31939 android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: STUDENT.name (Sqlite code 2067), (OS error - 2:No such file or directory) ……

    若使用insertOrReplace()方法添加數據,當前數據庫中不會有重復的數據,但是重復的這條數據的id會被修改!若項目中有用到id字段進行排序的話,這一點需要特別注意。

    4. 關系注解

    關系型注解GreenDao中主要就兩個:

    • @ToOne:定義與另一個實體(一個實體對象)的關系
    • @ToMany:定義與多個實體對象的關系
      至于如何使用,我們馬上就講。

    6. 一對一,一對多,多對多關系表的創建

    平常項目中,我們經常會使用到多表關聯,如文章開頭所說的數據庫表結構設置的那樣!接下來我們來講如何通過GreenDao實現多表關聯。

    1. 一對一

    一個學生對應一個身份證號:
    做法:

  • 我們在Student中設置一個注解@ToOne(joinProperty = "name")
  • 在創建Student的時候,將對應的數據傳遞給IdCard;
    代碼部分:
  • 學生Student代碼:

    @Entity public class Student { @Id(autoincrement = true) Long id; @Unique int studentNo;//學號 int age; //年齡 String telPhone;//手機號 String sex; //性別 String name;//姓名 String address;//家庭住址 String schoolName;//學校名字 String grade;//幾年級 @ToOne(joinProperty = "name") IdCard student; ……getter and setter …… }

    身份證IdCard代碼:

    @Entity public class IdCard { @Id String userName;//用戶名 @Unique String idNo;//身份證號 ……getter and setter …… }

    insert一組數據:

    public void addStudent(){ DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); Student student = new Student(); student.setStudentNo(i); int age = mRandom.nextInt(10) + 10; student.setAge(age); student.setTelPhone(RandomValue.getTel()); String chineseName = RandomValue.getChineseName(); student.setName(chineseName); if (i % 2 == 0) { student.setSex("男"); } else { student.setSex("女"); } student.setAddress(RandomValue.getRoad()); student.setGrade(String.valueOf(age % 10) + "年紀"); student.setSchoolName(RandomValue.getSchoolName()); daoSession.insert(student); //插入對應的IdCard數據 IdCard idCard = new IdCard(); idCard.setUserName(userName); idCard.setIdNo(RandomValue.getRandomID()); daoSession.insert(idCard); }

    ok,數據可以了!現在數據庫表插入完成了。

    2. 一對多

    一個人擁有多個信用卡
    做法:

  • 在我們在Student中設置@ToMany(referencedJoinProperty = "id");
  • 我們在CreditCard中設置編寫對應的id主鍵;
  • Student的代碼:

    @Entity public class Student { @Id(autoincrement = true) Long id; @Unique int studentNo;//學號 int age; //年齡 String telPhone;//手機號 String sex; //性別 String name;//姓名 String address;//家庭住址 String schoolName;//學校名字 String grade;//幾年級 @ToMany(referencedJoinProperty = "id") // 這個id是對應在CreditCard中的id List<CreditCard> creditCardsList; ……getter and setter …… }

    CreditCard的代碼:

    @Entity public class CreditCard { @Id Long id; Long userId; String userName;//持有者名字 String cardNum;//卡號 String whichBank;//哪個銀行的 int cardType;//卡等級,分類 0 ~ 5 ……getter and setter …… }

    添加數據代碼:

    public void addStudent(){ DaoSession daoSession = ((AserbaoApplication) getApplication()).getDaoSession(); Student student = new Student(); student.setStudentNo(i); int age = mRandom.nextInt(10) + 10; student.setAge(age); student.setTelPhone(RandomValue.getTel()); String chineseName = RandomValue.getChineseName(); student.setName(chineseName); if (i % 2 == 0) { student.setSex("男"); } else { student.setSex("女"); } student.setAddress(RandomValue.getRoad()); student.setGrade(String.valueOf(age % 10) + "年紀"); student.setSchoolName(RandomValue.getSchoolName()); daoSession.insert(student); //插入對應的CreditCard數據 for (int j = 0; j < random.nextInt(5) + 1 ; j++) { CreditCard creditCard = new CreditCard(); creditCard.setUserId(id); creditCard.setUserName(userName); creditCard.setCardNum(String.valueOf(random.nextInt(899999999) + 100000000) + String.valueOf(random.nextInt(899999999) + 100000000)); creditCard.setWhichBank(RandomValue.getBankName()); creditCard.setCardType(random.nextInt(10)); daoSession.insert(creditCard); } }

    3. 多對多

    一個學生有多個老師,老師有多個學生。
    做法:

  • 我們需要創建一個學生老師管理器(StudentAndTeacherBean),用來對應學生和老師的ID;

  • 我們需要在學生對象中,添加注解:

    @ToMany
    @JoinEntity(entity = StudentAndTeacherBean.class,sourceProperty = "studentId",targetProperty = "teacherId")
    List<Teacher> teacherList;

  • 我們需要在老師對象中,添加注解:@ToMany

  • @JoinEntity(entity = StudentAndTeacherBean.class,sourceProperty = "teacherId",targetProperty = "studentId") List<Student> studentList;

    StudentAndTeacherBean代碼:

    @Entity public class StudentAndTeacherBean { @Id(autoincrement = true) Long id; Long studentId;//學生ID Long teacherId;//老師ID ……getter and setter …… }

    Student 代碼:

    @Entity public class Student { @Id(autoincrement = true) Long id; @Unique int studentNo;//學號 int age; //年齡 String telPhone;//手機號 String sex; //性別 String name;//姓名 String address;//家庭住址 String schoolName;//學校名字 String grade;//幾年級 @ToMany @JoinEntity(entity = StudentAndTeacherBean.class,sourceProperty = "studentId",targetProperty = "teacherId") List<Teacher> teacherList; ……getter and setter …… }

    Teacher代碼:

    @Entity public class Teacher { @Id(autoincrement = true) Long id; @Unique int teacherNo;//職工號 int age; //年齡 String sex; //性別 String telPhone; String name;//姓名 String schoolName;//學校名字 String subject;//科目 @ToMany @JoinEntity(entity = StudentAndTeacherBean.class,sourceProperty = "teacherId",targetProperty = "studentId") List<Student> studentList; ……getter and setter …… }

    數據添加:

    public void addData(){ Student student = new Student(); student.setStudentNo(i); int age = mRandom.nextInt(10) + 10; student.setAge(age); student.setTelPhone(RandomValue.getTel()); String chineseName = RandomValue.getChineseName(); student.setName(chineseName); if (i % 2 == 0) { student.setSex("男"); } else { student.setSex("女"); } student.setAddress(RandomValue.getRoad()); student.setGrade(String.valueOf(age % 10) + "年紀"); student.setSchoolName(RandomValue.getSchoolName()); daoSession.insert(student); Collections.shuffle(teacherList); for (int j = 0; j < mRandom.nextInt(8) + 1; j++) { if(j < teacherList.size()){ Teacher teacher = teacherList.get(j); StudentAndTeacherBean teacherBean = new StudentAndTeacherBean(student.getId(), teacher.getId()); daoSession.insert(teacherBean); } } }

    好了,成功;

    7. 數據庫的升級

    GreenDao的OpenHelper下有個 onUpgrade(Database db, int oldVersion, int newVersion)方法,當設置的數據庫版本改變時,在數據庫初始化的時候就會回調到這個方法,我們可以通過繼承OpenHelper重寫onUpgrade方法來實現數據庫更新操作:

    GreenDao的升級思路:

  • 創建臨時表TMP_,復制原來的數據庫到臨時表中;
  • 刪除之前的原表;
  • 創建新表;
  • 將臨時表中的數據復制到新表中,最后將TMP_表刪除掉;
  • ok,思路就是這樣, 總共兩個類: 一個MyDaoMaster(OpenHelper繼承類),一個MigrationHelper(數據庫操作類) 下面是代碼編寫:

    修改Application中的DaoMaster的創建:

    MyDaoMaster helper = new MyDaoMaster(this, "aserbaos.db"); // DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "aserbao.db"); SQLiteDatabase db = helper.getWritableDatabase(); DaoMaster daoMaster = new DaoMaster(db); daoSession = daoMaster.newSession();

    MyDaoMaster代碼:

    public class MyDaoMaster extends OpenHelper { private static final String TAG = "MyDaoMaster"; public MyDaoMaster(Context context, String name) { super(context, name); } public MyDaoMaster(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { super.onUpgrade(db, oldVersion, newVersion); MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() { @Override public void onCreateAllTables(Database db, boolean ifNotExists) { DaoMaster.createAllTables(db, ifNotExists); } @Override public void onDropAllTables(Database db, boolean ifExists) { DaoMaster.dropAllTables(db, ifExists); } },ThingDao.class); Log.e(TAG, "onUpgrade: " + oldVersion + " newVersion = " + newVersion); } }

    MigrationHelper 代碼:

    public final class MigrationHelper { public static boolean DEBUG = false; private static String TAG = "MigrationHelper"; private static final String SQLITE_MASTER = "sqlite_master"; private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master"; private static WeakReference<ReCreateAllTableListener> weakListener; public interface ReCreateAllTableListener{ void onCreateAllTables(Database db, boolean ifNotExists); void onDropAllTables(Database db, boolean ifExists); } public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) { printLog("【The Old Database Version】" + db.getVersion()); Database database = new StandardDatabase(db); migrate(database, daoClasses); } public static void migrate(SQLiteDatabase db, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) { weakListener = new WeakReference<>(listener); migrate(db, daoClasses); } public static void migrate(Database database, ReCreateAllTableListener listener, Class<? extends AbstractDao<?, ?>>... daoClasses) { weakListener = new WeakReference<>(listener); migrate(database, daoClasses); } public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) { printLog("【Generate temp table】start"); generateTempTables(database, daoClasses); printLog("【Generate temp table】complete"); ReCreateAllTableListener listener = null; if (weakListener != null) { listener = weakListener.get(); } if (listener != null) { listener.onDropAllTables(database, true); printLog("【Drop all table by listener】"); listener.onCreateAllTables(database, false); printLog("【Create all table by listener】"); } else { dropAllTables(database, true, daoClasses); createAllTables(database, false, daoClasses); } printLog("【Restore data】start"); restoreData(database, daoClasses); printLog("【Restore data】complete"); } private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { String tempTableName = null; DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; if (!isTableExists(db, false, tableName)) { printLog("【New Table】" + tableName); continue; } try { tempTableName = daoConfig.tablename.concat("_TEMP"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";"); db.execSQL(dropTableStringBuilder.toString()); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName); insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); printLog("【Table】" + tableName +"\n ---Columns-->"+getColumnsStr(daoConfig)); printLog("【Generate temp table】" + tempTableName); } catch (SQLException e) { Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e); } } } private static boolean isTableExists(Database db, boolean isTemp, String tableName) { if (db == null || TextUtils.isEmpty(tableName)) { return false; } String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER; String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?"; Cursor cursor=null; int count = 0; try { cursor = db.rawQuery(sql, new String[]{"table", tableName}); if (cursor == null || !cursor.moveToFirst()) { return false; } count = cursor.getInt(0); } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } return count > 0; } private static String getColumnsStr(DaoConfig daoConfig) { if (daoConfig == null) { return "no columns"; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < daoConfig.allColumns.length; i++) { builder.append(daoConfig.allColumns[i]); builder.append(","); } if (builder.length() > 0) { builder.deleteCharAt(builder.length() - 1); } return builder.toString(); } private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { reflectMethod(db, "dropTable", ifExists, daoClasses); printLog("【Drop all table by reflect】"); } private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { reflectMethod(db, "createTable", ifNotExists, daoClasses); printLog("【Create all table by reflect】"); } /** * dao class already define the sql exec method, so just invoke it */ private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { if (daoClasses.length < 1) { return; } try { for (Class cls : daoClasses) { Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class); method.invoke(null, db, isExists); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } private static void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... 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"); if (!isTableExists(db, true, tempTableName)) { continue; } try { // get all columns from tempTable, take careful to use the columns list List<TableInfo> newTableInfos = TableInfo.getTableInfo(db, tableName); List<TableInfo> tempTableInfos = TableInfo.getTableInfo(db, tempTableName); ArrayList<String> selectColumns = new ArrayList<>(newTableInfos.size()); ArrayList<String> intoColumns = new ArrayList<>(newTableInfos.size()); for (TableInfo tableInfo : tempTableInfos) { if (newTableInfos.contains(tableInfo)) { String column = '`' + tableInfo.name + '`'; intoColumns.add(column); selectColumns.add(column); } } // NOT NULL columns list for (TableInfo tableInfo : newTableInfos) { if (tableInfo.notnull && !tempTableInfos.contains(tableInfo)) { String column = '`' + tableInfo.name + '`'; intoColumns.add(column); String value; if (tableInfo.dfltValue != null) { value = "'" + tableInfo.dfltValue + "' AS "; } else { value = "'' AS "; } selectColumns.add(value + column); } } if (intoColumns.size() != 0) { StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("REPLACE INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", intoColumns)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", selectColumns)); insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); printLog("【Restore data】 to " + tableName); } StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); db.execSQL(dropTableStringBuilder.toString()); printLog("【Drop temp table】" + tempTableName); } catch (SQLException e) { Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e); } } }

    轉載于:https://www.cnblogs.com/Free-Thinker/p/10654474.html

    總結

    以上是生活随笔為你收集整理的一篇好文之Android数据库 GreenDao的完全解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    91在线视频免费 | 久久人人艹 | 精品国产精品一区二区夜夜嗨 | 成人蜜桃网| 黄色影院在线播放 | 午夜精品一区二区三区免费 | 五月婷在线播放 | 日三级在线 | 一区二区三区四区久久 | 制服丝袜在线91 | 日韩高清dvd| 在线午夜av | 啪啪免费试看 | 国产精品美女999 | 日韩在线免费 | 美州a亚洲一视本频v色道 | 免费特级黄色片 | 天天操天天操天天干 | 一区二区欧美激情 | 成人毛片久久 | 天天干天天干天天干天天干天天干天天干 | 久久久国产影视 | 午夜123 | 国产在线精品观看 | 狠狠躁日日躁狂躁夜夜躁 | 黄色大全免费网站 | 午夜精品在线看 | 国产va饥渴难耐女保洁员在线观看 | 五月开心网 | 国产免费午夜 | 天天射夜夜爽 | 国产小视频在线看 | 欧美一区二区免费在线观看 | 日韩无在线 | 亚洲精品视频一 | 国产一区免费在线观看 | 97网在线观看 | 热久久国产 | 手机av电影在线 | 五月婷婷视频在线 | 精品福利网站 | 亚洲视频中文 | 国产在线超碰 | 中文字幕日韩av | 亚洲精品国产拍在线 | 久久久午夜视频 | 午夜精品一区二区三区在线视频 | 日韩在线视频观看免费 | 亚洲久久视频 | 欧美一级小视频 | 91丨九色丨首页 | 久久久私人影院 | 视频91| 日本中文字幕网址 | 久久电影日韩 | 欧美色图亚洲图片 | 久久精品国产免费看久久精品 | 在线观看日本高清mv视频 | 亚洲成人精品久久久 | 在线观看aa| 国产精品免费在线视频 | 日本中文字幕一二区观 | 亚洲天堂香蕉 | 在线观看欧美成人 | 日韩色爱 | 久久国产经典 | 三上悠亚一区二区在线观看 | 欧美一级乱黄 | 四虎成人精品永久免费av九九 | 视频在线观看99 | 九九99视频 | 久久久免费精品视频 | 久久婷婷国产色一区二区三区 | 深夜免费小视频 | 99精品久久只有精品 | 精品99免费视频 | 成人黄色大片在线免费观看 | 日本视频不卡 | www.久久久.com | 欧美成人黄 | 亚洲激情一区二区三区 | 国产又粗又硬又长又爽的视频 | 中文字幕精品在线 | 国产精品理论片 | 一区 二区电影免费在线观看 | 伊人黄| 婷婷久久婷婷 | 国产黄在线播放 | 99视频在线精品国自产拍免费观看 | 国产护士av| 亚洲一区 av | 天天爽夜夜爽人人爽一区二区 | 波多野结衣在线观看视频 | 亚欧日韩av | 国产原创av片 | 中文字幕日本特黄aa毛片 | 在线观看91久久久久久 | 天天操天天色天天 | www.99久久.com | 精品一区二区日韩 | 伊人五月天综合 | 免费视频久久久久 | 超碰在线网 | 亚洲三级网 | 国产69精品久久久久9999apgf | 日韩中文字幕国产 | 色欲综合视频天天天 | 国产精品久久久久久久久久久免费看 | 国产成人精品电影久久久 | av久久久 | 欧美精品久久久久久久免费 | 国产情侣一区 | 久久这里只有精品视频99 | 久久九九视频 | 国产区精品视频 | 美腿丝袜一区二区三区 | 亚州欧美视频 | 91综合视频在线观看 | 国产精品原创视频 | 中文字幕精品视频 | 免费亚洲片| 一区二区不卡高清 | 视频在线观看入口黄最新永久免费国产 | 亚洲伊人成综合网 | 涩涩伊人| 欧美精品成人在线 | 国产精品久久久久久吹潮天美传媒 | 久久久久久久久艹 | 精品国产一区二区三区久久久 | 美女av在线免费 | 在线观看蜜桃视频 | 日韩成人欧美 | 国内精自线一二区永久 | 深爱激情av | 精品国产一区二区三区久久影院 | 黄色精品国产 | 精品主播网红福利资源观看 | 午夜资源站 | 久久精品系列 | 丁香花在线观看免费完整版视频 | 亚洲区另类春色综合小说 | 久久涩涩网站 | 国产高清日韩欧美 | 国产视频不卡一区 | 久9在线| 欧美一级特黄aaaaaa大片在线观看 | 亚洲国产精品500在线观看 | 91精品在线播放 | 国产视频精品免费 | 高清精品久久 | 天天摸天天操天天舔 | 日本一区二区三区视频在线播放 | 亚洲精品美女久久久久网站 | 操久久网| 国产精品国产自产拍高清av | 亚洲经典视频在线观看 | 日本精品视频一区 | 亚洲a成人v | 国产精品第54页 | 久久视频精品在线观看 | 伊人狠狠| 欧美了一区在线观看 | 国产精品人成电影在线观看 | 中文av在线免费观看 | 成全免费观看视频 | 欧美成人xxx | 97超碰在线人人 | 精品国产福利在线 | 91在线精品一区二区 | 97视频人人澡人人爽 | 日韩欧美视频免费观看 | www婷婷| 欧美aa级| 国产精品久久一区二区三区不卡 | 天天操婷婷 | 91大神免费视频 | 日韩av中文字幕在线免费观看 | 国产精品久久 | 国产精品久久久久久高潮 | 国产精品久久久av | 亚洲成av人片在线观看香蕉 | 不卡的一区二区三区 | 成年美女黄网站色大片免费看 | 五月婷婷久久丁香 | 在线视频观看你懂的 | 天天操天天射天天 | 国产情侣一区 | 国产精品久久久久av免费 | 国产成人一区二 | 亚洲午夜久久久久久久久电影网 | 超级av在线| 久久久久久免费毛片精品 | 超碰人人射 | 日韩一级网站 | 激情久久五月天 | 国产免费三级在线观看 | 日日干干 | 国产资源免费 | 精品一区精品二区 | 日韩电影在线观看中文字幕 | 黄色成年片 | 中文字幕丝袜一区二区 | 国产视频一区二区三区在线 | 夜夜爽www | 久久天天躁狠狠躁亚洲综合公司 | 日韩区欧美久久久无人区 | 狠狠干婷婷色 | 91亚洲国产 | 综合网中文字幕 | 国产精品永久久久久久久www | 综合天堂av久久久久久久 | 色在线免费观看 | 日韩精品视频久久 | 国产成人精品久久 | 国产精品免费成人 | 国产999视频在线观看 | 视频一区二区视频 | 日韩在线中文字幕视频 | 国产一二区精品 | 国产精品久久久久久久久久久久 | 欧美一级裸体视频 | 91精品国产高清自在线观看 | 99视频精品在线 | 日韩在线电影 | 国产在线精品播放 | 免费热情视频 | 亚洲一级影院 | 狠狠插天天干 | 男女免费视频观看 | 欧美精品久久久久久久久老牛影院 | 欧美狠狠色| 久久久在线免费观看 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 九九视频在线观看视频6 | 免费a视频| 最新日韩在线观看视频 | 国产日韩欧美在线免费观看 | 日本中文字幕网址 | 丝袜美女在线 | 成人影片在线免费观看 | 三级黄色在线观看 | 97在线精品 | 色综合天天视频在线观看 | 一级免费片 | 久久久天堂| 日韩一级电影在线 | 免费中文字幕视频 | 九色视频网址 | 蜜臀久久99精品久久久酒店新书 | 日韩免费视频线观看 | 亚洲国产综合在线 | 在线国产日本 | 国内精品在线看 | 成人动态视频 | www.色午夜,com | 视频成人永久免费视频 | 美女免费视频观看网站 | 国产成人一区二区三区在线观看 | 手机看片| 日韩精品影视 | 久久精品中文视频 | 国产精品美女久久久久久 | 欧美在线不卡一区 | 久久好看| 美女视频一区 | 在线亚洲高清视频 | 国产九九精品视频 | 99精品免费视频 | 日本激情动作片免费看 | 日韩精品播放 | 麻豆影视在线观看 | 久久综合激情 | 看黄色.com| 色久av| 色五月色开心色婷婷色丁香 | 国产原创在线 | 99精品免费久久久久久久久日本 | 色中射| 摸bbb搡bbb搡bbbb | 久久久久久视频 | 涩涩网站在线 | www.xxx.性狂虐 | 成人精品在线 | 精品久久久久久国产91 | av女优中文字幕在线观看 | 福利电影久久 | 日韩免费中文字幕 | 色视频国产直接看 | 综合久久网| 久久久久久久久久久久久久电影 | 最新真实国产在线视频 | 久色免费视频 | 亚洲1级片 | 国产福利免费在线观看 | 国产成人精品久久久久 | 婷婷看片 | 日日草视频 | 中文字幕a∨在线乱码免费看 | 欧美日韩三区二区 | 亚洲综合导航 | 免费av观看网站 | 伊人网综合在线观看 | 成人a级网站 | 午夜精品99久久免费 | 天天射色综合 | 亚洲午夜精品福利 | 久久久精品成人 | 又黄又爽又无遮挡的视频 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 国产精彩视频一区二区 | 欧美大香线蕉线伊人久久 | 免费人成在线观看 | 色综合天天综合 | 特级西西www44高清大胆图片 | 国产精品资源 | 国产精品黄色在线观看 | 天天干天天干天天射 | 色wwww| 99精品视频在线观看 | 中文字幕免费在线 | 特级西西444www大精品视频免费看 | 久久久久亚洲最大xxxx | 欧美日韩在线看 | 精品视频www | 日韩精品久久久免费观看夜色 | 五月婷婷黄色 | 国产亚洲精品久久久久动 | 欧美日韩一级久久久久久免费看 | 久久蜜桃av| 黄色小说视频在线 | 四虎免费在线观看视频 | 在线免费试看 | 久久99久久99精品中文字幕 | 麻豆久久久久久久 | 国产成人av福利 | 美女视频永久黄网站免费观看国产 | 韩国av一区二区三区 | 中文字幕国内精品 | 国产91全国探花系列在线播放 | 国产成人精品一区一区一区 | 欧美极品少妇xbxb性爽爽视频 | 碰超在线 | 美女视频黄网站 | 日韩精品视频免费在线观看 | 亚洲精品视频在线播放 | 人人澡澡人人 | 国产精品6999成人免费视频 | 国产精品久久久99 | 亚洲欧美在线综合 | 欧美激情综合五月色丁香小说 | 俺要去色综合狠狠 | 精品二区视频 | 免费高清在线一区 | 天天综合天天综合 | 久久婷婷视频 | 日本最新中文字幕 | 色wwwww| 99日韩精品 | 国产亚洲婷婷免费 | 黄色大片免费播放 | 一区二区三区在线电影 | 久久99精品国产 | 久久久国产一区二区 | 在线之家免费在线观看电影 | 亚洲人在线7777777精品 | 少妇高潮冒白浆 | 免费看的毛片 | 国产视频97| 色噜噜噜噜 | 99精品在线播放 | 久久精品5 | av在线播放一区二区三区 | 色在线免费| 国产视| 国产福利免费看 | 玖玖精品视频 | 91视频最新网址 | 日韩电影精品一区 | 69人人| 夜夜夜影院 | 欧美孕妇与黑人孕交 | 91精品在线免费视频 | 亚洲日本在线视频观看 | 国产在线精品视频 | 99热在线国产精品 | 免费黄a大片 | 五月婷丁香网 | 天天鲁天天干天天射 | 久久99久久99精品 | 深爱开心激情 | 国产在线精品福利 | 亚洲一区在线看 | 国产精品久久久久一区二区三区共 | 午夜狠狠操 | 久久久综合九色合综国产精品 | 中文字幕日韩高清 | 国产成人精品不卡 | av最新资源| 成人精品视频久久久久 | 久久久久久久久久久影视 | 国产精品永久在线 | 久久综合狠狠狠色97 | 国色综合 | 国产一区免费视频 | 日韩系列 | 狠狠色丁香九九婷婷综合五月 | 91黄色在线视频 | 久草在线资源视频 | 国产一区二区三区在线免费观看 | 一区二区三区四区五区在线视频 | 黄色av电影在线 | 久久久久国产精品www | 久久在线视频在线 | 久久久www成人免费精品 | 一区二区三区免费 | 韩国精品视频在线观看 | 激情丁香 | 狠狠狠狠狠狠狠干 | 日韩一区二区三免费高清在线观看 | 四虎永久精品在线 | 久草观看 | 色综合久久88色综合天天人守婷 | www.av在线.com | 久久爽久久爽久久av东京爽 | 97精品一区 | 97av在线| 91免费版在线 | 中文字幕欧美日韩va免费视频 | 中文字幕免费播放 | 久久久久国产精品一区二区 | 人人爽人人爽人人爽学生一级 | 久久九九国产视频 | 国产裸体永久免费视频网站 | 免费av小说 | 亚洲综合黄色 | 亚洲国产视频在线 | 韩国在线视频一区 | aⅴ视频在线 | 欧美精品久久天天躁 | 国产高清绿奴videos | 天天摸天天操天天舔 | 国产黄大片 | 国产视频一区二区在线播放 | 在线免费观看视频一区二区三区 | 国产盗摄精品一区二区 | 在线91av| 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 久久99热精品这里久久精品 | 日本在线观看一区二区 | 黄色字幕网 | 在线视频久久 | 日本乱码在线 | 色多多在线观看 | 午夜婷婷网 | 色婷婷 亚洲 | 韩日精品在线 | 日韩视频一区二区在线 | 国产精品久久久久久久久久东京 | 亚洲黄色高清 | 99视频精品全部免费 在线 | 欧美性成人 | 日本公妇在线观看 | 99精品在线直播 | 天天摸夜夜添 | 蜜臀91丨九色丨蝌蚪老版 | 在线黄网站 | 日韩a级黄色片 | 伊人宗合网 | 天天看天天干 | 成人在线一区二区三区 | 特级片免费看 | 久久久久一区二区三区四区 | 成人啊 v | 国产精品 9999| 日韩成人精品一区二区 | 91久久久国产精品 | 亚洲电影第一页av | 国产精品久久久久久久久软件 | 91亚洲精品久久久蜜桃 | 国产精品电影一区 | 日韩va亚洲va欧美va久久 | 日韩精品在线观看av | 在线免费观看一区二区三区 | 最近日本韩国中文字幕 | 国产精品毛片久久久久久久久久99999999 | 午夜精品久久久久久99热明星 | av 一区二区三区 | 亚洲国产精品99久久久久久久久 | 欧美乱熟臀69xxxxxx | 99视频国产精品免费观看 | 五月婷婷爱 | 国产免费成人av | 一级黄色片在线观看 | 欧美精品在线观看一区 | 亚洲女裸体 | 最近免费中文字幕 | 国产高清视频在线播放 | 五月婷婷一级片 | 午夜精品成人一区二区三区 | 成人免费视频网站在线观看 | 在线观看av麻豆 | 国产精品激情在线观看 | 色婷婷久久久 | 成年人看片网站 | 国产伦精品一区二区三区四区视频 | 天天干,天天插 | 国产精品av在线 | 久久丁香 | 免费中午字幕无吗 | 免费色视频网址 | 亚洲乱码精品久久久 | 婷婷精品在线 | 久久久久综合视频 | 亚洲精品视频一二三 | 午夜视频亚洲 | av看片在线观看 | 超碰在线日本 | 黄色av免费| 婷婷网五月天 | 五月婷婷黄色 | 国产精品毛片一区 | 日批视频国产 | 91视频免费观看 | 最近久乱中文字幕 | 午夜三级毛片 | 久久午夜免费视频 | 久热av | www黄| 欧美精品久久久久a | 日韩精品一区二区免费视频 | 久久久久五月天 | 四月婷婷在线观看 | 天天色.com| 欧美va天堂在线电影 | 中中文字幕av在线 | 麻豆视频一区 | 日本精品va在线观看 | 91传媒免费观看 | 一区三区视频在线观看 | www.久久久 | 日韩综合一区二区 | 久久综合免费视频影院 | www.91av在线 | av一区二区三区在线观看 | 开心色插| av网址在线播放 | 日韩高清精品一区二区 | 日本一区二区三区免费观看 | 蜜臀久久99精品久久久酒店新书 | 在线观看国产麻豆 | www.伊人色.com | 国产乱对白刺激视频在线观看女王 | 久草网站在线观看 | 国产精品一区二区在线 | 夜色在线资源 | 一级特黄aaa大片在线观看 | 黄色精品一区二区 | av不卡网站| 国产日韩中文字幕 | 超碰免费成人 | 激情五月伊人 | 亚洲闷骚少妇在线观看网站 | 国产成人一区二区精品非洲 | 久久婷婷国产 | 精品999| 中文字幕 第二区 | 美女黄频 | 久草久热 | 欧美成人影音 | 在线观看精品视频 | 91视频com| 91丨九色丨蝌蚪丨老版 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 日韩网站中文字幕 | 欧美另类sm图片 | 在线观看色网 | 亚洲片在线观看 | 国产精品久久久影视 | 精品久久久久久久久久久久久久久久 | 麻豆94tv免费版 | 狠狠狠色丁香综合久久天下网 | 国产乱对白刺激视频在线观看女王 | 成年人免费电影 | 狠狠色丁香九九婷婷综合五月 | 国产精品一区二区久久国产 | 午夜少妇av | 欧美日本日韩aⅴ在线视频 插插插色综合 | 亚洲综合国产精品 | 日韩欧美视频一区二区 | 日日天天av | 午夜三级毛片 | 麻豆精品视频在线 | 日韩精品免费在线播放 | 色吊丝在线永久观看最新版本 | 久久福利综合 | 激情导航 | 精品久久免费看 | 中文字幕在线看视频 | 国产成人精品一区在线 | 欧美高清视频不卡网 | 国产一区二区三区免费视频 | www日| 亚洲欧美日韩在线看 | 最新免费av在线 | 69av免费视频 | 99热99re6国产在线播放 | 高清av中文在线字幕观看1 | 欧美极品一区二区三区 | 免费在线观看国产精品 | www.夜夜夜 | 中文字幕成人av | 在线视频 亚洲 | 久久久久久久久久国产精品 | 日韩成人免费电影 | 国产一级高清视频 | 日日弄天天弄美女bbbb | 手机在线中文字幕 | 色a网| 国内99视频 | 欧美另类巨大 | 国内精品久久久久影院优 | 色天天综合网 | 久久超级碰视频 | 91av在 | 国产精品成人免费一区久久羞羞 | 免费观看黄色12片一级视频 | 6080yy精品一区二区三区 | 91精品国产乱码久久桃 | 婷婷六月中文字幕 | 国产麻豆精品一区 | 丰满少妇高潮在线观看 | 日韩电影一区二区三区 | 亚洲精品2区 | 亚洲成人精品久久 | 美女国产网站 | 国内精品视频一区二区三区八戒 | 人人看人人草 | 午夜在线日韩 | 国产精品激情偷乱一区二区∴ | 久久视频免费在线观看 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 欧产日产国产69 | 91豆花在线| 中文字幕免费一区 | 中文字幕一区二区三 | 婷婷 综合 色 | 国产色视频123区 | 日韩网站在线观看 | 射九九| 天天摸日日摸人人看 | 91一区二区在线 | 国产美女永久免费 | 亚洲另类视频在线观看 | 国产色黄网站 | 51久久成人国产精品麻豆 | 天天翘av | 国产精品2019 | 欧美一级艳片视频免费观看 | 国产精品一区二区免费看 | 亚洲高清视频在线播放 | 在线亚洲成人 | 日韩区视频 | 黄色www | 四虎国产精品免费观看视频优播 | 亚洲精品免费观看 | 国产色黄网站 | а中文在线天堂 | 国产不卡在线观看视频 | 亚洲伦理一区 | 中文字幕韩在线第一页 | 日日爱影视 | 日韩影片在线观看 | 色偷偷88888欧美精品久久 | 黄网站色视频免费观看 | 国产成人精品在线观看 | 久草视频在线免费播放 | 国产美女免费看 | 国产成人精品一区二区三区在线观看 | 黄色成人av | www.色午夜.com| 国产婷婷一区二区 | 中文字幕在线看视频国产中文版 | 中文字幕免费高清av | 免费视频在线观看网站 | 亚洲精品麻豆视频 | 国产亚洲精品日韩在线tv黄 | 在线视频你懂得 | 久久国产亚洲 | 国产精品电影一区二区 | 久久久国产99久久国产一 | 伊人视频| 伊人久久国产 | 91传媒91久久久 | 国产福利不卡视频 | 亚洲天天在线日亚洲洲精 | 国产 日韩 在线 亚洲 字幕 中文 | 日本aaa在线观看 | 天海冀一区二区三区 | 日日爽天天爽 | 久99久视频 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 国产亚洲免费的视频看 | 成人在线观看你懂的 | 97在线免费视频 | 五月天.com| 91成人网在线观看 | 亚洲精品无 | 国产伦精品一区二区三区在线 | 欧美成人黄色片 | 日韩1级片 | 国产国语在线 | 在线观看视频免费大全 | 日韩xxxx视频 | 国产欧美日韩精品一区二区免费 | 日日操日日插 | 久久久资源 | 久久国产福利 | 蜜臀久久99静品久久久久久 | 天天色综合1 | 亚洲午夜久久久综合37日本 | 国产一区 在线播放 | 国产露脸91国语对白 | 又黄又刺激又爽的视频 | 超碰97在线人人 | 婷婷激情在线 | 国产精品6 | 国产成人精品999在线观看 | 日韩在线视 | 欧美精品在线观看一区 | 日韩精品一二三 | 日本aaa在线观看 | 国产黄色精品视频 | 久色 网 | 久章操 | 在线国产视频一区 | 国产xxxx做受性欧美88 | 久久久久99精品成人片三人毛片 | 国产黄色av影视 | 国产剧情久久 | 久久精品久久久久久久 | 久久99精品国产99久久6尤 | 国产午夜一区 | 国产一区二区播放 | av在线观 | 亚洲综合一区二区精品导航 | 国产精品丝袜在线 | 国产尤物在线视频 | 国产一区二区三区黄 | 久久激情综合 | bbw av| 亚洲综合激情五月 | 99热这里| 欧美亚洲专区 | 日韩视频免费在线观看 | 精品国产色| 亚洲在线视频免费观看 | 在线韩国电影免费观影完整版 | 99热最新 | 丁香五月缴情综合网 | 狠狠干我 | 久久99精品国产 | 国产综合婷婷 | 久久久久久久18 | 国产最新视频在线 | 久久草在线视频国产 | 婷婷社区五月天 | 欧美另类性 | 中文在线天堂资源 | 国产精品人成电影在线观看 | 精品一区二区三区电影 | 久久高清免费视频 | 久久免费福利 | 免费在线观看不卡av | 日韩在线免费小视频 | 久久精品99国产精品 | 黄污网站在线 | 午夜三级福利 | 久久这里只有精品首页 | 亚洲精品国产品国语在线 | 免费男女羞羞的视频网站中文字幕 | 国产网红在线观看 | 国产va在线| 日韩电影在线视频 | 中文字幕第一页在线 | 久久精品2 | av电影一区二区三区 | 91高清一区 | 91人人爽久久涩噜噜噜 | 国产亚洲高清视频 | 国产精品6 | 丁香激情婷婷 | 欧美 激情 国产 91 在线 | 五月天天av | 国产一区二三区好的 | 久久综合久久综合久久 | 在线观看色网站 | 91麻豆精品91久久久久同性 | 国产一区二区三区免费在线 | 色狠狠干 | 五月开心六月伊人色婷婷 | 亚洲爱爱视频 | 精品国产一区二区三区久久久蜜月 | 狠狠色丁香婷婷综合欧美 | 欧洲性视频| 免费高清看电视网站 | 91麻豆精品国产91久久久久久久久 | 欧美在线不卡一区 | 奇米网在线观看 | 亚洲综合一区二区精品导航 | 伊人永久在线 | 麻豆精品视频在线观看免费 | 久久久高清一区二区三区 | 91大神电影 | 91福利视频免费 | 日韩欧美国产精品 | 国产自在线 | 97超碰超碰| 国产手机在线观看视频 | 欧美 国产 视频 | 国产视频一区二区在线播放 | 国产一区二区三区免费在线 | 五月天色综合 | 日韩激情视频在线观看 | 日韩欧美在线免费观看 | 一区在线观看 | 欧美一级久久久久 | 精品一二三四视频 | 伊人影院在线观看 | 日韩在线高清视频 | 97人人爽 | 欧美一级免费 | 中文字幕色综合网 | 九色91在线 | 日本中文字幕影院 | 国产97免费 | 精品国偷自产国产一区 | 欧美另类sm图片 | 国产成人一区二区三区免费看 | 亚洲精品ww| 日韩三级中文字幕 | 黄色三级网站在线观看 | 国产午夜视频在线观看 | 丝袜美女在线观看 | 999国内精品永久免费视频 | 夜夜天天干 | 天天操操 | 黄色三级免费看 | 久久999精品 | 日本黄色大片免费看 | 国产精品免费久久久 | 狠狠操狠狠干2017 | 久久国产一区二区 | 亚洲成人999 | 久久狠狠干 | 国产亚洲精品久久久久久久久久 | 91精彩视频在线观看 | 亚州天堂| 精品国产精品一区二区夜夜嗨 | 91精品一区二区三区蜜桃 | 久久久久久久久久久黄色 | 久久国产精品一二三区 | 91视频久久 | 亚洲麻豆精品 | 国产日女人| 一区二区三区四区精品视频 | 在线成人国产 | 欧美在线视频不卡 | 天天操天天操天天 | 午夜美女av | 四虎影视精品永久在线观看 | 欧美日韩18 | 久草视频2| 97av免费视频 | 亚洲五月婷 | 色片网站在线观看 | 天天草天天摸 | 蜜臀av在线一区二区三区 | 91福利试看 | 亚洲波多野结衣 | 欧美巨大荫蒂茸毛毛人妖 | 在线观看国产成人av片 | 国产在线不卡 | 成人国产精品电影 | 天天弄天天操 | 国产a国产| 久久精品香蕉视频 | 午夜少妇一区二区三区 | 久久综合久久综合这里只有精品 | 国产精品wwwwww| 久久久久久久久久久久久久av | 久久视频国产精品免费视频在线 | 久久精品欧美一区二区三区麻豆 | 久久免费成人网 | 三级黄色理论片 | 97超碰人人澡人人爱学生 | 日韩免费b | 成人av网页 | 国产成人一区二区啪在线观看 | 久久综合一本 | 国产看片免费 | 国产精品99久久久久久大便 | 成人av观看 | 国产黄色片免费观看 | 在线观看成年人 | 三级a视频 | 国产精品福利在线观看 | 欧美 亚洲 另类 激情 另类 | 91成版人在线观看入口 | 香蕉视频在线观看免费 | 久久中文网 | 黄色片网站免费 | 中文字幕字幕中文 | 中文av网站 | 日本美女xx | 国产精品一区免费在线观看 | 久久久免费毛片 | 亚洲一区二区精品 | 在线观看中文字幕一区二区 | 在线视频免费观看 | 日韩精品视频在线免费观看 | 好看av在线 | 毛片www | 精壮的侍卫呻吟h | 久久国产精品久久精品国产演员表 | 国产在线观看免费 | 狠狠躁夜夜躁人人爽视频 | 欧美一区二区日韩一区二区 | 国产主播大尺度精品福利免费 | 天天操天天射天天舔 | 日韩黄色免费电影 | 97成人精品视频在线观看 | 韩国av电影在线观看 | 精品国产一区二区三区久久久蜜月 | 国产拍揄自揄精品视频麻豆 | 五月婷婷激情综合 | 亚洲视频专区在线 | 日韩网站在线 | av福利在线导航 | 国产色影院 | 精品999久久久| 欧美一级日韩三级 | 91爱爱免费观看 | 亚洲永久精品在线 | 亚洲精品tv久久久久久久久久 | 成 人 黄 色 视频免费播放 | www·22com天天操| 国内免费久久久久久久久久久 | 综合天天 | 91精品在线免费观看视频 | 国产 日韩 中文字幕 | 国产无套精品久久久久久 | 九九热精品视频在线播放 | 日韩二区三区在线观看 | 91福利视频网站 | 色综合欧洲 | 丁香六月婷婷激情 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 日韩精品在线观看视频 | 91中文字幕网 | 亚洲精区二区三区四区麻豆 | 日日夜色 | 一级欧美日韩 | 中文字幕一区二区三区四区久久 | 综合成人在线 | 人人干97 | 麻豆视频成人 | 国产在线视频在线观看 | 久久精品国产v日韩v亚洲 | 狠狠狠狠狠狠狠狠干 | 国产成人精品国内自产拍免费看 | 国产99在线免费 | 在线观看第一页 | 99精品欧美一区二区三区黑人哦 | 欧美在线观看小视频 | 欧美激情片在线观看 | 九九免费在线观看视频 | 丝袜足交在线 | av一级片| 中文字幕成人 | 91久久精品一区 | 99久久精品国产亚洲 | 97色综合| 欧美韩国在线 | 国产精品2区 | 视频在线国产 | 欧美午夜精品久久久久 | 日韩资源在线播放 | 九九热国产 | 国产在线精品一区二区不卡了 | 狠狠色丁香婷婷综合 | 国产一二三四在线观看视频 | 91在线最新 | 国产高清在线免费 | 久久久久色| 免费精品在线 | 在线黄色国产电影 | 婷婷综合亚洲 | 一区二区三区韩国免费中文网站 |