安卓项目实战之:数据库框架 LitePal 3.0 的使用详解

LitePal简介

LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表和增删改查的操作,并且LitePal很“轻”,jar包大小不到100k,而且近乎零配置,这一点和Hibernate这类的框架有很大区别。

GitHub : http://github.com/LitePalFramework/LitePal

LitePal的使用

1.添加依赖
在app/build.gradle文件中添加compile依赖如下:

dependencies {
    compile 'org.litepal.android:java:3.0.0'
}

2.在assets目录下创建litepal.xml配置文件
项目文件夹下New->Folder->Assets Folder创建相应的assets文件夹,然后在assets文件夹下创建一个名为litepal.xml的文件,编辑文件如下:

<?xml version="0.1" encoding="utf-8"?>
<litepal>
   <dbname value="litepaldemo" />            // 数据库名称为litepaldemo,默认以 .db 结尾,如未以此结尾,则自动添加。 
   <version value="1" />                     // 数据库版本为1,每次数据库发生变动版本号必须+1
   <list>                                    // 有几张表就在list之间写几个mapping
      // list标签中的实体类都应该继承LitePalSupport这个类,这个千万别忘记,实体类里面不能包含如List类型的字段,否则会报错
       <mapping class="com.gpf.com.User"></mapping>
       <mapping class="com.gpf.com.Reader"></mapping>  
       <mapping class="com.gpf.com.Movie"></mapping>
   </list>                           
   <storage value="gpf/database" />  //storage 定义数据库文件存储的地方,可选 internal(内部) 和 external(外部), 默认为 internal 
</litepal>

注意:上面的version版本号的配置在每次数据库有更改时度必须+1,否则新的修改不会生效,我们可以这样理解,当我们新增了一个mapping,但是version没有+1的话,重新运行应用,发现value的值和之前一样,就会忽略< list >标签中配置的mapping,这样新加的数据库是不会创建的,除非我们卸载了重新安装,不然就必须设置version+1才会重新启动配置。

3,在Application中初始化
在自己的application中加入一行代码即可:

public class MyApplication extends Application { 
    @Override 
    public void onCreate() { 
        super.onCreate();
        // 初始化
        LitePal.initialize(this); 
    }  
 ... 
 }

经过上面3步的配置,LitePal就已经集成成功并可以正常使用了。

4,创建实体类,继承 LitePalSupport,不能包含List类型的属性(非LitePal支持的类型),否则会报异常

litepal支持的实体类字段映射类型为 int,long,double,float,byte[],boolean,String,Date;不支持String[]数组型

public class Movie extends LitePalSupport{ 
    
    private int id;
    
    //name是唯一的,且默认值为unknown 
    @Column(unique = true, defaultValue = "unknown") 
    private String name; 
    
    //忽略即是不在数据库中创建该属性对应的字段 
    @Column(ignore = true) 
    private float price; 
    
    private byte[] cover; 
    private int duration; 
    
    //不为空 
    @Column(nullable = false) 
    private String director; 
    
    private String type; 
    
    //记得添加所有字段的getter和setter方法 
}

注意:

  • 其中id这个字段可写可不写,因为即使不写这个字段,LitePal也会在表中自动生成一个id列,毕竟每张表都一定要有主键的, 即不管实体类中有没有id这个属性,都会默认创建一个为整型的id字段,作为自增的主键。

使用的insert()方法来存储数据时是有返回值的,返回的是插入行对应的id也就是行号。但LitePal中的save()方法返回的是布尔值,那么我们怎样才能拿到存储成功之后这条数据对应的id呢?对此,LitePal使用了一种非常巧妙的做法,还记得我们在每个实体类中都定义了一个id字段吗?当调用save()方法或saveThrows()方法存储成功之后,LitePal会自动将该条数据对应的id赋值到实体类的id字段上。

  • 如果实体类中有一个字段名为id,那么类型只能为int或者long
  • id字段的值始终为当前记录的行号(下标从1开始),即使我们在实体类中定义了int或者long类型的id字段,在添加数据时人为的设置id的值为100,等其他值,查询数据库发现该id字段的值设置是无效的,她始终等于该条记录所在的行id,即第几条记录。
  • 所有的column注解总共有四个,defaultValue的默认值为空字符,所以这个注解只能用以是String类型的字段,即字符型才有默认值
  • litepal支持的实体类字段映射类型为 int,long,double,float,byte[],boolean,String,Date;不支持String[]数组型

