SQLite是一款无需独立服务进程的嵌入式数据库,整个数据库就是一个单独的文件,部署简单、零运维成本,非常适合桌面工具、小型Web应用、测试环境或者资源受限的场景。Spring Boot默认对MySQL、PostgreSQL、H2等数据库提供了良好的开箱支持,但对SQLite的支持需要一些额外的配置工作,尤其是Hibernate方言这一块容易踩坑。本文将完整演示从依赖引入到成功读写数据的全部步骤。

一、项目依赖引入与基础配置
第一步是在pom.xml中添加SQLite的JDBC驱动。目前社区维护最活跃的驱动是sqlite-jdbc,由xerial团队维护,底层基于原生SQLite库封装,稳定性较好。同时还需要引入hibernate-community-dialects,这是解决方言问题的关键依赖,后面会详细说明。
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.45.1.0</version>
</dependency>
<!-- Hibernate社区方言包,包含SQLiteDialect -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
</dependency>依赖添加完成后,接下来在application.yml中配置数据源。SQLite的JDBC URL格式非常简单,只需要指定数据库文件的路径即可。如果文件不存在,驱动会自动创建一个新文件;如果使用:memory:则表示使用内存数据库,应用重启后数据丢失,适合单元测试场景。
spring:
datasource:
driver-class-name: org.sqlite.JDBC
# 相对路径写法,数据库文件生成在项目根目录
url: jdbc:sqlite:app.db
# 内存模式:jdbc:sqlite::memory:
jpa:
database-platform: org.hibernate.community.dialect.SQLiteDialect
hibernate:
ddl-auto: update
show-sql: true这里有两个细节需要注意。第一,Windows环境下也可以使用绝对路径,例如jdbc:sqlite:C:/data/app.db,路径分隔符用正斜杠或双反斜杠都可以,写成C:\data\app.db这种单反斜杠形式在某些解析场景下会被当成转义符处理,建议统一用正斜杠。第二,SQLite没有传统意义上的用户名密码认证,datasource下的username和password可以不配置。
二、解决Hibernate方言缺失的报错
很多人配置完启动项目时会遇到这样一个报错:Unable to determine Dialect或者提示无法为SQLite自动选择方言。这是因为Hibernate核心包并不内置SQLite方言,它被划分到了社区方言包中。解决方案就是前面提到的引入hibernate-community-dialects依赖,并在配置中显式指定org.hibernate.community.dialect.SQLiteDialect。
如果你使用的是较老版本的Hibernate(5.x之前的版本),社区包里没有现成的SQLiteDialect,就需要自己动手实现一个。自定义方言的核心工作是继承Dialect类,注册SQLite支持的数据类型映射,例如下面这个简化版本:
public class SQLiteDialectCustom extends Dialect {
public SQLiteDialectCustom() {
registerColumnType(Types.INTEGER, "integer");
registerColumnType(Types.VARCHAR, "varchar");
registerColumnType(Types.BLOB, "blob");
registerColumnType(Types.REAL, "real");
registerColumnType(Types.TIMESTAMP, "text");
}
// SQLite不支持ALTER TABLE添加列的完整语法,
// 需禁用某些DDL操作来避免异常
@Override
public boolean hasAlterTable() {
return false;
}
@Override
public boolean dropConstraints() {
return false;
}
}这里要理解一个底层原因:SQLite是弱类型数据库,它的存储类型只有NULL、INTEGER、REAL、TEXT和BLOB五种,没有原生的日期时间类型和布尔类型。Hibernate会把日期映射成TEXT存储,把boolean映射成INTEGER(0和1)。自定义方言时如果不处理hasAlterTable返回false的问题,ddl-auto: update在尝试修改表结构时会直接抛出SQL语法异常,这是非常高频的一个坑。
三、实体类与数据操作实战
配置完成后,写一个简单的实体类验证整个链路是否通畅。下面的示例定义了一个用户表,注意主键采用了GenerationType.IDENTITY策略,SQLite支持自增主键,这种写法可以正常工作。
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username")
private String username;
@Column(name = "email")
private String email;
// 省略getter和setter
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsername(String username);
}启动应用后,Hibernate会根据ddl-auto: update自动在项目根目录生成app.db文件并创建表。此时通过Repository接口调用save和findAll方法即可完成增删查改。如果想直观查看数据,可以安装DB Browser for SQLite这类图形化工具打开db文件,验证数据是否落盘。
如果你不使用JPA而是选择MyBatis,配置会更加简单,因为MyBatis不依赖方言。只需要在mybatis-config或者通过注解正常编写SQL即可,SQLite的标准SQL语法基本都能支持。需要注意的是SQLite的SQL中有一些特殊语法,比如拼接字符串用双竖线||而不是CONCAT函数,分页直接使用LIMIT加OFFSET,这些在写Mapper XML时要留意与MySQL的差异。
四、并发写入限制与生产环境建议
SQLite最被诟病的一点是写并发能力弱。它的机制是库级别锁,同一时刻只允许一个写操作,高并发写入场景下会出现database is locked的报错。缓解这个问题可以在JDBC URL上追加连接参数,限制连接池大小并开启WAL模式。
spring:
datasource:
url: jdbc:sqlite:app.db?journal_mode=WAL&busy_timeout=5000
hikari:
maximum-pool-size: 1WAL模式(Write-Ahead Logging)允许读写操作并行执行,读操作不再阻塞写操作,能显著改善并发表现。而把HikariCP连接池的最大连接数设为1,虽然牺牲了并行写入能力,但能从根源上避免多个连接争抢写锁导致的锁死问题,对于中小规模应用来说是务实的选择。 busy_timeout参数则指定了获取锁失败后的等待毫秒数,避免立刻抛异常。
总体来说,Spring Boot整合SQLite的技术方案适合日活不高、部署追求极简的项目,例如内部管理工具、爬虫数据存储、边缘设备服务等。如果业务规模增长到需要频繁并发写入或海量数据检索,就应该果断迁移到MySQL、PostgreSQL这类独立数据库,SQLite的定位决定了它是轻量场景的最优解而非万能方案。掌握好方言配置、WAL模式和连接池调优这三点,就可以稳定地把SQLite用在生产环境中了。
Spring BootSQLite数据库配置修改时间:2026-09-13 10:34:31