📗

SQLite 入门

创建者UE-DND
创建时间
上次编辑者UE-DND
上次编辑时间
状态
已完成

一、为什么我推荐 SQLite

简单就是硬道理。

上图是《程序设计实践II》任务书中的二选一题目,这两个题目都提到推荐使用 MySQL 作为数据库管理系统。

但我认为,对于这类小型项目,使用 MySQL 有如大炮打蚊子、杀鸡用牛刀。对于初学者来说,我更推荐使用 SQLite 作为数据库管理系统,原因有三:

  1. 配置简单:不需要任何配置,也不需要通过网络端口连接数据库等复杂操作。
  1. 语法简单:省略了很多用不上的复杂功能,基础语法非常简单。
  1. 迁移简单:只要目标环境支持且文件完整,可以直接将数据库文件拷贝到另一台电脑上,相当于你给别人发送了一个 Word 文档,对方点击就能打开并查看里面的内容。而 MySQL 需要复杂的迁移操作。

💡
任务书推荐 MySQL 更多是出于未来就业技能培养的考虑。

如果你想快速高效地完成这个项目,并且深刻理解“用合适的工具做合适的事”,那么大胆地使用 SQLite!

如果你想借此机会挑战一下自己,学习和掌握更通用的企业级数据库技术,那么按照任务书的建议去折腾一下 MySQL 也是非常有价值的。

二、SQL?

说了这么多,又是 MySQL 又是 SQLite,它们究竟是什么,为什么作业需要用到它们?

观察 MySQL 和 SQLite 这两个名称,你会发现它们有一个共同点——SQL。

要想了解 MySQL 和 SQLite,我们先从 SQL 说起。

SQL (Structured Query Language),中文全称“结构化查询语言”,日常读作 /ˈsiːkwəl/ 。

它是一种专门设计用来与数据库进行通信的语言规范。

为什么需要数据库?

在上学期的课程设计任务中,我们通过C语言文件IO简单地读写文件。这种操作虽然便利,但就像把所有资料都随意扔进单个抽屉里,当需要查找时,不仅效率低下,还容易把其它资料弄乱。

数据库,就相当于配备了管理员的大图书馆。它将资料分门别类地放好,将需要频繁查看的资料放在最显眼的位置,还有防盗措施……大大提高了资料的查找效率和安全性。

学习了 SQL, 我们就能操控数据库,完成对资料的增、删、查、改等一系列操作。

MySQL 和 SQLite

可能和你猜测的不太一样,虽然 MySQL 和 SQLite 中都有 SQL,但它们并不是语言规范,而是基于 SQL 开发出的软件产品。

打个不太恰当的比喻,MySQL 和 SQLite 就像谷歌浏览器和Edge浏览器,虽然它们的名字不同,软件页面的设计也不同,但它们都使用 Chromium 作为内核。

同样,MySQL 和 SQLite 都遵循了 SQL 标准,所以对于这两个软件,你可以用类似的 SQL 语法操作它们,但它们在功能等方面有显著差异。MySQL 主要针对企业场景以及大型项目,它的操作更复杂,语法也在 SQL 的基础上作了很多更改。而 SQLite 正如它的名字一样:轻量化,同时针对这种小型项目也更加容易配置。

三、安装 SQLite

既然 SQLite 是一个软件,我们就必须先安装再使用。

下面给出 Windows 和macOS 的安装方式:

GUI 是图形化界面,可以方便地查看和编辑数据库文件。

CLI 是命令行界面,使用终端查看和编辑数据库文件。

对于 Windows,建议同时安装 GUI 和 CLI。

而对于 macOS,可以只安装 GUI,因为 macOS 中自带一个较低版本的 CLI。如果有需要,可以通过brew 重新安装。

🖥️

Windows


  • GUI (DB Browser for SQLite)
    choco install sqlitebrowser

    安装后桌面上会有两个快捷方式,其中一个是 (SQLCipher)。它是 DB Browser for SQLite 的一部分,提供了处理加密 SQLite 数据库的附加功能。


  • CLI
    choco install sqlite
