前言
Litepal是一个轻型的数据库操作框架,运用ORM对象映射模型,所有的数据库操作都通过对象直接进行操作,可以大大简化数据的存储与维护过程。项目地址,传送门。
litepal导入
1.添加依赖
dependencies {
compile 'org.litepal.android:core:1.5.1'
}
2.在assets中创建litepal.xml
注意在android studio中要一定要新建一个assets文件夹,然后在里面创建名为litepal的xml文件,如果litepal.xml新建在res/raw中,则会无法识别。
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<!--
数据库名字
-->
<dbname value="demo" />
<!--
数据库的版本号
-->
<version value="1" />
<!--
要映射的实体类路径
For example:
<list>
<mapping class="com.test.model.Reader" />
<mapping class="com.test.model.Magazine" />
</list>
-->
<list>
</list>
<--
//可以选择存储数据库/内部或者外部
//默认internal -->
<storage value="external" />
</litepal>
3.配置Litepal.初始化litepal
在自己的application中加入一行代码即可
public class MyOwnApplication extends AnotherApplication {
@Override
public void onCreate() {
super.onCreate();
LitePal.initialize(this);
}
...
}
实体类创建
/**一定要继承自DataSupport*/
public class Movie extens DataSupport{
//运用注解来为字段添加index标签
//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方法
}
上面的实体类对应的数据库sql语句为
CREATE TABLE album (
//注意,不管实体类中有没有id这个属性,都会默认创建一个为整型的id字段,作为自增的主键
id integer primary key autoincrement,
name text unique default 'unknown',
cover blob,
duration integer,
director text not null,
type text
);
litepal支持的实体类字段映射类型为
int,long,double,float,byte[],boolean,String,Date;
注意不支持String[]数组型。
所有的column注解
用@column在实体类中为属性注解可以在创建数据库时为表中的字段添加字段的约束,所以这是一个非常重要的知识点,认识所有的column注解很有必要。
总共四个注解,defaultValue的默认值为空字符,所以这个注解只能用以是String类型的字段,即字符型才有默认值
public @interface Column {
/**
* Set nullable constraint for the column.
*/
boolean nullable() default true;
/**
* Set unique constraint for the column.
*/
boolean unique() default false;
/**
* Set default value with String type for the column regardless of what column type is.
*/
String defaultValue() default "";
/**
* Ignore to map this field into a column.
*/
boolean ignore() default false;
}
实体类出现名为id的字段
假如设置实体类的一个字段为id,类型是字符型,会报错么?
private String id;
现在在Movie类里加上这个字段来测试一下
结果报了如下异常
org.litepal.exceptions.DataSupportException: id type is not supported. Only int or long is acceptable for id
com.example.hapzhu.andrioddemotest W/System.err: at org.litepal.crud.DataSupport.saveThrows(DataSupport.java:1870)
com.example.hapzhu.andrioddemotest W/System.err: at org.litepal.crud.DataSupport.save(DataSupport.java:1802)
意思是如果字段名为id,类型只能为int或者long。
生成的数据库表结构
运行程序保存一条movie的数据,打开模拟器文件管理器,找到data/data/app包名下的database文件夹。
里面有一个litepal生成的数据库,后辍名.db。运用expertSqlDatabase软件查看该数据库的结构,其中movie的表结构如下图。
自定义设置id值有作用吗?
如果将id设为long或int,然后再人为设置id的值,在表中插入这一条数据时,id会被设置为自定义值吗?
Movie movie1=new Movie();
movie1.setId(1002);
movie1.setName("东成西就");
movie1.setDirector("刘镇伟");
movie1.setDuration(100);
movie1.setType("喜剧");
movie1.save();
}
保存这一条数据后,再打开数据库来查看一下movie表中新插入的记录
可以看到新插入的这条记录id不是自定义的1002,而是2,故结论就是不管一个实体类对象有没有设置id字段,数据库的表中都会创建一个id的主键,而这个id的值会在新记录插入时被自动置为表中的rowId,也即是唯一值。
数据库增删改查操作
1.存储操作
Movie movie=new Movie();
movie.setName("3Diots");
movie.setDirector("Indians");
//这一步就是将一条记录存储进数据库中
movie.save();
2.删除记录
//删除数据库中movie表的所有记录
DataSupport.deleteAll(Movie.class);
//删除数据库movie表中id为1的记录
DataSupport.deleteAll(Movie.class,1);
//删除数据库movie表中duration大于3500的记录
DataSupport.deleteAll(Movie.class, "duration > ?" , "3500");
3.修改记录
方法一
//第一步,查找id为1的记录
Movie movie = DataSupport.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");
4.查询记录
//查找movie表的所有记录
List<Movie> allMovies = DataSupport.findAll(Movie.class);
//查找movie表id为1的记录
Movie movie = DataSupport.find(Movie.class,1);
//查找name为2Diots的记录,条件查询,以时长作排序
List<Movie> movies = DataSupport.where("name = ?", "2Diots").order("duration").find(Movie.class);
5.异步操作
异步操作适用于数据量特别大的操作,可能需要比较久的时间去操作数据库,这时就可以用子线程来完成数据库操作。
注意这是1.5.1之后才添加的方法,所有增删改查都可以用异步操作,只需在方法名后拼接上async这个关键词即可。
//异步查询所有电影数据
DataSupport.findAllAsync(Movie.class).listen(new FindMultiCallback() {
@Override
public <T> void onFinish(List<T> t) {
List<Movie> allMovies= (List<Movie>) t;
}
});
//异步保存数据至数据库
movie.saveAsync().listen(new SaveCallback() {
@Override
public void onFinish(boolean success) {
}
});
建立表关联
一部电影,肯定有一个编剧,而一个编剧不止写了一部电影的剧本,那如何用litepal将它们的关系表述出来呢。
其实很简单,在实体类创建时,里面放置一个其它实体类的对象,就做到了一对一的关联,如果放置的是实体类的集合,则是一对多的关联。
例子:
创建一个编剧实体类
public class Writter extens DataSupports{
//编剧的名字
private String name;
//编剧的年龄
private int age;
//编剧写的电影剧本-有多部电影,用电影类集合关联
private List<Movie> movies;
...getter & setter
}
在movie里添加一个writter对象,来关联编剧这个表
public class Movie extens DataSupports{
//添加一个writter对象字段,来关联writter表
private Writter writter;
...getter & setter
}
原理就是在实体类中添加其它类的对象,其实就是这表中添加了一个外表的主键,这样就把它们给关联起来了。
混淆设置
-keep class org.litepal.** {
*;
}
-keep class * extends org.litepal.crud.DataSupport {
*;
}
运用sqlite命令查看数据库表结构
除了从模拟器中找到数据库文件导出后来用软件查看这个数据库的数据外,还可以用命令行来查看数据库文件。
第一步:
打开任务管理器,确保adb连接上了模拟器,在任务管理器中找到adb.exe这个进程,然后找到文件位置打开,在地址栏输入cmd进入adb.exe所在目录。
//输入命令
adb shell
PS:这个目录是逍遥模拟器的adb目录位置,出现了#表示这是超级用户,如果是$说明这是普通用户,用命令su提升权限。
第二步:
进入程序包名所有的目录,然后打开程序放置数据库的文件夹
命令行如下,我的包名为com.example.hapzhu.andrioddemotest
cd data/data/com.example.hapzhu.andrioddemotest/databases
ls
ls的作用是查看当前目录下的所有文件
第三步:
运用sqlite3命令来打开数据库
sqlite3 demo_db.db
demo_db数据库已经打开
//用该命令来查看所有数据库里的所有表
.table
可以看到用litepal创建的实体类movie生成的表格,其它两个表格都是自动生成的,忽略不计。
第四步
查看table里的所有字段列
//table_info(表名),注意一定要用冒号;结束
pragma table_info(movie);
可以看到有五个字段即这个表有五个列,但都挤成一团了,不好观察具体的字段属性。
只需换一种显示模式即可
.mode line
pragma table_info(movie);
可以看到每个字段的数据结构,notnull=0表示可以不为空=1表示不能为空;PK=1表示这是一个主键。
查找所有数据
用sql语句查询所有数据
select * from movie;
一共储存了三条数据,显示乱码的是中文