《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 数据库初始化机制 阅读笔记 36

《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 数据库初始化机制 阅读笔记 36

12.6 数据库初始化机制

Spring Boot 在整合 JDBC 时提供了一个比较有趣的初始化机制,它可以在应用启动阶段向连接的数据库发送一些 DDL、DML 语句,以完成创建数据库表、写入表数据等操作。这个机制在使用 H2 等内存数据库时尤为好用,因为内存数据库的特点是启动时没有数据,进程结束后释放内存而造成数据丢失,而数据库的初始化机制可以让内存数据库初始化完成后执行一些 DDL、DML 语句完成初始数据的准备动作,进而减少一些重复的工作。

12.6.1 DDL 语句发送

首先尝试让 Spring Boot 发送 DDL 语句,代码准备了一个部门表 tbl_dept 的建表语句,对于这个建表语句不要直接在 MySQL 中执行,而是将它制作为一个名为 "schema.sql" 的文件,并将其放到工程的 src/main/resources 目录下。schema.sql 这个文件名是 Spring Boot 约定使用的名称,只要 Spring Boot 检测到工程的 src/main/resources 目录下有这个文件,就会加载它并在连接的数据源上执行。

sql 复制代码
CREATE TABLE `tbl_dept` (
                            `id` int(11) NOT NULL AUTO_INCREMENT,
                            `name` varchar(32) DEFAULT NULL COMMENT '部门名称',
                            `pid` int(11) DEFAULT NULL COMMENT '上级部门id',
                            `del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除字段',
                            PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

随后要在全局配置文件中设置一个配置项:spring.sql.init.mode=always,这代表在任意条件下都执行这个 schema.sql 文件。保存完毕后直接重启整个工程,启动成功后刷新数据库可以看到 tbl_dept 表被创建。

yaml 复制代码
spring:
  application:
    name: springboot-jdbc-a
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.19.201:3306/spring-dao?characterEncoding=utf8
    username: spring-dao
    password: yyy123456.
  sql:
    init:
      mode: always

如果 DDL 语句文件名不是 schema.sql,或者这些文件不在 src/main/resources 目录下,也可以通过设置 spring.sql.init.schema-locations 配置项指定这些文件的位置,注意这个配置项可以传入一个数组。

yaml 复制代码
spring.sql.init.schema-locations[0]=classpath*:sql/schema.sql
spring.sql.init.schema-locations[1]=classpath*:schema.sql

12.6.2 DML语句发送

与执行 DDL 语句的机制类似,执行 DML 语句的约定文件名是 data.sql,只需要在 src/main/resources 目录下再放入一个 data.sql 文件并编写内容,即可在每次工程启动时执行它们。代码中提供了一个插入部门表数据的 SQL,内容比较简单。

sql 复制代码
delete from tbl_dept where del = 0;
insert into tbl_dept (name, pid) values ('总公司', 0);
insert into tbl_dept (name, pid) values ('第一分公司', 1);

如果此时直接重启工程,会发现启动时抛出异常:Table'tbl_dept'already exists,之所以出现这个现象,是因为刚才设置了spring.sql.init.mode=always,这个初始化模式会在每次项目启动时都执行,而同样的建表语句不能连续发送两次,导致抛出了表已存在的异常。解决该问题的方式很简单,只需要在 schema.sql 文件的最开始加入一行 DROP TABLE IF EXISTS tbl_dept; 。

调整后再次重启工程,这次可以在 IDEA 的数据库面板中看到数据库中插入了两条数据,说明 DML 语句也成功执行。

与 schema.sql 文件的配置类似,可以在全局配置文件中设置 spring.sql.init.data-locations 配置项指定 DML 语句的 SQL 文件位置,该配置项同样可以接收一个数组。

12.6.3 多平台兼容与初始化策略

如果工程需要同时考虑对接多种不同的数据库,则有可能因 SQL 语法不兼容导致在一个数据库平台中执行成功,在另一个数据库平台中执行失败。Spring Boot 考虑到了这一点,它支持在 SQL 文件名中添加数据库平台标识来区分不同的类型。例如 schema.sql 代表所有数据库平台中都会执行的 SQL 文件,而 schema-mysql.sql 则代表只有数据源为 MySQL 时才执行的 SQL 文件,schema-oracle.sql 代表数据源为 Oracle 数据库时才执行的 SQL 文件,以此类推,data.sql 同理。

另外解释一下这个数据库初始化机制的使用特点。通过上面的使用过程也能看出,设置 spring.sql.init.mode=always 在连接外部数据库时会产生很大的麻烦,由于每次都要先删掉表后再新建,会导致其中的数据全部丢失,这种使用方式在实际项目开发中是不被允许的,因此 Spring Boot给配置项 spring.sql.init.mode 设置的默认值是 EMBEDDED,即只有在嵌入式数据库中才生效,因为嵌入式数据库就是内存数据库,每次启动时都需要初始化表和数据,刚好可以用得上这个机制。此外还可以设置 spring.sql.init.mode=never 来禁用该初始化机制。

12.7 小结

本章通过使用 Spring Framework 和 Spring Boot 整合 JDBC 完成与数据库的交互操作,并使用 JdbcTemplate 和事务控制完成基本的数据层开发。

Spring Framework 整合 JDBC 所使用的核心包括数据源、数据库访问客户端和事务管理器,在 Spring Boot 中这些组件都基于自动装配完成注册。使用 JdbcTemplate 可以完成简单的数据库 CRUD 操作。Spring Framework 的事务控制包括编程式和声明式,正常的项目开发中更多使用注解声明式事务在 Service 层完成控制。

虽然直接使用 JdbcTemplate 编写 SQL 语句已经简化了与数据库交互的开发,但实际项目开发中更多使用 ORM 框架完成与数据库的交互,第13 章会介绍主流 ORM 框架 MyBatis 在 Spring Boot 项目中的应用。

相关推荐
qiuhaipeng11 小时前
Claude code 升级后上下文长度变短问题
java·前端·数据库
wxwx_bscxy3222 小时前
基于Python新冠疫情可视化分析系统的设计与实现
java·数据库·spring boot·python·微信小程序·sqlite
剑之所向2 小时前
.NET 官方`System.Threading.Channels`
前端·javascript·数据库
推送者3 小时前
用宠物照片制作桌宠:从AI拆帧到九点标定的本地化实现笔记
笔记·宠物·用宠物照片制作桌宠
词却3 小时前
数据库基础:DQL 数据查询语言
数据库·oracle
一条破秋裤3 小时前
16_TIM编码器接口测速
笔记·stm32·学习
tju新生代魔迷3 小时前
Verilog HDL 学习笔记(十)| 第10章 时序和延迟
笔记·学习·fpga开发
昌原的儿子LEO5 小时前
Linux IO多路复用与SQLite数据库核心知识点总结
linux·数据库·oracle
血小板要健康5 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表