Android之SQLite数据库学习

1,192 阅读9分钟

(一)使用Android原生API

1. 介绍

  • SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎,它是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式的,而且由于其占用资源低(占用内存只需几百K)、处理速度快等特点,目前许多嵌入式产品中都使用了它,其中就包括大名鼎鼎的iOS和Android移动操作系统。SQLite能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月, 至今已经有14个年头,现在SQLite也迎来了一个版本 SQLite 3已经发布。SQLite的特点大致总结如下:

    • 1.轻量级

    使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸想当小。

    • 2.独立性

    SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。

    • 3.隔离性

    SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。

    • 4.跨平台

    SQLite 目前支持大部分操作系统,不至电脑操作系统更在众多的手机系统也是能够运行,比如:Android和IOS。

    • 5.多语言接口

    SQLite 数据库支持多语言编程接口。

    • 6.安全性

    SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。

  • 要想了解更多有关SQLite数据库相关的历史、特点及命令操作,可以学习以下两个网站的资源:

    • http://www.sqlite.org/lang.html

    • http://www.w3cschool.cc/sqlite/sqlite-intro.html


2. 使用adb shell对数据库和表的创建情况进行检查

配置环境

adb是Android SDK中自带的一个调式工具,它存放在sdkplatform-tools目录下,如果想在命令行中使用这个工具,就需要先把它的路径配置到环境变量中。

  • windows系统下配置,(如果你们的系统是MAC或Linux系统,请自行百度

    • 1.找到sdk下的platform-tools文件夹路径。

    • 2.将路径配置到Path

    • 3.配置好环境变量之后,就可以使用adb工具了。打开命令行界面(如果是夜神模拟器看下面截图步骤)输入adb shell就会进入设备的控制台。

3. 创建数据库(解释都在注释中)

MyDatabaseHelper类需要继承SQLiteOpenHelper类

public class MyDatabaseHelper extends SQLiteOpenHelper {

    // 创建表
    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement,"
            + "author text,"
            + "price real,"
            + "pages integer,"
            + "name text)";

    private Context mContext;


    /**
     * 在继承SQLiteOpenHelper这个类的时候有两个构造函数可供重写,一般使用参数少一点的那个构造方法即可。
     * <p>
     * 第一个参数:Context上下文
     * 第二个参数:数据库的名字,创建数据库时使用的就是这里指定的名称
     * 第三个参数:允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null
     * 第四个参数:当前数据库的版本号
     *
     * @param context
     * @param name
     * @param factory
     * @param version
     */
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

        sqLiteDatabase.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "创建成功!", Toast.LENGTH_SHORT).show();

    }

 
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

MainActivity

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper mDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mDbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

        Button createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                /**
                 * getWritableDatabase()和getReadableDatabase()方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否咋创建一个新的数据库)并返回一个可对数据库进行读写操作的对象。
                 *      不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,
                 *                                               getWritableDatabase()方法则将出现异常。
                 *
                 *  数据库的文件会存放到/data/data/<package name>/database/目录下
                 *
                 */

                mDbHelper.getWritableDatabase();
            }
        });

    }
}

4. 升级数据库

MyDatabaseHelper类中添加下面的代码

public class MyDatabaseHelper extends SQLiteOpenHelper {

    // 创建表
    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement,"
            + "author text,"
            + "price real,"
            + "pages integer,"
            + "name text)";

    public static final String CREATE_CATEGORY = "create table Category("
            + "id integer primary key autoincrement,"
            + "category_name text,"
            + "category_code integer)";


    private Context mContext;


    /**
     * 在继承SQLiteOpenHelper这个类的时候有两个构造函数可供重写,一般使用参数少一点的那个构造方法即可。
     * <p>
     * 第一个参数:Context上下文
     * 第二个参数:数据库的名字,创建数据库时使用的就是这里指定的名称
     * 第三个参数:允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null
     * 第四个参数:当前数据库的版本号
     *
     * @param context
     * @param name
     * @param factory
     * @param version
     */
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

        sqLiteDatabase.execSQL(CREATE_BOOK);
        sqLiteDatabase.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext, "创建成功!", Toast.LENGTH_SHORT).show();

    }

    /**
     * onUpgrade()方法进行数据库升级
     *
     * @param sqLiteDatabase
     * @param i
     * @param i1
     */
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // 如果发现数据库中已经存在Book表或Category表了,就将这两张表删除掉,然后再调用onCreate()方法重新创建
        // 如果不添加下面两行语句,在运行程序的时候会报错
        sqLiteDatabase.execSQL("drop table if exists Book");
        sqLiteDatabase.execSQL("drop table if exists Category");
        onCreate(sqLiteDatabase);
    }
}

MainActivity

**只需要 new MyDatabaseHelper(this, "BookStore.db", null, 2);改变最后一个参数(version),之前我们传入的是1,现在只要传入一个比1大的数就行,既可以让onUpgrade()方法得到执行了 **


5. CRUD

添加数据

主要使用了ContentValues对象,使用insert()方法,在MainActivity中添加以下代码

Button addData = findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = mDbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name", "WangXiaoNao");
                values.put("author", "Tom");
                values.put("pages", 454);
                values.put("price", 20.22);
                // 插入第一条数据
                // insert():方法,它接受3个参数,
                //             第一个参数:表名。
                //             第二个参数:用于未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到,直接传入null
                //             第三个参数:是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
                db.insert("Book", null, values);
                values.clear();
                // 开始组装第二条数据
                values.put("name", "WangDaNao");
                values.put("author", "Amry");
                values.put("pages", 520);
                values.put("price", 12.11);
                db.insert("Book", null, values);
            }
        });