💻

macOS


  • GUI (DB Browser for SQLite)
    brew install --cask db-browser-for-sqlite

    设置为中文

    选择语言为中文后点击右下角 save 保存并重启应用。

  • CLI
    brew install sqlite

四、安装驱动

我们还需要一个翻译官。

现在,我们再总结一下需求:

但是,如何在我们的 Java 程序里使用 SQL 命令呢?

事实上,SQL 命令只能在终端使用。在没有引入翻译官前,我们无法在 Java 代码中直接写 SQL 命令,Java 编译器也看不懂这些命令,只会当成普通的字符串。

我们需要引入一个翻译官,它能接收我们写在 Java 代码写的 SQL 命令,然后去和软件沟通,最终让软件对数据库文件进行操作,完成我们发送的命令。

这个翻译官就是 JDBC 驱动程序规范

JDBC,全称 Java DataBase Connectivity(Java 数据库连接)。为了更好地理解它的功能,我们将其转换成动词的形式:“Java 连接数据库”。这样看,“翻译官”的角色就很明显了。

JDBC 跟 SQL 一样,它们仅仅是开发者参考的规范,不是可以直接使用的工具。为此,我们需要使用 SQLite-JDBC,它才是“真正的”那个翻译官。

SQLite-JDBC 前面的“SQLite”表明这个驱动程序是专门针对 SQLite 软件的。

前面提到,数据管理软件有很多,虽然它们大部分都基本遵循 SQL 语法,但每个软件的内部设计仍有区别,因此我们需要针对特定软件的驱动。由于我们选择了 SQLite 管理数据库,那么我们就必须选择 SQLite-JDBC 作为驱动程序。

对于安装这个驱动程序,以下有两种不同方法:

五、SQLite 基本语法

正式开始操作数据库。

不知道你有没有这样的疑惑:

前面我们提到“掌握了 SQL 语法后,我们就可以使用 SQL 命令操控 SQLite 软件“。为什么标题是“SQLite 基本语法”,而不是“SQL 基本语法”?

这些软件仅仅是基本遵守 SQL 的规范。可能在原有的语法上作了改进,可能在原有的语法上作了删减。因此,我们不得不学习针对特定软件的语法。

但别担心,虽然它们仅仅是基本遵守 SQL 的规范,但至少还是遵守了的,语法结构仍然有一定程度相似,日后再使用其他软件如 MySQL 也不会非常困难。


在正式开始前,请确保已经安装好了所有程序。

为了快速上手而不是深入学习,我将直接以代码示例的形式给出,需要自己理解语法结构。

注意:

1️⃣ SQLite 命令【关键字】对大小写不敏感,但部分命令的大写形式和小写形式有所区别。为了便于区分命令与普通字符,对于 SQLite 的命令,最好采用区分大小写的方式(通常为大写)。

2️⃣ 哪里要加分号,哪里要加逗号。


前提

在 SQL 的规范中,我们必须先定义表格的每一列(的结构),然后才能插入每一行(的数据)

例如:

学号姓名班级成绩
1张三100.0
2李四59.0
3王五91.0

下面这种表格定义是不合理的,SQL 也不支持这种定义方式。

学号123
姓名张三李四王五
班级
成绩100.059.091.0

启动 SQLite

  1. 打开终端
  1. cd进入指定的目录
  1. 在终端中输入并回车
    sqlite3

为了进行接下来的所有操作,请保证 SQLite 处于启动状态。


创建 / 打开一个数据库

 .open DatabaseName.db

如果目录中没有这个文件,将会自动创建;如果存在这个文件,将会打开这个数据库。


为了进行接下来的所有操作,请保证数据库处于打开状态。


在数据库中创建一个表格

一个数据库是由许多互相关联的表格构成的,这里的表格不是什么高大上的概念,就是你平时填表的那种表格。
CREATE TABLE IF NOT EXISTS studentss (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   name VARCHAR NOT NULL,
   class_name TEXT,
   score REAL
);

