Android—LitePal操作数据库
Android—LitePal操作数据库
简介
LitePal 是一款 Android 数据库框架,它采用了对象关系映射(ORM)的模式。
Demo下载
LitePal 的GitHub地址:https://github.com/LitePalFramework/LitePal
LitePal Demo 的个人GitHub地址:https://github.com/linweimao/LitePal
LitePal Demo 百度网盘链接:https://pan.baidu.com/s/1qgLFDMDPjBl6uSxCP0ovPQ
提取码:rvkv
LitePal采用的是对象关系映射(ORM)模式,那么什么是对象关系映射呢?
简单来说,我们使用的编程语言是面向对象语言,而使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射。
框架步骤
配置 LitePal
编辑app/build.gradle文件,在 dependencies 闭包中添加如下内容:
implementation 'org.litepal.android:java:3.0.0'
新建 assets 文件夹与创建 litepal.xml 文件
assets 文件夹的创建方式:右击app/src/main 目录—New—Directory,创建一个 assets 目录,然后在 assets 目录下新建一个 litepal.xml 文件,litepal.xml 的文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="BookStore"></dbname>
<version value="2"></version>
<list>
<mapping class="com.lwm.litepaltest.Book"></mapping>
<mapping class="com.lwm.litepaltest.Category"></mapping>
</list>
</litepal>
dbname标签用于指定数据库名
version 标签用于指定数据库版本号
dbname标签用于指定所有的映射模型
配置 AndroidManifest.xml
将下面的代码添加到 <application 下
android:name="org.litepal.LitePalApplication"
此时 LitePal 的配置工作全部完成。
创建和升级数据库
定义一个 Book 类和 Category 类
public class Book {
private int id;
private String author;
private double price;
private int pages;
private String name;
private String press;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
}
public class Category {
private int id;
private String categoryName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
以上是典型的Java bean,Book 类对应数据库中的 Book 表,而类中的每一个字段分别对应了表中的每一个列,这就是对象关系映射最直观的体验
将 Book 类和 Category 类添加到映射模型列表
在 litepal.xml 进行修改,由于上面我们已经将Book 类和 Category 类添加到映射模型列表所以不用再进行添加了。
<mapping class="com.lwm.litepaltest.Book"></mapping>
<mapping class="com.lwm.litepaltest.Category"></mapping>
这里使用 mapping 标签来声明我们要配置的映射模型类,注意一定要使用完整的类名,不管有多少模型类需要映射,都使用同样的方式配置在 lite 标签下
创建数据库
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LitePal.getDatabase();
}
});
调用 LitePal.getDatabase(); 方法就是一次最简单的数据库操作,只要点击一下按钮,数据库就会自动创建完成
查看数据库是否被创建(查看的时候记得运行模拟器)
win+R输入cmd
在窗口输入 adb shell
输入 su 切换模式为超级管理员,这时你可以访问模拟器中的一切数据,如果你的命令行上显示的是 $ 符号,那么就表示你现在是普通管理员。
如果输入 su 报 /system/bin/sh: su: not found 错误,那么你可以参考https://blog.csdn.net/weixin_42814000/article/details/104994222
在输入 ==cd /data/data/com.lwm.litepaltest/databases/==进到数据库下
注意:com.lwm.litepaltest对应项目文件目录,如下
输入 ls 查看数据库是否被创建
接下来输入 sqlite3 BookStore.db 进入到数据库
输入 .schema查看建表语句
当我们升级数据库时,我们需要把之前的表 drop 掉,然后在重新创建,这其实是一个非常严重的问题,因为这样会造成数据丢失,每当升级一次数据库,之前表中的数据就全没了,在使用 LitePal 时如果要升级数据库,只用将版本号加 1 就可以了(修改 assets 的 litepal.xml 文件的 version 标签),此时 LitePal 会自动保留之前表中的所有数据
LitePal 添加数据
LitePal 添加数据的方式:创建模型类的实例,在将所有要存储的数据设置好,最后调用一下 save() 方法就可以了
LitePal 进行表管理操作时不需要模型类有任何的继承结构,但是进行CRUD 操作时就不行了,需要继承自 LitePalSupport 类才行。
public class Book extends LitePalSupport {
private int id;
private String author;
private double price;
private int pages;
private String name;
private String press;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
}
开始向 Book 表中添加数据。
// 添加数据
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setName("The Da Vinci Code");
book.setAuthor("Dan Brown");
book.setPages(454);
book.setPrice(16.96);
book.setPress("Unknow");
book.save();
}
});
首先创建出一个 Book 实例,然后调用 Book 类中的各种 set 方法对数据进行设置,最后在调用 book.save(); 方法就能完成数据添加操作了。
重新运行程序,点击一下 Add data 按钮,此时数据应该已经添加成功了,输入SQL查询语句 select * from Book
LitePal 更新数据
首先最简单的更新方式就是对已存储的对象重新设值,然后重新调用 book.save(); 方法即可
什么是已存储对象呢?
对于 LitePal 来说,对象是否已存储就是根据调用 model.isSaved( ) 方法的结果来判断的,返回 true 就表示已存储,返回 false 就表示未存储。那么接下来的问题就是,什么情况下会返回 true ,什么情况会返回 false 呢?
实际上只有在两种情况下 model.isSaved( ) 方法才会返回 true ,一种情况是已经调用过 model.save() 方法去添加数据,此时 model 会被认为是已存储的对象。另一种情况是 model 对象是通过 LitePal 提供的查询 API 查出来的,由于是从数据库中查到的对象,因此也会被认为是已存储的对象。
这种更新方式只能对已存储的对象进行操作,限制性比较大
// 这种更新方式只能对已存储的对象进行操作,限制性比较大
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setName("The Lost Symbol");
book.setAuthor("Dan Brown");
book.setPages(510);
book.setPrice(19.95);
book.setPress("Unknow");
book.save();
book.setPrice(10.99);
book.save();
}
});
比较灵巧的更新方式
// 比较灵巧的更新方式
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setPrice(14.95);
book.setPress("Anchor");
book.updateAll("name=? and author = ?", "The Lost Symbol", "Dan Brown");
book.save();
}
});
在使用 updateAll( ) 方法时,还有一个非常重要的知识点是你需要知晓的
当你想把一个字段的值更新成默认值时,是不可以使用上面的方式来 set 数据的。在 Java 中任何一种数据类型的字段都会有默认值,例如 int 类型的默认值是 0 ,boolean 类型的默认值是 false, String 类型的默认值是 null 。那么当 new 出一个 Book 对象时,其实所有的字段都已经被初始化成默认值了,比如说 pages 字段的值就是 0 。因此,如果我们想把数据库表中的 pages 列更新为 0 ,直接调用 book.setPages(0); 是不可以的,因此即使不调用这行代码,pages 字段本身也是 0 ,LitePal 此时是不会对这个列进行更新的。对于所有想要将为数据更新成默认值的操作,LitePal 统一提供了一个 setToDefault( ) 方法,然后传入相应的列名就可以实现了。
// 将某个字段的数据更新为默认值(例如:int的默认值为0 , boolean的默认值为false , String的默认值为null)
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setToDefault("pages");
book.updateAll();
}
});
这个代码的意思是,将所有书的页数都更新为 0 ,因为 updateAll( ) 方法中没有指定约束条件,因此更新操作对所有数据都生效。
LitePal 删除数据
// 删除数据
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LitePal.deleteAll(Book.class, "price < ?", "15");
}
});
这里调用了 LitePal.deleteAll( ); 方法来删除数据,其中的 deleteAll( ) 方法的第一个参数用于指定删除哪张表中的数据,Book.class 就意味着删除 Book 表中的数据,后面的参数用于指定约束条件。这行代码的意思是:删除 Book 表中价格低于 15 的书。
如果 deleteAll( ) 方法如果不指定约束条件,那么就是要删除表中所有的数据,这一点和 updateAll( ) 方式是相似的。
LitePal 查询数据
查询 Book 表中的所有数据。
List<Book> books = LitePal.findAll(Book.class);
只需要调用一下 findAll( ) 方法,然后通过 Book.class 参数指定查询 Book 表就可以。另外,findAll( ) 方法的返回值是一个 Book 类型的 List 集合,LitePal 已经自动帮我们完成了赋值操作了。
public void query() {
// 打印查询到的数据
queryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 查询 Book 表的所有数据,
// 与 Cursor cursor = db.query("Book",null,null,null,null,null,null);功能一样
// findAll() 方法通过 Book.class 参数指定查询 Book 表,
// 另外, findAll() 方法的返回值实体个 Book 类型的List 集合,也就是说 LitePal 自动帮我们完成了赋值操作
List<Book> books = LitePal.findAll(Book.class);
for (Book book : books) {
Log.d(TAG, "book name is: " + book.getName());
Log.d(TAG, "book author is: " + book.getAuthor());
Log.d(TAG, "book pages is: " + book.getPages());
Log.d(TAG, "book price is: " + book.getPrice());
Log.d(TAG, "book press is: " + book.getPress());
}
}
});
// 打印第一条数据
queryData1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book firstBook = LitePal.findFirst(Book.class);
Log.d(TAG, "book name is: " + firstBook.getName());
Log.d(TAG, "book author is: " + firstBook.getAuthor());
Log.d(TAG, "book pages is: " + firstBook.getPages());
Log.d(TAG, "book price is: " + firstBook.getPrice());
Log.d(TAG, "book press is: " + firstBook.getPress());
}
});
// 打印最后一条数据
queryData2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book lastBook = LitePal.findLast(Book.class);
Log.d(TAG, "book name is: " + lastBook.getName());
Log.d(TAG, "book author is: " + lastBook.getAuthor());
Log.d(TAG, "book pages is: " + lastBook.getPages());
Log.d(TAG, "book price is: " + lastBook.getPrice());
Log.d(TAG, "book press is: " + lastBook.getPress());
}
});
// select() 方法用于指定查询哪几列,对应了 SQL中的 select 关键字。查询name和author两列的数据
queryData3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.select("name", "author").find(Book.class);
Log.d(TAG, "book name is: " + books.get(0).getName());
Log.d(TAG, "book author is: " + books.get(0).getAuthor());
}
});
// where() 方法用于指定查询的约束条件,对应了SQL当中的where关键字。比如查询页数大于400的数据
queryData4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.where("pages > ?", "400").find(Book.class);
Log.d(TAG, "book name is: " + books.get(0).getName());
Log.d(TAG, "book author is: " + books.get(0).getAuthor());
Log.d(TAG, "book pages is: " + books.get(0).getPages());
Log.d(TAG, "book price is: " + books.get(0).getPrice());
Log.d(TAG, "book press is: " + books.get(0).getPress());
}
});
// order() 方法用于指定结果的排序方式,对应了SQL中的 order by关键字。比如将查询结果按照书价格从高到底进行排序
queryData5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.order("price desc").find(Book.class);
for (Book book : books) {
Log.d(TAG, "book name is: " + book.getName());
Log.d(TAG, "book author is: " + book.getAuthor());
Log.d(TAG, "book pages is: " + book.getPages());
Log.d(TAG, "book price is: " + book.getPrice());
Log.d(TAG, "book press is: " + book.getPress());
}
}
});
// limit() 方法用于指定查询结果的数量
queryData6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.limit(3).find(Book.class);
Log.d(TAG, "book name is: " + books.get(0).getName());
Log.d(TAG, "book author is: " + books.get(0).getAuthor());
Log.d(TAG, "book pages is: " + books.get(0).getPages());
Log.d(TAG, "book price is: " + books.get(0).getPrice());
Log.d(TAG, "book press is: " + books.get(0).getPress());
}
});
// offset() 方法用于指定查询结果的偏移量
queryData7.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.limit(3).offset(1).find(Book.class);
Log.d(TAG, "book name is: " + books.get(0).getName());
Log.d(TAG, "book author is: " + books.get(0).getAuthor());
Log.d(TAG, "book pages is: " + books.get(0).getPages());
Log.d(TAG, "book price is: " + books.get(0).getPrice());
Log.d(TAG, "book press is: " + books.get(0).getPress());
}
});
// 连缀组合查询
queryData8.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = LitePal.select("name", "author", "pages")
.where("pages > ?", "400")
.order("pages")
.limit(10)
.offset(10)
.find(Book.class);
for (Book book : books) {
Log.d(TAG, "book name is: " + book.getName());
Log.d(TAG, "book author is: " + book.getAuthor());
Log.d(TAG, "book pages is: " + book.getPages());
Log.d(TAG, "book price is: " + book.getPrice());
Log.d(TAG, "book press is: " + book.getPress());
}
}
});
// 使用原生SQL查询
queryData9.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Cursor cursor = LitePal.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");
if (cursor.moveToFirst()) {
do {
// 遍历 Cursor 对象,取出数据并打印
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("name"));
String press = cursor.getString(cursor.getColumnIndex("name"));
Log.d(TAG, "book name is: " + name);
Log.d(TAG, "book author is: " + author);
Log.d(TAG, "book pages is: " + pages);
Log.d(TAG, "book price is: " + price);
Log.d(TAG, "book press is: " + press);
} while (cursor.moveToNext());
}
cursor.close();
}
});
}