SQLite 深度解析:在 Java/Spring 中的使用与H2、Derby对比

SQLite 深度解析:在 Java/Spring 中的使用与嵌入式数据库横向对比

一、SQLite 是什么?

SQLite 是一个嵌入式关系数据库引擎 ,由 D. Richard Hipp 于 2000 年创建,采用公共领域(Public Domain) 许可证。它不是传统的客户端-服务器数据库,而是一个进程内库------直接嵌入到应用程序中,无需独立的数据库进程。

官方口号:Small. Fast. Reliable. Choose any three.

核心特性

  • 零配置:无需安装、无需配置、无需管理员
  • 服务器less:应用程序直接读写数据库文件,无中间进程
  • 单文件存储:整个数据库是一个普通的磁盘文件
  • ACID 事务:支持原子提交,即使系统崩溃也能保证数据一致性
  • 完整 SQL 实现:支持 CTE、窗口函数、JSON 函数、FTS5 全文搜索等
  • 轻量级:完整库体积仅约 600KB(可裁剪至更小)
  • 高可靠性:测试覆盖率 100%,有超过 1 亿行测试代码
  • 跨平台:支持所有主流操作系统

二、SQLite 与其他嵌入式数据库的对比

嵌入式数据库三巨头:SQLiteH2Apache Derby。此外还有 HSQLDB。以下是深度对比:

特性 SQLite H2 Apache Derby HSQLDB
实现语言 C Java(纯) Java(纯) Java(纯)
数据库文件 单文件 单文件 + 可选内存 多文件 多文件
LICENSE Public Domain MPL/EPL Apache 2.0 BSD
嵌入方式 原生 C,通过 JDBC 桥接 原生 JDBC 原生 JDBC 原生 JDBC
服务器模式 不支持 支持 支持 支持
内存数据库 支持(:memory:) 支持 支持 支持
Spring 原生支持 ❌ 需手动配置 ✅ 内建支持 ✅ 内建支持 ✅ 内建支持
多进程并发 ✅ 多进程可读,单写 ❌ 单进程 ❌ 单进程 ❌ 单进程
MVCC ❌(文件级锁)
SQL 标准兼容 部分(无 RIGHT/FULL JOIN) 较好 较好 较好
启动速度 极快 极快 较快 较快
Java 集成便利性 一般(需第三方驱动) 极佳 极佳 极佳
生态/用户量 极广(万亿级部署)
Hibernate 兼容性 需额外配置(Dialect) 原生支持 原生支持 原生支持

选型建议

选 SQLite 当:

  • 需要多进程并发读取同一数据库
  • 应用非 Java 语言(C/C++、Python、Go、Rust...)
  • 追求极致轻量和零依赖
  • 数据库文件需跨语言/跨平台交换
  • 移动端、IoT、桌面应用

选 H2/Derby/HSQLDB 当:

  • 纯 Java 生态(Spring Boot 内建支持最佳)
  • 需要服务器模式以便远程管理
  • 需要高性能 MVCC 并发写入
  • JPA/Hibernate 重度使用(SQLite 的 Dialect 不完善)
  • 开发测试环境需要快速重置数据库

三、SQLite 在 Java/Spring 中的使用

Spring 官方并未将 SQLite 列为内建嵌入式数据库(只支持 H2、HSQL、Derby),但我们依然可以通过第三方驱动和少量配置将其集成进来。

3.1 引入依赖(Maven)

xml 复制代码
<!-- SQLite JDBC 驱动 -->
<dependency>
    <groupId>org.xerial</groupId>
    <artifactId>sqlite-jdbc</artifactId>
    <version>3.46.0.0</version>
</dependency>

推荐同时引入 HikariCP 连接池:

xml 复制代码
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.1.0</version>
</dependency>

3.2 基础 JDBC 使用

java 复制代码
import java.sql.*;

public class SQLiteExample {
    public static void main(String[] args) throws Exception {
        // 1. 加载驱动(3.46.0+ 版本自动注册,可省略)
        Class.forName("org.sqlite.JDBC");

        // 2. 连接数据库(文件不存在会自动创建)
        try (Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db")) {
            // 3. 创建表
            try (Statement stmt = conn.createStatement()) {
                stmt.execute("CREATE TABLE IF NOT EXISTS users (" +
                             "id INTEGER PRIMARY KEY AUTOINCREMENT," +
                             "name TEXT NOT NULL," +
                             "email TEXT UNIQUE NOT NULL," +
                             "created_at TEXT DEFAULT CURRENT_TIMESTAMP)");
            }

            // 4. 插入数据
            String sql = "INSERT INTO users(name, email) VALUES(?, ?)";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setString(1, "张三");
                pstmt.setString(2, "zhangsan@example.com");
                pstmt.executeUpdate();
            }

            // 5. 查询数据
            try (Statement stmt = conn.createStatement();
                 ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
                while (rs.next()) {
                    System.out.printf("%d | %s | %s | %s%n",
                        rs.getInt("id"),
                        rs.getString("name"),
                        rs.getString("email"),
                        rs.getString("created_at"));
                }
            }
        }
    }
}

3.3 在 Spring Boot 中配置 SQLite

yaml 复制代码
# application.yml
spring:
  datasource:
    url: jdbc:sqlite:mydb.db
    driver-class-name: org.sqlite.JDBC
    username:
    password:
    hikari:
      maximum-pool-size: 1        # SQLite 不支持并发写,设为 1
      minimum-idle: 1
      connection-timeout: 30000
  jpa:
    database-platform: org.hibernate.community.dialect.SQLiteDialect
    hibernate:
      ddl-auto: update
    show-sql: true

