美文网首页
GreenDao3+ 介绍

GreenDao3+ 介绍

作者: 灿烂呀 | 来源:发表于2019-08-08 11:46 被阅读0次

    简介
    GreenDao可以说是当今最流行,最高效而且还在迭代的关系型数据库。
    关系型数据库:ORM(Object Relation Mapping 即 对象关系映射),就是将面向对象编程语言里的对象与数据库关联起来的一种技术,greenDao其实就是一种将java object 与SQLite Database关联起来的桥梁

    配置不介绍了,参考官网即可。

    优点

    1.存取速度快
    2.支持数据库加密
    支持android原生的数据库SQLite,也支持SQLCipher(在SQLite基础上加密型数据库)。
    3.轻量级
    greenDao的代码库仅仅100k大小
    4.激活实体
    处于激活状态下的实体可以有更多操作方法
    5.支持缓存
    能够将使用的过的实体存在缓存中,下次使用时可以直接从缓存中取,这样可以使性能提高N个数量级
    6.代码自动生成

    DaoMaster

    DaoMaster 是入口类,每一个DaoMaster持有一个数据库连接,通过DaoMaster#newSession()方法可以实例化多个Session,这些Session对应同一个数据库连接,但是系统会为每一个Session分配内存,在这片内存中会为实体进行缓存。每一个Session对应一个Identity .

    DaoSession

    从DaoSession中可以获取各实体类的对应DAO,然后就可以进行增删改查的操作了,对于每一个Session中的查询操作都会对查到的实体类做缓存操作,所以对应同一个Session的多次查询操作,如果entity的对象在该Session中有对应缓存则直接使用,而不再从数据库中读取数据并构建新的实体类对象。

    常用注解介绍

    @Entity

    该实例是类的注解,告诉greenDAO这个类是需要持久化的实体类。下面是其内部注解

    @Entity(
            // If you want to have more than one schema, you can tell greenDAO
            // to which schema an entity belongs (pick any string as a name).
            schema = "myschema",
            
            // Flag to make an entity "active": Active entities have update,
            // delete, and refresh methods.
            active = true,
            
            // Specifies the name of the table in the database.
            // By default, the name is based on the entities class name.
            nameInDb = "AWESOME_USERS",
            
            // Define indexes spanning multiple columns here.
            indexes = {
                    @Index(value = "name DESC", unique = true)
            },
            
            // Flag if the DAO should create the database table (default is true).
            // Set this to false, if you have multiple entities mapping to one table,
            // or the table creation is done outside of greenDAO.
            createInDb = false
    )
    
    @ID, field注解

    表示选择一个long或Long类型的属性作为该实体所对应数据库中数据表的主键,参数可以设置(autoincreament=true),其实其他类型高版本也是可以的,比如String 不过应该不能自增长了。

    @Property field 注解

    可以自定义该属性在数据表的列名,默认的列名为属性名大写,并由下划线隔开多个单词,@Property(nameInDb="XXXX")可以自定义列名。

    @NotNull

    对应着数据表中该列不能为空。

    @Transient

    与Java中的Transient关键字类似,指不对该属性持久化,即不为该属性在数据表中创建相应列。

    @Index

    使用@Index 可以将一个属性变为数据库索引;其有俩个参数
    name :不使用默认名称,自定义索引名称
    unique : 给索引增加一个唯一约束,迫使该值唯一

    @Entity
    public class User { 
    @Id 
    private Long id;
     @Index(unique = true)
     private String name;
    }
    
    @Unique

    含义与数据表中列的unique一致, 这种情况下,SQLite会自动为该列建立索引。

    @Generated greenDAO

    会根据开发者定义的实体类定义schema,并生成DAOs,而在生成过程中会为开发者编写的实体类的一些方法和域上添加

    @Generated注解

    提示开发者该属性不能被修改;并且实体类的方法,属性,构造器一旦被@Generated注释就不能被再次修改,否则或报错

    此外还有@ToOne, @ToMany, @JoinEntity与多个数据表的关系有关,后面再对此详细介绍。

    @Entity
    public class User { 
          @Id(autoincrement = true)
           private Long id;  
          @Property(nameInDb = "USERNAME") 
           private String name;  
          @NotNull 
          private int repos;  
          @Transient 
          private int tempUsageCount; 
     ...}
    
    查询list

    1.list()
    缓存查询结果;list()类型一般为ArrayList
    2.listLazy();
    懒查询,只有当调用list()中的实体对象时才会执行查询操作并且只缓存第一次被查询的结果,需要关闭
    3.listlazyUncached() 懒查询,只有当调用list()中的实体对象时才会执行查询操作并且不缓存;
    4.listIterator() 对查询结果进行遍历,不缓存,需要关闭;

       List<City>  cityList =EntityManager.getInstance().getCityDao().queryBuilder().list();
        LazyList<City>  cityList2 =EntityManager.getInstance().getCityDao().queryBuilder().listLazy();
        cityList2.close();
        List<City>  cityList3 =EntityManager.getInstance().getCityDao().queryBuilder().listLazyUncached();
        CloseableListIterator<City> cityList4 =EntityManager.getInstance().getCityDao().queryBuilder().listIterator();
        cityList4.close();//需要try
    
    
    分页查询

    limit(int): 限制查询的数量;
    offset(int): 每次返回的数量; offset不能单独使用;

    多次查询:

    即 第一次查询返回的 query 可以再次设置条件;

    // fetch users with Joe as a first name born in 1970
    Query<User> query = userDao.queryBuilder().where(
        Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)
    ).build();
    List<User> joesOf1970 = query.list();
     
    // using the same Query object, we can change the parameters
    // to search for Marias born in 1977 later:
    query.setParameter(0, "Maria");
    query.setParameter(1, 1977);
    List<User> mariasOf1977 = query.list();
    
    关联查询 joinI();
    @Entity
    public class City {
    
        @Id
        private Long  id;
    
        private  String name;
    
        private  int   population;
    
        private  Long  countryId;
    }
    
    @Entity
    public class Country {
        @Id
        private Long  id;
    
        private  String  name;
    }
    

    city 表示持有country 表的id

      QueryBuilder<Country> qb=EntityManager.getInstance().getCountryDao().queryBuilder();
                  Join cities= qb.join(City.class,CityDao.Properties.CountryId)
                          .where(CityDao.Properties.Population.gt(1000));
                   List<Country> countries =qb.list();
    

    就是 join on 只不过这里它替你写了 on 的部分,应该只是 id 才可以。

    多线程查询

    多条线程执行查询语句时需要调用forCurrentThread()方法将query对象与当前线程进行绑定,如果其他线程修改该Query对象,greenDao将会抛出一个异常;forCurrentThread()方法通过将Query创建时的时间作为 query标识;
    先看一段代码

     final   Query<Country> query =EntityManager.getInstance().getCountryDao().queryBuilder().build();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            List<Country> countries =query.list();
                            for (Country c:countries){
                                Log.e("返回",c.getName()+Thread.currentThread().getName());
                            }
                        }
                    }).start();
    

    执行后会报错,当前的query 已经绑定到主线程,这时候在子线程中调用query 会报错

    08-08 15:56:44.040 4587-4614/com.green.dao E/AndroidRuntime: FATAL EXCEPTION: Thread-314
        Process: com.green.dao, PID: 4587
        org.greenrobot.greendao.DaoException: Method may be called only in owner thread, use forCurrentThread to get an instance for this thread
            at org.greenrobot.greendao.query.AbstractQuery.checkThread(AbstractQuery.java:99)
            at org.greenrobot.greendao.query.Query.list(Query.java:87)
            at com.green.dao.MainActivity$1.run(MainActivity.java:98)
            at java.lang.Thread.run(Thread.java:818)
        
    

    这个错误是在哪里抛出的呢?看下list()源码

     public List<T> list() {
            checkThread();
            Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
            return daoAccess.loadAllAndCloseCursor(cursor);
        }
    
        protected void checkThread() {
            if (Thread.currentThread() != ownerThread) {
                throw new DaoException(//就是这里抛出了异常
                        "Method may be called only in owner thread, use forCurrentThread to get an instance for this thread");
            }
        }
    

    啥意思?list()只能在它自己的线程中调用。 错误提示很清晰了,用 forCurrentThread 给当前线程一个 query

      final   Query<Country> query =EntityManager.getInstance().getCountryDao().queryBuilder().build();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            List<Country> countries =query.forCurrentThread().list();
                            for (Country c:countries){
                                Log.e("返回",c.getName());
                            }
                        }
                    }).start();
    

    这样就ok 了。大概就是每个线程要绑定自己的query

    所以下面这张写法肯定没有问题啦

     new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Query<Country> query =EntityManager.getInstance().getCountryDao().queryBuilder().build();
                            List<Country> countries =query.list();
                            for (Country c:countries){
                                Log.e("返回",c.getName());
                            }
                        }
                    }).start();
    
    Sql语句查询

    方式1

     Query<City> query =EntityManager.getInstance().getCityDao().queryBuilder().where(new WhereCondition.StringCondition("_ID IN"+"(SELECT _ID FROM CITY WHERE  _ID=1)")).build();
                    City city =query.unique();
    

    StringCondition()中的内容:_ID 可以换成任何字段,但是需要跟后面的查询内容保持一致, 虽然后面的sql 语句是如果放到数据库里查询是只能返回id 但是这里不是 而是返回所有值。注意 IN 还有sql 语句的括号。

    方式2:

    Query<City> query =EntityManager.getInstance().getCityDao().queryRawCreate("where _ID=?","1");
                    City city=query.unique();
                        Log.e("返回值",city.getPopulation()+"~~~"+city.getName()+"~~~"+city.getId());
    
    

    方式3

      List<City> citiess=EntityManager.getInstance().getCityDao().queryRaw("where _ID=?","1");
                    for (City city:citiess){
                        Log.e("返回值",city.getPopulation()+"~~~"+city.getName()+"~~~"+city.getId());
                    }
    

    相关文章

      网友评论

          本文标题:GreenDao3+ 介绍

          本文链接:https://www.haomeiwen.com/subject/rqatjctx.html