现在只要对数据库有任何操作,指定的数据库表就会自动被创建。比如获取SQLiteDatabase示例:

SQLiteDatabase db = LitePal.getDatabase();

调用上面的代码后,数据库所有的表就被自动创建好了。

数据库增删改查操作

1.存储操作
详细说明参见:LitePal的存储操作

Movie movie1=new Movie(); 
  movie1.setId(1002); 
  movie1.setName("东成西就"); 
  movie1.setDirector("刘镇伟"); 
  movie1.setDuration(100); 
  movie1.setType("喜剧"); 
//这一句代码就是将一条记录存储进数据库中
movie1.save();

save()方法是有返回值的,返回true代表添加成功,返回flase代表添加失败。
save()是添加一条数据,批量添加是 LitePal.saveAll(persons);

2.删除记录
更多用法参见:LitePal的修改和删除操作

// 删除单个记录,id=1
LitePal.delete(Movie.class,1);

//删除数据库中movie表的所有记录 
LitePal.deleteAll(Movie.class); 

//删除数据库movie表中duration大于3500的记录 
LitePal.deleteAll(Movie.class, "duration > ?" , "3500"); 

3.修改记录
方法一:

//第一步,查找id为1的记录 
Movie movie = LitePal.find(Movie.class, 1); 
//第二步,改变某个字段的值 
movie.setPrice(4020f); 
//第三步,保存数据 
movie.save(); 

方法二:

Movie movie=new Movie(); 
movie.setName("2Diots"); 
movie.setDirector("某人");
 //直接更新id为1的记录 
 movie.update(1);

方法三:

Movie movie=new Movie(); 
movie.setDirector("someone"); 
//更新所有name为2Diots的记录,将director字段设为someone 
movie.updateAll("name = ?", "2Diots");

Movie movie=new Movie(); 
movie.setName("someone"); 
movie.setDirector("someone"); 
//将更新所有name为2Diots,director为gpf的记录name和director均改为someone
movie.updateAll("name=? and director=?", "2Diots""gpf");

4.查询记录
更多用法参见:LitePal的查询艺术

//查找movie表的所有记录,返回值是一个泛型为Movie的List集合
List<Movie> allMovies = LitePal.findAll(Movie.class); 

//查找movie表id为1的记录 
Movie movie = LitePal.find(Movie.class,1); 

// 比如获取news表中的第一条数据
News firstNews = LitePal.findFirst(News.class);

// 获取News表中的最后一条数据
News lastNews = LitePal.findLast(News.class);

// 想把news表中id为1、3、5、7的数据都查出来
List<News> newsList = LitePal.findAll(News.class, 1, 3, 5, 7);
// 或者
long[] ids = new long[] { 1, 3, 5, 7 };
List<News> newsList = LitePal.findAll(News.class, ids);

//查找name为2Diots的记录,并且以时长作排序,where()方法接收任意个字符串参数,其中第一个参数用于进行条件约束,
//从第二个参数开始,都是用于替换第一个参数中的占位符的。那这个where()方法就对应了一条SQL语句中的where部分。 
List<Movie> movies = LitePal.where("name = ?", "2Diots").order("duration").find(Movie.class); 
// 但是这样会将news表中所有的列都查询出来,也许你并不需要那么多的数据,而是只要title和content这两列数据。那么也很简单,我们只要再增加一个连缀就行了,如下所示:
List<News> newsList = LitePal.select("title", "content")
		.where("commentcount > ?", "0").find(News.class);
//将查询出的新闻按照发布的时间倒序排列,即最新发布的新闻放在最前面,那就可以这样写:
List<News> newsList = LitePal.select("title", "content")
		.where("commentcount > ?", "0")
		.order("publishdate desc").find(News.class);
//order()方法中接收一个字符串参数,用于指定查询出的结果按照哪一列进行排序,asc表示正序排序,desc表示倒序排序,因此order()方法对应了一条SQL语句中的order by部分。
//也许你并不希望将所有条件匹配的结果一次性全部查询出来,因为这样数据量可能会有点太大了,而是希望只查询出前10条数据,那么使用连缀同样可以轻松解决这个问题,代码如下所示:
List<News> newsList = LitePal.select("title", "content")
		.where("commentcount > ?", "0")
		.order("publishdate desc").limit(10).find(News.class);