Spring Boot 3.x / Hibernate 6+ 注意SQLiteDialect 从 Hibernate 6 起移至 org.hibernate.community.dialect 包,需额外引入:

xml 复制代码
<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-community-dialects</artifactId>
</dependency>

3.4 使用 JPA(实体映射示例)

java 复制代码
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    private LocalDateTime createdAt;

    // getters / setters ...
}
java 复制代码
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    List<User> findByNameContaining(String keyword);
}

3.5 内存数据库模式

SQLite 支持纯内存数据库,适合测试场景:

java 复制代码
// JDBC 方式
Connection conn = DriverManager.getConnection("jdbc:sqlite:");

// Spring 配置
spring.datasource.url=jdbc:sqlite:

3.6 WAL 模式------提升并发性能

SQLite 默认使用回滚日志模式(rollback journal),写入时会锁定整个数据库。切换到 WAL(Write-Ahead Log)模式 后,读写可以并发进行:

sql 复制代码
-- 在连接建立后执行
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA busy_timeout=5000;

在 Spring 中自动执行:

java 复制代码
@Configuration
public class SQLiteConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:sqlite:mydb.db");
        config.setDriverClassName("org.sqlite.JDBC");
        config.setMaximumPoolSize(1);
        config.setConnectionInitSql("PRAGMA journal_mode=WAL");
        return new HikariDataSource(config);
    }
}

3.7 使用 Spring JDBC 模板

java 复制代码
@Repository
public class UserDao {
    private final JdbcTemplate jdbcTemplate;

    public UserDao(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public List<User> findAll() {
        return jdbcTemplate.query("SELECT * FROM users",
            (rs, rowNum) -> new User(
                rs.getLong("id"),
                rs.getString("name"),
                rs.getString("email"),
                rs.getObject("created_at", LocalDateTime.class)
            ));
    }
}

四、SQLite 的关键优化 PRAGMA

PRAGMA 说明 推荐值
journal_mode 日志模式 WAL(最佳读写并发)
synchronous 同步级别 NORMAL(平衡性能与安全)
cache_size 缓存页数(单位:页) -64000(=64MB)
page_size 页大小 4096
temp_store 临时存储位置 MEMORY
busy_timeout 忙等待超时(ms) 5000
foreign_keys 外键约束 ON(默认关闭,需手动开启)

五、SQLite 的典型应用场景

  1. 移动端(Android/iOS 默认数据库)
  2. 桌面应用(浏览器、编辑器、游戏存档)
  3. IoT/嵌入式设备(资源受限环境)
  4. 应用文件格式(替代 XML/JSON 作为数据存储格式)
  5. 开发/测试阶段(快速原型,无需安装数据库)
  6. 数据分析/ETL 中间存储
  7. 浏览器、Chrome/Firefox 内部存储

六、SQLite 的局限性

  • 不支持并发写入(WAL 模式下可读写并发,但仍不支持多写)
  • 不支持存储过程、用户自定义函数(UDF 需编译 C 扩展)
  • 不支持 RIGHT/FULL OUTER JOIN
  • 不支持 GRANT/REVOKE 权限管理
  • 不适合高并发 OLTP 场景
  • 不适合超大规模数据(单库推荐 < 140TB,实际 < 10TB 更佳)
  • Hibernate/JPA 集成体验不如 H2/Derby(Dialect 非官方,部分特性不支持)

七、总结

SQLite 是世界上部署最广泛的数据库引擎 (没有之一),每个智能手机都有数百个 SQLite 数据库。它是一款极致轻量、零依赖、跨语言的嵌入式数据库。

在 Java/Spring 生态中,如果项目是纯 Java 且不需要多进程共享 ,H2 往往是更好的选择(Spring 原生支持、更好的 Hibernate 兼容性、内置控制台)。但如果需要跨语言共享数据文件、多进程并发读取、或部署在资源受限环境,SQLite 仍是不可替代的选择。

简单决策树:

  • 纯 Java 微服务 / 测试环境 → H2
  • 移动端 / IoT → SQLite
  • 桌面应用 / 单用户软件 → SQLite (更轻量)或 H2(需远程管理时)
  • 多进程读写同一数据库 → SQLite(WAL 模式)
  • 需要服务器模式远程连接 → H2 / Derby

参考链接:

相关推荐
laufing14 小时前
Java 模板引擎 FreeMarker 入门教程:语法、内建函数与常用案例
java·freemarker
wengqidaifeng14 小时前
C++从菜鸟到强手:2.类和对象(上)—— 从结构体到类的跨越
java·开发语言·c++
自律懒人14 小时前
2026年AI编程工具横评:Trae、Cursor、Claude Code、Copilot X,同一需求谁更强?
java·copilot·ai编程
夕除14 小时前
spring boot 13
java·mysql·spring
marlondu15 小时前
ScopedValue:Java 21 引入的结构化作用域值
java
risc12345615 小时前
DocumentsWriterDeleteQueue
java·开发语言
日月云棠15 小时前
12 Dubbo 2.7 服务发布全流程源码解析
java·后端
用户2986985301415 小时前
告别手动复制:Java 拆分 Word 文档的两种实用方案
java·后端
En^_^Joy15 小时前
Django开发:基本入门指南
python·django·sqlite