《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 项目中的应用。

相关推荐
城北徐宫2 分钟前
MySQL约束条件一览
数据库·mysql
ClouGence2 小时前
数据库变更审批困局,被这个开源工具解决了
数据库·开源
TDengine (老段)3 小时前
TDengine IDMP 十大实用功能(9)
大数据·数据库·人工智能·物联网·时序数据库·tdengine·idmp
叼烟扛炮3 小时前
Linux 学习笔记(五十八):IO 多路复用封神——epoll 底层原理揭秘
linux·运维·服务器·网络·笔记·学习·php
starrocks_stella4 小时前
EMR Serverless StarRocks Object Table:用 SQL 连接 OSS 文件与多模态 AI
数据库
这个DBA有点耶4 小时前
以为自增ID只是有空洞?聊聊双主架构下无声的“数据覆盖”
数据库·mysql·dba
陈布衣4 小时前
MySQL(1)_MySQL 5.7.21 Linux 安装笔记
linux·笔记·mysql
钱栈up5 小时前
内网全断,怎么核实高炉和烧结系统的数据库对接信息
数据库
秋天的怀念_David5 小时前
算法一千零一夜 · 第二十六夜 协议的母语
java·spring boot·算法
weavecodes5 小时前
双层缓存与权限实时生效:织码在线教育系统的 Caffeine + Redis 设计
数据库