一、需求
- 在项目启动时,自动新建数据表
二、实现思路
-
创建触发类
-
实现SpringBoot的ApplicationRunner接口
-
编写建表语句常量
-
实现run方法,并在run方法中使用JDBC工具类的建表方法,传入建表语句常亮,完成建表
三、代码实现(末尾附完整代码)
- 创建触发类,实现ApplicationRunner接口
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.HashMap;/*** 项目启动的程序触发器** @author Odinpeng* @since 2023/11/29**/@Slf4j
@Component
@Order(0) //表示触发的顺序,越小越靠前
public class TableBuildingTrigger implements ApplicationRunner {}
注:
一个项目可以有多个启动触发器
@Order的value属性表示启动触发器的执行顺序
value属性越小,该启动触发器的执行顺序越靠前(可以为负数)
- 编写建表语句常量
// 建表语句1private static final String USER_TABLE = "CREATE TABLE user_table "+ "( id Integer NOT NULL COMMENT 'id',"+ " username varchar(20) NOT NULL COMMENT '用户名',"+ " password varchar(4) NOT NULL COMMENT '密码',"+ " PRIMARY KEY (id) ) COMMENT='用户表'";// 建表语句2private static final String ORDER_TABLE = "CREATE TABLE order_table "+ "( id Integer NOT NULL COMMENT 'id',"+ " orderName varchar(20) NOT NULL COMMENT '订单名',"+ " price Integer NOT NULL COMMENT '价格',"+ " PRIMARY KEY (id) ) COMMENT='订单表'";
- 引入JDBC工具类,实现ApplicationRunner接口的run方法完成建表
// 重写run方法@Overridepublic void run(ApplicationArguments args) throws Exception {// 将表名和建表语句存入mapHashMap<String, String> tableMap = new HashMap<String, String>() {{put("user_table", USER_TABLE);put("order_table", ORDER_TABLE);}};// 遍历建表tableMap.forEach((key, value) -> {//执行建表方法,在建表方法中判断当前表是否存在if (!checkTable(key, value)) {log.error("初始化{}核心配置表失败,执行sql:{}", key, value);throw new BizException("建表失败");}});}/*** 检查表是否存在,不存在新建表** @param tableName 表名* @param createSql 建表语句* @return*/private boolean checkTable(String tableName, String createSql) {// 查询指定表名的数量String sql = "select count(table_name) from information_schema.tables where table_name like '%s'";// 将表名动态拼接到以上sql中String querySql = String.format(sql, tableName);Integer total = jdbcTemplate.queryForObject(querySql, Integer.class);// 若查询指定表名的数量<=0,说明当前表不存在,则新增表if (total <= 0) {// 查询当前数据库版本String versionSql = "select version()";String version = jdbcTemplate.queryForObject(versionSql, String.class);// 若当前数据库版本为5.7开头,则将字符集由"utf8mb4"替换为"utf8"(MySQL5.7默认字符集是"utf8mb4",支持4字节字符,而utf8支持3字节)if (version.startsWith("5.7")) {createSql = createSql.replaceAll("utf8mb4", "utf8");}// 新建表int update = jdbcTemplate.update(createSql);if (update <= 0) {return false;}}return true;}
四、完整代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.HashMap;/*** 项目启动的程序触发器** @author Odinpeng* @since 2023/11/29**/@Slf4j
@Component
@Order(0) //表示触发的顺序,越小越靠前
public class TableBuildingTrigger implements ApplicationRunner {// 引入JDBC工具类,用于建表和查询表是否存在@Resourceprivate JdbcTemplate jdbcTemplate;// 建表语句1private static final String USER_TABLE = "CREATE TABLE user_table "+ "( id Integer NOT NULL COMMENT 'id',"+ " username varchar(20) NOT NULL COMMENT '用户名',"+ " password varchar(4) NOT NULL COMMENT '密码',"+ " PRIMARY KEY (id) ) COMMENT='用户表'";// 建表语句2private static final String ORDER_TABLE = "CREATE TABLE order_table "+ "( id Integer NOT NULL COMMENT 'id',"+ " orderName varchar(20) NOT NULL COMMENT '订单名',"+ " price Integer NOT NULL COMMENT '价格',"+ " PRIMARY KEY (id) ) COMMENT='订单表'";@Overridepublic void run(ApplicationArguments args) throws Exception {// 将表名和建表语句存入mapHashMap<String, String> tableMap = new HashMap<String, String>() {{put("user_table", USER_TABLE);put("order_table", ORDER_TABLE);}};// 遍历建表,并查询表是否存在tableMap.forEach((key, value) -> {//执行建表方法,在建表方法中判断当前表是否存在if (!checkTable(key, value)) {log.error("初始化{}核心配置表失败,执行sql:{}", key, value);throw new BizException("建表失败");}});}/*** 检查表是否存在,不存在新建表** @param tableName 表名* @param createSql 建表语句* @return*/private boolean checkTable(String tableName, String createSql) {// 查询指定表名的数量String sql = "select count(table_name) from information_schema.tables where table_name like '%s'";// 将表名动态拼接到以上sql中String querySql = String.format(sql, tableName);Integer total = jdbcTemplate.queryForObject(querySql, Integer.class);// 若查询指定表名的数量<=0,说明当前表不存在,则新增表if (total <= 0) {// 查询当前数据库版本String versionSql = "select version()";String version = jdbcTemplate.queryForObject(versionSql, String.class);// 若当前数据库版本为5.7开头,则将字符集由"utf8mb4"替换为"utf8"(MySQL5.7默认字符集是"utf8mb4",支持4字节字符,而utf8支持3字节)if (version.startsWith("5.7")) {createSql = createSql.replaceAll("utf8mb4", "utf8");}// 新建表int update = jdbcTemplate.update(createSql);if (update <= 0) {return false;}}return true;}
}