Android数据库:Litepal性能分析及使用中遇到的坑

教程的话当然是去郭神的官方csdn了

总结一下使用经验

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;
    }
}

发布了72 篇原创文章 · 获赞 28 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/changhuzichangchang/article/details/88557647