加表格数据

在 SQL 的规范中,新添加的每一行数据不能指定插入的位置,只能放在最后一行。

使用CREATE TABLE新建的表格中没有任何数据(注意下方是第0行,实际不显示)。

idnameclass_namescore
INSERT INTO students (name, class_name, score)
VALUES ('陈六', '一班', 85.5);
idnameclass_namescore
1陈六一班85.5
INSERT INTO students (name, class_name, score) VALUES
('李四', '一班', 92.0),
('王五', '二班', 76.5),
('赵六', '二班', 95.0),
('胡七', '三班', 98.0);
idnameclass_namescore
1陈六一班85.5
2李四一班92.0
3王五二班76.5
4赵六二班95.0
5胡七三班98.0

删除表格数据

DELETE FROM table_name WHERE [condition];
⚠️

WHERE 不是必须的,但如果没有 WHERE 以及后面的 [condition],整个表格的数据将会被删除,只留下第0行:

idnameclass_namescore

编成一句话:删除table_name表格中满足condition条件的行。

DELETE FROM students WHERE id = 3;
idnameclass_namescore
1陈六一班85.5
2李四一班92.0
4赵六二班95.0
5胡七三班98.0
DELETE FROM students WHERE score < 90;
idnameclass_namescore
2李四一班92.0
4赵六二班95.0
5胡七三班98.0
DELETE FROM students WHERE class_name = '一班' OR class_name = '二班' ;
idnameclass_namescore
5胡七三班98.0

上面的语句还可以简化

DELETE FROM students WHERE class_name IN ('一班', '二班');

查找表格数据

SELECT * FROM students;
1陈六一班85.5
2李四一班92.0
3王五二班76.5
4赵六二班95.0
5胡七三班98.0
SELECT name, score FROM students;
陈六85.5
李四92.0
王五76.5
赵六95.0
胡七98.0
SELECT * FROM students WHERE class_name = '一班';
1陈六一班85.5
2李四一班92.0
SELECT * FROM students WHERE score > 90;
2李四一班92.0
4赵六二班95.0
5胡七三班98.0
SELECT * FROM students ORDER BY score DESC;
5胡七三班98.0
4赵六二班95.0
2李四一班92.0
1陈六一班85.5
3王五二班76.5
SELECT * FROM students ORDER BY score DESC LIMIT 2;
5胡七三班98.0
4赵六二班95.0

修改表格数据

UPDATE students
SET score = 98.5
WHERE name = '李四';
idnameclass_namescore
1陈六一班85.5
2李四一班98.5
3王五二班76.5
4赵六二班95.0
5胡七三班98.0
UPDATE students
SET class_name = '精英班'
WHERE class_name = '二班';
idnameclass_namescore
1陈六一班85.5
2李四一班98.5
3王五精英班76.5
4赵六精英班95.0
5胡七三班98.0

查找数据库中的表格

.table

删除数据库中的表格

DROP TABLE IF EXISTS table_name;
⚠️

使用此命令时要特别注意,一旦一个表被删除,表中所有信息也将永远丢失。


退出数据库并退出 SQLite

.exit

六、在 Java 中使用 SQLite 命令

马上就要完成了……

以下是一个小小的测试用例。

用于测试刚刚的驱动程序能否运行,以及如何在 Java 中使用 SQLite 命令:

/**
 * 导入相关的包,以下这些基本上都是必要的。你还可以根据项目需求导入其它的包
 */
import java.sql.Connection;     // 用于建立与数据库的连接
import java.sql.DriverManager;  // 用于管理JDBC驱动程序
import java.sql.ResultSet;      // 用于存储查询结果
import java.sql.Statement;      // 用于执行SQL语句

/**
 * SQLite 基础操作示例
 */
