DAOServiceImpl.java 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package com.primeton.dsp.upgrader;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.io.IOUtils;
  4. import org.apache.commons.lang.StringUtils;
  5. import org.jsoup.Jsoup;
  6. import org.jsoup.nodes.Document;
  7. import org.jsoup.nodes.Element;
  8. import org.jsoup.parser.ParseSettings;
  9. import org.jsoup.parser.Parser;
  10. import org.jsoup.select.Elements;
  11. import org.springframework.core.io.ClassPathResource;
  12. import org.springframework.jdbc.core.ColumnMapRowMapper;
  13. import org.springframework.jdbc.core.JdbcTemplate;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. import java.nio.charset.StandardCharsets;
  17. import java.sql.Connection;
  18. import java.sql.DatabaseMetaData;
  19. import java.sql.SQLException;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Optional;
  25. import java.util.regex.Matcher;
  26. import java.util.regex.Pattern;
  27. /**
  28. * 为了升级元数据,兼容 hibernate 的 API
  29. *
  30. * <pre>
  31. *
  32. * Created by zhaopx.
  33. * User: zhaopx
  34. * Date: 2020/6/3
  35. * Time: 11:12
  36. *
  37. * </pre>
  38. *
  39. * @author zhaopx
  40. */
  41. @Slf4j
  42. public class DAOServiceImpl {
  43. /**
  44. * SQL #var# 类型的替换
  45. */
  46. public static final Pattern SQL_VAR_PATTERN = Pattern.compile("(#(\\w|\\.|-|_)+#)");
  47. public final JdbcTemplate jdbcTemplate;
  48. /**
  49. * SQL statement 缓存
  50. */
  51. private final static Map<String, String> sqlCache = new HashMap<>();
  52. public DAOServiceImpl(JdbcTemplate jdbcTemplate) {
  53. this.jdbcTemplate = jdbcTemplate;
  54. if (sqlCache.isEmpty()) {
  55. // 未初始化,则初始化一次
  56. try {
  57. init(jdbcTemplate);
  58. } catch (Exception e) {
  59. throw new IllegalStateException("无法加载 SQL 声明文件。", e);
  60. }
  61. }
  62. }
  63. /**
  64. * 注意:静态,同步方法
  65. *
  66. * @param jdbcTemplate
  67. * @throws Exception
  68. */
  69. private synchronized static void init(JdbcTemplate jdbcTemplate) throws Exception {
  70. if (!sqlCache.isEmpty()) {
  71. return;
  72. }
  73. Connection connection = jdbcTemplate.getDataSource().getConnection();
  74. try {
  75. DatabaseMetaData metaData = connection.getMetaData();
  76. String productName = metaData.getDatabaseProductName();
  77. log.info("database product name: {}", productName);
  78. String sqlXmlPath = String.format("META-INF/sqlxml/%s/upgradeSql.xml", Optional.ofNullable(productName).orElse("mysql").toLowerCase());
  79. ClassPathResource pathResource = new ClassPathResource(sqlXmlPath);
  80. try (InputStream in = pathResource.getInputStream()) {
  81. String content = IOUtils.toString(in, StandardCharsets.UTF_8);
  82. sqlCache.putAll(readProperties(content));
  83. }
  84. log.info("load sql xml file: {} success.", sqlXmlPath);
  85. } finally {
  86. try {
  87. connection.close();
  88. } catch (Exception e) {
  89. }
  90. }
  91. }
  92. protected static Map<String, String> readProperties(String xml) {
  93. Map<String, String> prop = new HashMap<>();
  94. // 保持 properties 中的配置是大小写区分的,否则全是小写的
  95. Parser parser = Parser.xmlParser();
  96. // 大小写敏感
  97. parser.settings(ParseSettings.preserveCase);
  98. Document doc = Jsoup.parse(xml, "http://www.primeton.com/dsp", parser);
  99. Elements statements = doc.select("statement");
  100. if (statements.size() > 0) {
  101. for (Element statement : statements) {
  102. prop.put(statement.attr("id"), statement.text());
  103. }
  104. }
  105. return prop;
  106. }
  107. /**
  108. * 获取一个无须替换参数的 SQL
  109. *
  110. * @param name
  111. * @return
  112. */
  113. public String getSQL(String name) {
  114. return getSQL(name, new HashMap());
  115. }
  116. /**
  117. * 获取 SQL, 替换模板
  118. *
  119. * @param name
  120. * @param params
  121. * @return
  122. */
  123. public String getSQL(String name, Map<String, Object> params) {
  124. params = Optional.ofNullable(params).orElse(new HashMap());
  125. String sql = sqlCache.get(name);
  126. if (params.isEmpty()) {
  127. return sql;
  128. }
  129. Map<String, String> varParam = new HashMap<>(params.size());
  130. for (Map.Entry<String, Object> entry : params.entrySet()) {
  131. varParam.put(entry.getKey(), "?");
  132. }
  133. return getFullString(sql, varParam);
  134. }
  135. /**
  136. * 根据 String 的 #field# 按照 map 中的参数替换,组成一个新的 SQL 返回。
  137. *
  138. * @param sql 支持 #field# 的变量替换
  139. * @param params 参数,如果没有参数则会原路返回
  140. * @return 返回新的变量替换的 SQL
  141. */
  142. public static String getFullString(String sql, Map<String, String> params) {
  143. Matcher matcher = SQL_VAR_PATTERN.matcher(sql);
  144. StringBuffer sb = new StringBuffer();
  145. while (matcher.find()) {
  146. String group = matcher.group();
  147. String field = StringUtils.trim(group.substring(1, group.length() - 1));
  148. String val = params.get(field);
  149. if (val == null) {
  150. continue;
  151. }
  152. matcher.appendReplacement(sb, val);
  153. }
  154. matcher.appendTail(sb);
  155. return sb.toString();
  156. }
  157. /**
  158. * 执行查询 SQL 无参数
  159. *
  160. * @param sql
  161. * @return
  162. */
  163. public List<Map> queryForMap(String sql) {
  164. return queryForMap(sql, new String[]{});
  165. }
  166. /**
  167. * 执行一次查询
  168. *
  169. * @param sql
  170. * @param params
  171. * @return
  172. */
  173. public List<Map> queryForMap(String sql, Object[] params) {
  174. params = Optional.ofNullable(params).orElse(new Object[]{});
  175. return (List) jdbcTemplate.query(sql, new ColumnMapRowMapper(), params);
  176. }
  177. /**
  178. * 执行一次查询
  179. *
  180. * @param sql
  181. * @param params
  182. * @return
  183. */
  184. public Map queryForObjectMap(String sql, Object[] params) {
  185. List<Map> rs = queryForMap(sql, params);
  186. return rs.isEmpty() ? Collections.emptyMap() : rs.get(0);
  187. }
  188. /**
  189. * 执行一个 更新 SQL
  190. *
  191. * @param sql
  192. * @return
  193. */
  194. public int updateSQL(String sql) {
  195. return updateSQL(sql, new String[]{});
  196. }
  197. /**
  198. * 执行一个 更新 SQL
  199. *
  200. * @param sql
  201. * @param params
  202. * @return
  203. */
  204. public int updateSQL(String sql, Object[] params) {
  205. params = Optional.ofNullable(params).orElse(new Object[]{});
  206. return jdbcTemplate.update(sql, params);
  207. }
  208. /**
  209. * 批量执行 SQL
  210. *
  211. * @param batchSql
  212. * @return
  213. */
  214. public int[] batchUpdateSQL(String... batchSql) throws SQLException {
  215. if (batchSql.length == 0) {
  216. return new int[]{};
  217. }
  218. return jdbcTemplate.batchUpdate(batchSql);
  219. }
  220. }