欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android—LitePal操作数据库

程序员文章站 2022-06-01 21:11:11
...

简介

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对应项目文件目录,如下
Android—LitePal操作数据库
输入 ls 查看数据库是否被创建
Android—LitePal操作数据库
接下来输入 sqlite3 BookStore.db 进入到数据库
Android—LitePal操作数据库
输入 .schema查看建表语句
Android—LitePal操作数据库
当我们升级数据库时,我们需要把之前的表 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
Android—LitePal操作数据库
 

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

    }
相关标签: Android android