//limit()方法接收一个整型参数,用于指定查询前几条数据,这里指定成10,意思就是查询所有匹配结果中的前10条数据。
//刚才我们查询到的是所有匹配条件的前10条新闻,那么现在我想对新闻进行分页展示,翻到第二页时,展示第11到第20条新闻,只需要再连缀一个偏移量就可以了,如下所示:
List<News> newsList = LitePal.select("title", "content")
		.where("commentcount > ?", "0")
		.order("publishdate desc").limit(10).offset(10)
		.find(News.class);
//这里指定成10,就表示偏移十个位置,那么原来是查询前10条新闻的,偏移了十个位置之后,就变成了查询第11到第20条新闻了,如果偏移量是20,那就表示查询第21到第30条新闻

//查找所有年龄小于25岁的人
List<Person> person = LitePal.where("age < ?", 25).find(Person.class); 

异步操作

默认情况下,每个数据库操作都在主线程上。如果您的操作可能花费很长时间,例如保存或查询大量记录。您可能需要使用异步操作。

Litepal支持对所有CRUD方法执行异步操作。如果您想在后台线程上查找Song表中的所有记录,请使用类似这样的代码:

// 异步查询示例
LitePal.findAllAsync(Song.class).listen(new FindMultiCallback<Song>() {
    @Override
    public void onFinish(List<Song> allSongs) {
    
    }
});

只需使用 findallasync() 代替 findall() 即可,然后调用 listen() 方法,查询一旦完成就会回调onFinish()方法。
异步保存也是类似同样的方式,如下:

Album album = new Album();
album.setName("album");
album.setPrice(10.99f);
album.setCover(getCoverImageBytes());
album.saveAsync().listen(new SaveCallback() {
    @Override
    public void onFinish(boolean success) {

    }
});

只需使用 saveAsync() 代替 save() 即可,保存成功将回调onFinish()方法。

混淆配置

-keep class org.litepal.** {
    *;
}

-keep class * extends org.litepal.crud.DataSupport {
    *;
}

-keep class * extends org.litepal.crud.LitePalSupport {
    *;
}

使用LitePal来完成升级表的操作:

包括新增一张表,新增表中的一个字段,删除表中的一个字段,删除表等,每一次的升级操作litepal.xml文件中数据库的版本号都必须加1.
具体升级操作见博客:
https://blog.csdn.net/guolin_blog/article/details/39151617

使用LitePal来建立表之间的关联关系:

在数据库中表与表之间的关联关系一共有三种类型:一对一,一对多,多对多,下面分情况讨论:

一对一:

例如新闻表News和简介表Introducation,一条新闻只能对应一条简介,同时一条简介也只能属于一条新闻。
一对一关系的体现:
在编程语言中:只需要在News类中持有一个Introduction类的引用,然后在Introduction类中也持有一个News类的引用,这样它们之间自然就是一对一的关系了:
在这里插入图片描述
就是这么简单,在News类中可以得到一个对应的Introduction的实例,那么它们之间就是一对一关系了。
在数据库表中的体现:使用外键,并且外键加在任意哪一张表上都可以。

一对多:

例如新闻表News和评论表Comment,一条新闻可以有多条评论,但是一条评论只能属于一条新闻。
一对多关系的体现:
在编程语言中:java中有List,Set等集合类来建立对象之间的一对多关系,只需要在一的一方即News类中创建一个集合类型并且泛型是Comment的成员变量即可。
在这里插入图片描述
在这里插入图片描述

在数据库表中的提现:也是使用外键,但是外键只能加在多方的表中。

多对多:

例如新闻表News和种类表Category,一条新闻可能属于不同的种类,同样的一种种类下也可以有多条新闻。
多对多关系的体现:
在编程语言中:只需要在News类中使用集合类声明拥有多个Category,然后在Category类中也使用集合类声明拥有多个News就可以了。
在这里插入图片描述
在这里插入图片描述
在数据库表中的体现:多对多关系不能使用外键来表示,必须借助于中间表,中间表主要用来存放News表和category表之间的关联关系。

针对以上表和表之间的关联关系,如果建表的时候使用SQL语句那么肯定会特别复杂,稍有不慎就有可能会出错,因此使用LitePal来自动建立表关联又是一个非常不错的选择,我们不需要关心什么外键,什么中间表等实现的细节,只需要在实体类中声明好他们之间的引用关系即可。

  • 12
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智玲君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值