public class SQLiteSimple {
    public static void main(String[] args) throws Exception {
		    /***************** 0. 驱动注册 *****************/
		    // 对于较旧版本的Java,通常需要注册驱动操作
		    // 我们使用的Java版本较新,Java已经帮我们实现了自动注册
        
        /*1. 与数据库建立连接(打开SQLite,创建/打开数据库)*/
        Connection conn = DriverManager.getConnection("jdbc:sqlite:simple.db");
        System.out.println("数据库连接成功");
        
        /************ 2. 创建Statement对象 *************/
        Statement stmt = conn.createStatement();
        
        /************ 3. 在数据库中创建一个表格 **********/
        
        // executeUpdate是Statement类的一个方法,用于执行数据库的更新操作。
        stmt.executeUpdate("DROP TABLE IF EXISTS students");  // 如果该表格存在,先删除它
        // 可以看到,在 Java 中都是以字符串的形式使用 SQLite 语句
        // 与在终端中使用 SQLite 语句不同,每条语句的末尾不需要加分号,只保留Java本身的分号
        
        stmt.executeUpdate("CREATE TABLE IF NOT EXISTS students (
											        id INTEGER PRIMARY KEY,
											        name TEXT,
											        score INTEGER
											      )");
        System.out.println("创建表格成功");
        
        /*************** 4. 增加表格数据 ***************/
        stmt.executeUpdate("INSERT INTO students VALUES (1, '张三', 95)");
        stmt.executeUpdate("INSERT INTO students VALUES (2, '李四', 88)");
        stmt.executeUpdate("INSERT INTO students VALUES (3, '王五', 73)");
        System.out.println("插入数据成功");
        
        /*************** 5. 查询表格数据 ***************/
        System.out.println("\n所有学生信息:");
        
        // executeQuery是Statement类的一个方法,用于执行数据库的查询操作。
        ResultSet rs = stmt.executeQuery("SELECT * FROM students");  // 将查询到的结果传递给ResultSet
        
        // 可以将ResultSet视为一个完整表格,但这个表格只显示第一行
        while (rs.next()) {  // 使用.next移动到下一行
            int id = rs.getInt("id");  // 将get到的数据存储并打印
            String name = rs.getString("name");
            int score = rs.getInt("score");
            System.out.println(id + "\t" + name + "\t" + score);
        }
        
        /*************** 6. 更新表格数据 **************/
        stmt.executeUpdate("UPDATE students SET score = 100 WHERE name = '张三'");
        System.out.println("\n更新后的张三信息:");
        rs = stmt.executeQuery("SELECT * FROM students WHERE name = '张三'");
        while (rs.next()) {
            System.out.println(rs.getInt("id") + "\t" + rs.getString("name") + "\t" + rs.getInt("score"));
        }
        
        /*************** 7. 删除表格数据 **************/        
        stmt.executeUpdate("DELETE FROM students WHERE name = '王五'");
        System.out.println("\n删除王五后的所有学生信息:");
        rs = stmt.executeQuery("SELECT * FROM students");
        while (rs.next()) {
            System.out.println(rs.getInt("id") + "\t" + rs.getString("name") + "\t" + rs.getInt("score"));
        }
        
        /**************** 8. 关闭数据库 ***************/        
        rs.close();
        stmt.close();
        conn.close();
        System.out.println("\n数据库连接已关闭");
    }
} 

代码写完了,我们该如何运行这个程序?

(VSCode)直接点击右上角运行按钮肯定是不行的,不信你试一下。

以下提供两种运行方法:

运行成功后,控制台应该会输出以下内容:

数据库连接成功
创建表成功
插入数据成功

所有学生信息:
1       张三    95
2       李四    88
3       王五    73

更新后的张三信息:
1       张三    100

删除王五后的所有学生信息:
1       张三    100
2       李四    88

数据库连接已关闭

最后解答一个疑惑:

如果我将整个项目拷贝到其它电脑(即使没有安装 SQLite 和 驱动),这个项目也可以运行吗?

答案是:“Write Once, Run Anywhere”(一次编写,到处运行)。