总结一下使用经验
20190705 更新
1、Litepal布尔类型存储
在litepal中,boolean的默认值是false,当你设置为true时,可以使用,但是当赋值为false时,需要使用setToDefault()方法。如果不使用这种方式,更新不会成功。
当然int类型也一样如此。郭婶原话是:
1、首先是郭神的这个教程,只到2.0。但是现在已经litepal已经3.0了
3.0的文档
3.0主要是有了一个数据库更新时的一个监听
我在使用这个功能的时候遇到了一个这个问题getDatabase called recursively
2、litepal目前不支持建立索引
我观察了一下数据库的字段,发现每张表被建立的时候会建一个唯一索引(id)
3、关联表的数据插入
划重点,建立一对一关联后,首先你要记得,把关联表的数据save!!并不是你直接把数据set赋值之后,关联表就有数据了。set只是给两个表建立关联的啊懂。我搞了好久才发现这个惊天大秘密~~。下面提供模板
News news=new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.setPublishDate(new Date());
Introduction introduction=new Introduction();
introduction.setGuide("这是新闻导语");
introduction.setDigest("这是新闻摘要");
news.setIntroduction(introduction);//只是建立关联
introduction.save();//重点
news.save();
4、关联表的查询
郭神提供了激进查询,去查询关联表,传送门
但是这种激进查询的方法不支持–>迭代查询关联表的关联表数据。
郭神建议大家还是使用默认的懒加载,使用方式同样点击刚刚那个那个传送门
这种方式呢,如果想–>迭代查询关联表的关联表数据–>就很傻了
之所以说它懒呢,是因为比如你有三张表:新闻,新闻简介,新闻简介的作者。从名字可以看出这三张表是一层套一层的。当你一开始去查第一张表(新闻)的数据时,你会发现取到的数据里,新闻简介对象是空的。你想要获取新闻简介的数据,你就必须, news.getIntroduction()。在getIntroduction()方法里面呢是根据关联id去查询对应新闻简介。
这种情况你直接用激进查询的话其实更容易实现。
但是呢,激进查询不支持二级以上不是。于是懒查询的方式你想获得一个完整的对象,你需要一步步把数据查出来,再set回去。
三表联查:
News news=DBManager.getInstance().queryNews();
Introduction introduction = news.getIntroduction();
IntroductionAuthor author=introduction.getIntroductionAuthor();
List<Comment> commentList=news.getCommentList();
introduction.setIntroductionAuthor(author);
news.setIntroduction(introduction);
news.setCommentList(commentList);
很蠢的操作
5、我不想用那么蠢的方式,因为我现在要用的对象,是一个十级左右的嵌套。。。
所以我只能把这个对象转成jsonString然后作为一个字段传进去,而不是关联表的方式
但是这也很蠢,因为一个对象被序列化成字符串再从字符创序列化成对象,很耗费性能
所以呢,现在,我要去测试一下,这种办法性能如何。
好了,性能测试出来了。当然啦,蠢办法测试
性能分析
这份测试结果,包含了我的业务逻辑,其中存储包括序列化对象,查询包括取出之后反序列化成对象。等等的基础上的测试结果,并不代表litepal的性能。总结就是查询出一个size为1001的对象列表需要3秒左右。此方案可行。
测试代码
首先一个对象jsonstring的大小为
{
"closed": false,
"createTime": 1551856765000,
"customerCount": 1,
"deviceUuid": "POS",
"discountTotal": 0.0,
"isBlock": false,
"isCancelled": false,
"isPaid": true,
"isPrinted": false,
"menuTotal": 1.0,
"openTime": 1551856765000,
"orderNumber": "1903061024011001630",
"orderPromotionBlocks": [],
"orderPromotions": [],
"orderSource": 2,
"orderTotal": 1.0,
"orderTransactions": [{
"beginTime": 1551856767000,
"deviceUuid": "POS",
"discountTotal": 0.0,
"isSynced": false,
"menuTotal": 1.0,
"orderNumber": "1903061024011001630",
"orderTransactionDetails": [{
"addTime": 1551856762000,
"detailNumber": "19030615192510924011995377",
"detailTargetName": "打包盒",
"detailTargetNumber": "1604",
"detailType": "M",
"isPrinted": false,
"isVoid": false,
"isWeight": false,
"orderNumber": "1903061024011001630",
"parentDetailNumber": "",
"prepared": false,
"quantity": 1,
"seq": 1,
"status": 1,
"storeNumber": "1040104024",
"totalPrice": 1.0,
"transactionNumber": "190306102401100163",
"unitPrice": 1.0,
"weightQuantity": 0.0
}],
"seq": 1,
"status": 3,
"storeNumber": "1040104024",
"submitTime": 1551856767000,
"transactionNumber": "190306102401100163",
"transactionTotal": 1.0,
"transactionType": 0
}],
"outChannel": "",
"outSeq": 0,
"paymentInfos": [{
"amount": 1.0,
"orderNumber": "1903061024011001630",
"paymentTime": 1552547967000,
"paymentmethodAction": "cash"
}],
"paymentTime": 1552547967000,
"printType": 0,
"seq": 100163,
"serviceChargeTotal": 0.0,
"status": 1,
"storeNumber": "1040104024",
"tableNumber": "1",
"timePeriodNumber": "TP004",
"transType": 1
}
MainActivity.class
ThreadManger.get().add(new ThreadListener() {
@Override
public void doAction() throws Exception {
Long beginTime=new Date().getTime();
for (int i=0;i<1000;i++){
OrderManager.getInstance().getPos(i);
}
Long endTime=new Date().getTime();
long time=(beginTime-endTime);
LogManager.get().getLogger(HomeActivity.class).info("1001单插入耗费时间"+time);
Long beginTime1=new Date().getTime();
ArrayList<IOrder> orders=OrderManager.getInstance().loadOrder();
Long endTime1=new Date().getTime();
long time1=(beginTime1-endTime1);
LogManager.get().getLogger(HomeActivity.class).info(orders.size()+"单查询耗费时间"+time1);
Long beginTime2=new Date().getTime();
IOrder order=OrderManager.getInstance().getOrderByNumbers("19030610240110016325");
Long endTime2=new Date().getTime();
long time2=(beginTime2-endTime2);
LogManager.get().getLogger(HomeActivity.class).info(order.getOrderNumber()+"单查询指定订单耗费时间"+time2);
Long beginTime3=new Date().getTime();
IOrder order3=OrderManager.getInstance().getOrderByNumbers("190306102401100163888");
Long endTime3=new Date().getTime();
long time3=(beginTime3-endTime3);
LogManager.get().getLogger(HomeActivity.class).info(order3.getOrderNumber()+"单查询指定订单耗费时间"+time3);
}
});
public void getPos(int i){
String msg="{\"orderNumber\":\"190306102401100163"+i+"\",\"timePeriodNumber\":\"TP004\",\"seq\":\"100163\",\"storeNumber\":\"1040104024\",\"people\":1,\"openTime\":\"2019-03-06 15:19:25\",\"menuTotal\":1.00,\"orderTotal\":1.00,\"discountTotal\":0.0,\"transType\":1,\"reservation\":false,\"reservationTime\":\"\",\"tableNumber\":\"1\",\"outChannel\":\"\",\"outSeq\":0,\"transactions\":[{\"transactionNumber\":\"190306102401100163\",\"beginTime\":\"2019-03-06 15:19:27\",\"submitTime\":\"2019-03-06 15:19:27\",\"details\":[{\"detailNumber\":\"19030615192510924011995377\",\"seq\":1,\"addTime\":\"2019-03-06 15:19:22\",\"detailType\":\"M\",\"parentDetailNumber\":\"\",\"quantity\":1.00,\"unitPrice\":1.00,\"totalPrice\":1.0000,\"detailTargetNumber\":\"1604\",\"detailTargetName\":\"打包盒\"}]}],\"deliveryInfo\":[],\"payments\":[{\"amount\":1.00,\"paymentMethodAction\":\"cash\",\"paymentTime\":\"2019-03-14 15:19:27\",\"outterTraxNo\":\"\"}]}";
// 组装返回数据
OrderResponseEntity orderResponseEntity;
try {
orderResponseEntity = JSON.parseObject(msg, OrderResponseEntity.class);
} catch (Exception e) {
cn.tedia.core.util.Log.w("RPCService", "收到订单接口数据,订单数据反序列化失败");
LogManager.get().getLogger(getClass()).info("收到order接口数据,order数据反序列化失败", e);
return ;
}
// 转换
IOrder order = OrderManager.getInstance().getOrderByPOSEntity(orderResponseEntity);
if (order == null) {
cn.tedia.core.util.Log.w("RPCService", "收到订单接口数据,转换订单数据失败");
LogManager.get().getLogger(getClass()).info("收到order接口数据,转换成order数据失败");
return;
}
// 保存订单
if (!OrderManager.getInstance().addPOSOrderToDB(order)) {
cn.tedia.core.util.Log.w("RPCService", "收到订单接口数据,订单数据保存失败");
LogManager.get().getLogger(getClass()).info("收到order接口数据,order数据保存失败");
return ;
}
// 组装返回数据
return;
}
查询全部订单
OrderManager.class
/**
* 加载本地所有没有关单的订单
*/
public ArrayList<IOrder> loadOrder() {
ArrayList<IOrder> orderList = orderController.getOrderByDateAndNotClosed(new Date());
return orderList;
}
public ArrayList<IOrder> getOrderByDateAndNotClosed(Date date) {
OrderDBModel orderDBModel = OrderManager.getInstance().getOrderDBModel();
if (orderDBModel == null) {
return null;
}
ArrayList<String> orderStringList = orderDBModel.getOrderByDateAndNotClosed(date);
if (orderStringList == null) {
return null;
}
ArrayList<IOrder> data = new ArrayList<>();
for (int i = 0; i < orderStringList.size(); i++) {
data.add(JSON.parseObject(orderStringList.get(i), IOrder.class));
}
return data;
}
查询指定订单
OrderManager.class
/**
* 加载本地所有没有关单的订单
*/
public IOrder getOrderByNumbers(String s) {
IOrder orderList = orderController.getOrderByNumber(s);
return orderList;
}
public IOrder getOrderByNumber(String orderNumber) {
OrderDBModel orderDBModel = OrderManager.getInstance().getOrderDBModel();
if (orderDBModel == null) {
return null;
}
String data = orderDBModel.getOrder(orderNumber);
try {
return JSON.parseObject(data, IOrder.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
以上
最后
放一下我的demo,详细源码可以去我的GitHub上找,但是吧,我一般做测试都在这个项目,所以非常乱,不建议去
OrderDBModel.class
package com.example.pc.testeverything.SqliteManager.litepalmanager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.tiidian.log.LogManager;
import com.tiidian.threadmanager.ThreadListener;
import com.tiidian.threadmanager.ThreadManger;
import org.litepal.LitePal;
import org.litepal.tablemanager.Connector;
import org.litepal.tablemanager.callback.DatabaseListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* Created by skyshi on 2019/2/18.
*/
public class DBModel {
public DBModel() {
LitePal.registerDatabaseListener(new DatabaseListener() {
@Override
public void onCreate() {
LogManager.get().getLogger(LogManager.class).info("数据库操作:创建数据库");
}
@Override
public void onUpgrade(int oldVersion, int newVersion) {
ThreadManger.get().add(new ThreadListener() {
@Override
public void doAction() throws Exception {
try {
//更新数据库时的一些其他操作
} catch (Exception e) {
e.printStackTrace();
LogManager.get().getLogger(LogManager.class).error("数据库操作:版本更新出现异常", e);
}
}
});
LogManager.get().getLogger(LogManager.class).info("数据库操作:版本更新:" + oldVersion + "版本更新到" + newVersion + "版本");
}
});
SQLiteDatabase db = Connector.getDatabase();
}
/**
* 保存新闻数据
*
* @param news
* @return
*/
public boolean save(News news) {
if (news == null) {
return false;
}
//根据news的唯一标识(新闻号)查询
List<News> newsList = LitePal.where("newsNumber= ?", news.getNewsNumber()).find(News.class);
boolean result = false;
//已经存在做更新操作
if (newsList != null && newsList.size() > 0) {
int affectedRows = news.updateAll("newsNumber = ?", news.getNewsNumber());
if (affectedRows > 0) {
result = true;
}
} else {
//不存在做插入操作
result = news.save();
}
return result;
}
/**
* 根据新闻号获取指定新闻
*
* @param newsNumber
* @return
*/
public List<News> getNews(String newsNumber) {
if (TextUtils.isEmpty(newsNumber)) {
return null;
}
List<News> newsList = LitePal.where("newsNumber= ?", newsNumber).find(News.class);
return newsList;
}
/**
* 获取不是今天并且标题为“郭神”的新闻列表
*
* @return
*/
public List<News> getNewsNotTodayAndAboutGuoShen() {
List<News> newsList = LitePal.where("title= ? and publishDay <> ?", "郭神威武", getDayDate(new Date())).find(News.class);
if (newsList == null) {
return null;
}
return newsList;
}
/**
* 根据新闻发布日期查找新闻
*
* @param publishDay 发布日期
* @return
*/
public List<News> getNewsByDate(Date publishDay) {
List<News> newsList = LitePal.where("publishDay= ?", getDayDate(publishDay)).find(News.class);
if (newsList == null) {
return null;
}
return newsList;
}
/**
* 获取开单日期
*
* @param date
* @return
*/
private String getDayDate(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(date);
}
/**
* 根据id更新新闻标题
*
* @param id
* @return
*/
public boolean syncNewsTitle(int id) {
News news = new News();
news.setTitle("郭神威武");
int affectedRows = news.updateAll("id = ?", String.valueOf(id));
if (affectedRows > 0) {
return true;
}
return false;
}
/**
* 获取News表的数据量
*
* @return
*/
public int getNewsCount() {
List<News> News = LitePal.select("id").find(News.class);
return News.size();
}
/**
* 获取News表的最大ID
*
* @return
*/
public int getNewsMaxId() {
Cursor cursor = LitePal.findBySQL("select max(id) as id from News");
int id = 0;
if (cursor.moveToFirst()) {
do {
id = cursor.getInt(cursor.getColumnIndex("id"));
} while (cursor.moveToNext());
}
return id;
}
/**
* 删除某个日期之前的新闻
*
* @return
*/
public boolean deleteNewsByDay(Date publishDay) {
int affectedRows = LitePal.deleteAll(News.class, "publishDay < ?", getDayDate(publishDay));
boolean result = false;
if (affectedRows > 0) {
result = true;
}
return result;
}
/**
* 删除某个时间之前的新闻
*
* @return
*/
public boolean deleteNewsByDate(Long updateTime) {
int affectedRows = LitePal.deleteAll(News.class, "publishDate < ?", String.valueOf(updateTime));
boolean result = false;
if (affectedRows > 0) {
result = true;
}
return result;
}
/**
* 根据新闻号删除指定新闻
*
* @param newsNumber
*/
public boolean deleteNews(String newsNumber) {
int affectedRows = LitePal.deleteAll(News.class, "newsNumber = ?", newsNumber);
boolean result = false;
if (affectedRows > 0) {
result = true;
}
return result;
}
}