敞开生长之旅!这是我参加「日新方案 12 月更文挑战」的第2天,点击查看活动详情

SpringBoot系列之数据库初始化-datasource配置方式

在咱们的日常业务开发进程中,假如有db的相关操作,通常咱们是直接建立好对应的库表结构,并初始化对应的数据,即更常见的情况下是咱们在已有表结构根底之下,进行开发; 可是当咱们是以项目形式作业时,更常见的做法是所有的库表结构改变、数据的初始、更新等都需要持有对应的sql改变,并保存在项目工程中,这也是运用liqubase的一个重要场景; 将上面的问题进行简单的翻译一下,便是怎么完成在项目发动之后履行相应的sql,完成数据库表的初始化?

本文将作为初始化方法的第一篇:基于SpringBoot的装备方法完成的数据初始化

I. 项目建立

1. 依赖

首先建立一个规范的SpringBoot项目工程,相关版别以及依赖如下

本项目凭借SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

开一个web服务用于测试

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
</dependencies>

本文运用MySql数据库, 版别8.0.31

2. 装备

注意完成初始化数据库表操作的核心装备就在下面,重点关注

装备文件: resources/application.yml

# 默许的数据库名
database:
  name: story
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/${database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
    initialization-mode: always
    platform: mysql
    separator: ;
    data: classpath:config-data.sql
    #data-username: root
    #data-password:
    schema: classpath:config-schema.sql # schema有必要也存在,若只存在data,data中的sql也不会被履行
# springboot 2.5+ 版别运用下面这个
#  sql:
#    init:
#      mode: always
#      data-location: classpath:config-data.sql
#      schema-location: classpath:init-schema.sql
logging:
  level:
    root: info
    org:
      springframework:
        jdbc:
          core: debug

上面的装备中,相比较于一般的数据库链接装备,多了几个装备项

  • spring.datasource.initialization-mode: 取值为 always,改成其他的会导致sql不会被履行
  • spring.datasource.platform: mysql
  • spring.datasource.seprator: ; 这个表示sql之间的分隔符
  • spring.datasource.data: classpath:config-data.sql 取值可所以数组,这里存的是初始化数据的sql文件地址
  • spring.datasource.data-username: 上面data对应的sql文件履行用户名
  • spring.datasource.data-password: 上面data对应的sql文件履行用户暗码
  • spring.datasource.schema: classpath:config-schema.sql 取值也可所以数组,这里存的是初始化表结构的sql文件地址

3. 初始化sql

上面指定了两个sql,一个是用于建表的ddl,一个是用于初始化数据的dml

resources/config-schema.sql 文件对应的内容如下

CREATE TABLE `user2`
(
    `id`               int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `third_account_id` varchar(128) NOT NULL DEFAULT '' COMMENT '第三方用户ID',
    `user_name`        varchar(64)  NOT NULL DEFAULT '' COMMENT '用户名',
    `password`         varchar(128) NOT NULL DEFAULT '' COMMENT '暗码',
    `login_type`       tinyint      NOT NULL DEFAULT '0' COMMENT '登录方法: 0-微信登录,1-账号暗码登录',
    `deleted`          tinyint      NOT NULL DEFAULT '0' COMMENT '是否删除',
    `create_time`      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创立时刻',
    `update_time`      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最终更新时刻',
    PRIMARY KEY (`id`),
    KEY                `key_third_account_id` (`third_account_id`),
    KEY                `user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4  COMMENT='用户登录表';

resources/config-data.sql 文件对应的内容如下

INSERT INTO `user2` (id, third_account_id, `user_name`, `password`, login_type, deleted)
VALUES (2, '222222-0f85-4dd5-845c-7c5df3746e92', 'admin2', 'admin2', 0, 0);

II. 示例

1. 验证demo

接下来上面的作业准备完毕之后,在咱们发动项目之后,正常就会履行上面的两个sql,咱们写一个简单的验证demo

@Slf4j
@SpringBootApplication
public class Application implements ApplicationRunner {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List list = jdbcTemplate.queryForList("select * from user2 limit 2");
        log.info("发动成功,初始化数据: {}\n{}", list.size(), list);
    }
}

SpringBoot系列之数据库初始化-datasource配置方式

2. 问题记载

从上面的进程走下来,看起来很简单,可是在实际的运用进程中,很简单遇到不收效的问题,下面记载一下

2.1 只要初始化数据data.sql,没有schema.sql时,不收效

当库表现已存在时,此时咱们可能并没有上文中的config-schema.sql文件,此时对应的装备可能是


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/${database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
    initialization-mode: always
    platform: mysql
    separator: ; # 默以为 ;
    data: classpath:config-data.sql
    #data-username: root
    #data-password:
    #schema: classpath:config-schema.sql # schema有必要也存在,若只存在data,data中的sql也不会被履行

如上面所示,当咱们只指定了data时,会发现data对应的sql文件也不会被履行;即要求schema对应的sql文件也有必要同时存在

针对上面这种情况,可以考虑将data.sql中的句子,卸载schema.sql中

2.2 版别问题导致装备不收效

在SpringBoot2.5+版别,运用 spring.sql.init 替代上面的装备项

# springboot 2.5+ 版别运用下面这个
spring:
  sql:
    init:
      mode: always
      data-location: classpath:config-data.sql
      schema-location: classpath:init-schema.sql

相关的装备参数阐明如下

  • spring.sql.init.enabled:是否发动初始化的开关,默许是true。假如不想履行初始化脚本,设置为false即可。经过-D的命令行参数会更简单操控。
  • spring.sql.init.usernamespring.sql.init.password:装备履行初始化脚本的用户名与暗码。这个非常有必要,由于安全管理要求,通常给业务应用分配的用户对一些建表删表等命令没有权限。这样就可以与datasource中的用户分隔管理。
  • spring.sql.init.schema-locations:装备与schema改变相关的sql脚本,可装备多个(默许用;切割)
  • spring.sql.init.data-locations:用来装备与数据相关的sql脚本,可装备多个(默许用;切割)
  • spring.sql.init.encoding:装备脚本文件的编码
  • spring.sql.init.separator:装备多个sql文件的分隔符,默许是;
  • spring.sql.init.continue-on-error:假如履行脚本进程中碰到过错是否继续,默许是false`

2.3 mode装备不对导致不收效

当装备完之后发,发现sql没有按照预期的履行,可以检查一下spring.datasource.initialization-mode装备是否存在,且值为always

2.4 重复发动之后,报错

相同上面的项目,在第一次发动时,会履行schema对应的sql文件,创立表结构;履行data对应的sql文件,初始化数据;可是再次履行之后就会报错了,会提示表现已存在

即初始化是一次性的,第一次履行完毕之后,请将spring.datasource.initialization-mode设置为none

3. 小结

本文首要介绍了项目发动时,数据库的初始化方法,当然除了本文中介绍的spring.datasource装备之外,还有spring.jpa的装备方法

对于装备方法不太友爱的当地则在于欠好自适应操控,若表存在则不履行;若不存在则履行;后面将介绍怎么运用DataSourceInitializer来完成自主可控的数据初始化,以及更现代化一些的基于liquibase的数据库版别管理记载

III. 不能错失的源码和相关知识点

0. 项目

  • 工程:github.com/liuyueyi/sp…
  • 源码:github.com/liuyueyi/sp…

1. 微信大众号: 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和过错之处,如发现bug或许有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记载所有学习和作业中的博文,欢迎大家前去逛逛

  • 一灰灰Blog个人博客 blog.hhui.top
  • 一灰灰Blog-Spring专题博客 spring.hhui.top