GreenDao3+ 介绍

2019-08-08  本文已影响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());
                }
上一篇下一篇

猜你喜欢

热点阅读