DdlHelper.java 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright (c) 2011-2023, baomidou (jobob@qq.com).
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.baomidou.mybatisplus.extension.ddl;
  17. import com.baomidou.mybatisplus.core.toolkit.StringPool;
  18. import com.baomidou.mybatisplus.extension.ddl.history.IDdlGenerator;
  19. import com.baomidou.mybatisplus.extension.ddl.history.MysqlDdlGenerator;
  20. import com.baomidou.mybatisplus.extension.ddl.history.OracleDdlGenerator;
  21. import com.baomidou.mybatisplus.extension.ddl.history.PostgreDdlGenerator;
  22. import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory;
  23. import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.*;
  24. import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.apache.ibatis.io.Resources;
  27. import org.apache.ibatis.jdbc.ScriptRunner;
  28. import org.apache.ibatis.jdbc.SqlRunner;
  29. import org.springframework.core.io.ClassPathResource;
  30. import javax.sql.DataSource;
  31. import java.io.*;
  32. import java.nio.charset.Charset;
  33. import java.sql.Connection;
  34. import java.sql.SQLException;
  35. import java.time.LocalDateTime;
  36. import java.time.format.DateTimeFormatter;
  37. import java.util.List;
  38. import java.util.Map;
  39. import java.util.Objects;
  40. /**
  41. * DDL 辅助类
  42. *
  43. * @author hubin
  44. * @since 2021-06-22
  45. */
  46. @Slf4j
  47. public class DdlHelper {
  48. /**
  49. * 允许 SQL 脚本文件
  50. *
  51. * @param ddlGenerator DDL 生成器
  52. * @param connection 数据库连接
  53. * @param sqlFiles SQL 文件列表
  54. * @param autoCommit 自动提交事务
  55. * @throws SQLException SQLException
  56. */
  57. public static void runScript(IDdlGenerator ddlGenerator, Connection connection, List<String> sqlFiles, boolean autoCommit) throws SQLException {
  58. // 执行自定义 DDL 信息
  59. final String jdbcUrl = connection.getMetaData().getURL();
  60. final String schema = DdlHelper.getDatabase(jdbcUrl);
  61. SqlRunner sqlRunner = new SqlRunner(connection);
  62. ScriptRunner scriptRunner = getScriptRunner(connection, autoCommit);
  63. if (null == ddlGenerator) {
  64. ddlGenerator = getDdlGenerator(jdbcUrl);
  65. }
  66. if (!ddlGenerator.existTable(schema, sql -> {
  67. try {
  68. Map<String, Object> resultMap = sqlRunner.selectOne(sql);
  69. if (null != resultMap && !StringPool.ZERO.equals(String.valueOf(resultMap.get(StringPool.NUM)))) {
  70. return true;
  71. }
  72. } catch (SQLException e) {
  73. log.error("run script sql:{} , error: {}", sql, e.getMessage());
  74. }
  75. return false;
  76. })) {
  77. scriptRunner.runScript(new StringReader(ddlGenerator.createDdlHistory()));
  78. }
  79. // 执行 SQL 脚本
  80. for (String sqlFile : sqlFiles) {
  81. try {
  82. List<Map<String, Object>> objectMap = sqlRunner.selectAll(ddlGenerator.selectDdlHistory(sqlFile, StringPool.SQL));
  83. if (null == objectMap || objectMap.isEmpty()) {
  84. log.debug("run script file: {}", sqlFile);
  85. String[] sqlFileArr = sqlFile.split(StringPool.HASH);
  86. if (Objects.equals(2, sqlFileArr.length)) {
  87. // 命令间的分隔符
  88. scriptRunner.setDelimiter(sqlFileArr[1]);
  89. // 原始文件路径
  90. sqlFile = sqlFileArr[0];
  91. } else {
  92. scriptRunner.setDelimiter(StringPool.SEMICOLON);
  93. }
  94. File file = new File(sqlFile);
  95. if (file.exists()) {
  96. scriptRunner.runScript(new FileReader(file));
  97. } else {
  98. scriptRunner.runScript(new InputStreamReader(getInputStream(sqlFile)));
  99. }
  100. sqlRunner.insert(ddlGenerator.insertDdlHistory(sqlFile, StringPool.SQL, getNowTime()));
  101. }
  102. } catch (Exception e) {
  103. log.error("run script sql:{} , error: {} , Please check if the table `ddl_history` exists", sqlFile, e.getMessage());
  104. }
  105. }
  106. }
  107. /**
  108. * 允许 SQL 脚本文件
  109. *
  110. * @param ddlGenerator DDL 生成器
  111. * @param dataSource 数据源
  112. * @param sqlFiles SQL 文件列表
  113. * @param autoCommit 自动提交事务
  114. */
  115. public static void runScript(IDdlGenerator ddlGenerator, DataSource dataSource, List<String> sqlFiles, boolean autoCommit) {
  116. try (Connection connection = dataSource.getConnection()) {
  117. runScript(ddlGenerator, connection, sqlFiles, autoCommit);
  118. } catch (Exception e) {
  119. log.error("run script error: {}", e.getMessage());
  120. }
  121. }
  122. public static InputStream getInputStream(String path) throws Exception {
  123. return new ClassPathResource(path).getInputStream();
  124. }
  125. protected static String getNowTime() {
  126. return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
  127. }
  128. public static ScriptRunner getScriptRunner(Connection connection, boolean autoCommit) {
  129. ScriptRunner scriptRunner = new ScriptRunner(connection);
  130. Resources.setCharset(Charset.forName(StringPool.UTF_8));
  131. scriptRunner.setAutoCommit(autoCommit);
  132. scriptRunner.setEscapeProcessing(false);
  133. scriptRunner.setRemoveCRs(true);
  134. scriptRunner.setStopOnError(true);
  135. scriptRunner.setFullLineDelimiter(false);
  136. return scriptRunner;
  137. }
  138. protected static IDdlGenerator getDdlGenerator(String jdbcUrl) throws RuntimeException {
  139. IDialect dialect = DialectFactory.getDialect(JdbcUtils.getDbType(jdbcUrl));
  140. if (dialect instanceof MySqlDialect) {
  141. return MysqlDdlGenerator.newInstance();
  142. }
  143. if (dialect instanceof PostgreDialect) {
  144. return PostgreDdlGenerator.newInstance();
  145. }
  146. if (dialect instanceof OracleDialect || dialect instanceof Oracle12cDialect) {
  147. return OracleDdlGenerator.newInstance();
  148. }
  149. throw new RuntimeException("The database is not supported");
  150. }
  151. public static String getDatabase(String jdbcUrl) {
  152. String[] urlArr = jdbcUrl.split("://");
  153. if (urlArr.length == 2) {
  154. String[] dataArr = urlArr[1].split("/");
  155. if (dataArr.length > 1) {
  156. return dataArr[1].split("\\?")[0];
  157. }
  158. }
  159. return null;
  160. }
  161. }