更新数据

使用update()方法,在MainActivity中添加以下代码

SQLiteDatabase db1 = mDbHelper.getWritableDatabase();
                ContentValues values1 = new ContentValues();

                values1.put("price", 10.99);
                /*
                 update()方法:
                        第一个参数:指定的表名
                        第二个参数:是ContentValues对象
                        第三个参数:对应的是SQL语句的where语句,表示更新所有name等于?的行,而?是一个占位符
                        第四个参数:提供一个字符串数组为第三个参数中的每个占位符指定相应的内容。

                 */
                db1.update("Book", values1, "name = ?", new String[]{"WangXiaoNao"});

删除数据

使用delete()方法,在MainActivity中添加以下代码

SQLiteDatabase db2 = mDbHelper.getWritableDatabase();
                /*
                delete()方法:
                        第一个参数:表名
                        第二个参数、第三个参数:第二个参数相当于sql语句的where。第三个值相当于where的值。
                        用于约束删除某一行或某几行的数据,不指定的话默认就是删除所有行。
                 */
                db2.delete("Book", "pages > ?", new String[]{"500"});

查询数据

使用query()方法,在MainActivity中添加以下代码

SQLiteDatabase db3 = mDbHelper.getWritableDatabase();
                // 查询Book表中所有的数据
                Cursor cursor = db3.query("Book", null, null, null, null, null, null);

                //  moveToFirst()方法将数据的指针移动到第一行的位置,然后进入了一个循环当中,去遍历查询到每一行的数据
                if (cursor.moveToFirst()) {
                    do {
                        // 遍历Cursor对象,取出数据并打印
                        // Cursor的getColumnIndex()方法获取到某一列在表中对应的位置索引,然后将这个索引传入到相应的取值方法中,就可以得到数据库中的读取到的数据了
                        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("price"));

                        Log.d(TAG, "name = " + name + " " + "author = " + author + " " + "pages = " + pages + " "+ "price = " + price );

                    } while (cursor.moveToNext());

                }
                // 注意:最后一定调用close()方法
                cursor.close();
  • query()方法中7个参数的含义:


(二)使用LitePal

LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式。

LitePal使用

配置LitePal

  • 添加依赖

      compile 'org.litepal.android:core:1.3.2'
    
  • 在app/src/main下创建一个名为assets的Directory,在assets目录下创建一个litepal.xml文件

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <!--<dbname>标签用于指定数据库名-->
    <dbname value="BookStore"></dbname>
    <!--<version>标签用于指定数据版本号-->
    <version value="1"></version>
    <!--<list>标签用于指定所有的映射类型-->
    <list>
        <mapping class="com.wzg.litepaltest.Book"></mapping>
        <mapping class="com.wzg.litepaltest.Category"></mapping>
    </list>
</litepal> 

Book类,主要要继承DataSupport

public class Book extends DataSupport{

    private int id;
    private String author;
    private double price;
    private int pages;
    private String name;
    private String press;



    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = 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;
    }
}

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button createDatabase = findViewById(R.id.create_database);
        createDatabase.setOnClickListener(this);

        Button addData = findViewById(R.id.add_data);
        addData.setOnClickListener(this);

        Button updateData = findViewById(R.id.update_data);
        updateData.setOnClickListener(this);

        Button deleteData = findViewById(R.id.delete_data);
        deleteData.setOnClickListener(this);

        Button queryData = findViewById(R.id.query_data);
        queryData.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.create_database:
                // 创建数据库
                Connector.getDatabase();

                break;
            // 添加数据
            case R.id.add_data:
                Book book = new Book();
                book.setName("The Da Vinci Code");
                book.setAuthor("Dan Brown");
                book.setPages(454);
                book.setPrice(16.96);
                book.save();


                break;

            // 更新数据
            case R.id.update_data:
                // 第一种更新数据的方式
                Book book1 = new Book();
                book1.setName("The Lost Symbol");
                book1.setAuthor("Dan Brown");
                book1.setPages(510);
                book1.setPrice(19.96);
                book1.setPress("Unknow");
                book1.save();
                book1.setPrice(10.99);
                book1.save();


                // 第二种方式更新数据的方式
                Book book2 = new Book();
                book2.setPrice(14.96);
                book2.setPress("Anchor");
                // 使用updateAll()指定一个约束。
                book2.updateAll("name= ? and author = ?", "The Lost Symbol", "Dan Brown");

                // 对于所有想要将为数据更新成默认值的操作,LitePal提供了统一setToDefault()方法,然后传入相应的列名就可以了
                Book book3 = new Book();
                book3.setToDefault("pages");
                // updateAll()方法中没有指定约束条件,更新操作对所有数据都生效了
                book3.updateAll();


                break;

            // 删除数据
            case R.id.delete_data:

                // 第一种删除方式: 调用已存储对象的delete()方法

                // 第二种方式
                DataSupport.deleteAll(Book.class, "price < ?", "15");
                break;
            // 查询数据
            case R.id.query_data:
                List<Book> books = DataSupport.findAll(Book.class);
                for (Book book5 : books) {
                    Log.d(TAG, "name = " + book5.getName() + " author = " + book5.getAuthor() + "pages = " + book5.getPages() + "price = " + book5.getPrice() + "press = " + book5.getPress());

                }
                break;
        }
    }
}