SQLRunner.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. package com.primeton.dsp.dataservice.utils;
  2. import lombok.NonNull;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.commons.dbcp2.BasicDataSource;
  5. import org.apache.commons.dbutils.DbUtils;
  6. import org.apache.commons.dbutils.QueryRunner;
  7. import org.apache.commons.dbutils.handlers.MapListHandler;
  8. import org.apache.commons.io.IOUtils;
  9. import org.apache.commons.lang.StringUtils;
  10. import javax.sql.DataSource;
  11. import java.io.Closeable;
  12. import java.io.IOException;
  13. import java.sql.*;
  14. import java.sql.Date;
  15. import java.text.ParseException;
  16. import java.text.SimpleDateFormat;
  17. import java.util.*;
  18. import java.util.regex.Matcher;
  19. import java.util.regex.Pattern;
  20. /**
  21. *
  22. * 数据库执行类。主要封装了查询,更新,批量更新等一些执行SQL的方法。
  23. *
  24. * <pre>
  25. *
  26. * Created by zhaopx.
  27. * User: zhaopx
  28. * Date: 2020-03-26
  29. * Time: 10:20
  30. *
  31. * </pre>
  32. *
  33. * @author zhaopx
  34. */
  35. @Slf4j
  36. public class SQLRunner implements Closeable {
  37. protected final DataSource ds;
  38. public SQLRunner(Properties config) {
  39. this(config.getProperty("jdbc.driverClassName"),
  40. config.getProperty("jdbc.url"),
  41. config.getProperty("jdbc.user"),
  42. config.getProperty("jdbc.password"));
  43. }
  44. public SQLRunner(String driverClass,
  45. String url,
  46. String user,
  47. String password) {
  48. BasicDataSource dataSource = new BasicDataSource();
  49. dataSource.setMaxTotal(2);
  50. dataSource.setMinIdle(1);
  51. dataSource.setInitialSize(1);
  52. dataSource.setDriverClassName(driverClass);
  53. dataSource.setUrl(url);
  54. dataSource.setUsername(user);
  55. dataSource.setPassword(password);
  56. this.ds = dataSource;
  57. }
  58. public SQLRunner(@NonNull DataSource ds) {
  59. this.ds = ds;
  60. }
  61. public int update(String sql) throws SQLException {
  62. if(sql == null) {
  63. throw new SQLException("Null SQL statement");
  64. }
  65. Connection conn = ds.getConnection();
  66. if(conn == null) {
  67. throw new SQLException("Null connection");
  68. }
  69. Statement statement = null;
  70. int r = 0;
  71. try {
  72. statement = conn.createStatement();
  73. r = statement.executeUpdate(sql);
  74. } finally {
  75. close(conn, statement, null);
  76. }
  77. return r;
  78. }
  79. public int update(String sql, Object[] params) throws SQLException {
  80. QueryRunner runner = new QueryRunner(this.ds);
  81. return runner.update(sql, params);
  82. }
  83. /**
  84. * 批量更新
  85. * @param sql SQL 值 ? 代替
  86. * @param params 参数数组
  87. * @return
  88. * @throws SQLException
  89. */
  90. public int[] updateBatch(String sql, List<Object[]> params) throws SQLException {
  91. QueryRunner runner = new QueryRunner(this.ds);
  92. return runner.batch(sql, params.toArray(new Object[params.size()][]));
  93. }
  94. /**
  95. * 查询 sql,带参数
  96. * @param sql
  97. * @param params
  98. * @return
  99. * @throws SQLException
  100. */
  101. public QueryResult query(String sql, Object[] params) throws SQLException {
  102. if(params.length == 0) {
  103. // 不带参数的查询
  104. return query(sql);
  105. }
  106. // 没有参数,QueryRunner 会报错
  107. QueryRunner runner = new QueryRunner(this.ds);
  108. RSTypeHandler typeHandler = new RSTypeHandler();
  109. List<Map<String, Object>> list = runner.query(sql, typeHandler, params);
  110. QueryResult queryResult = new QueryResult(typeHandler.getTypes(), list);
  111. queryResult.setSql(sql);
  112. return queryResult;
  113. }
  114. /**
  115. * 无参数的查询
  116. * @param sql
  117. * @return
  118. * @throws SQLException
  119. */
  120. public QueryResult query(String sql) throws SQLException {
  121. Connection conn = ds.getConnection();
  122. if(conn == null) {
  123. throw new SQLException("Null connection");
  124. } else if(sql == null) {
  125. DbUtils.close(conn);
  126. throw new SQLException("Null SQL statement");
  127. } else {
  128. Statement statement = null;
  129. ResultSet rs = null;
  130. try {
  131. statement = conn.createStatement();
  132. rs = statement.executeQuery(sql);
  133. RSTypeHandler typeHandler = new RSTypeHandler();
  134. List<Map<String, Object>> list = typeHandler.handle(rs);
  135. QueryResult queryResult = new QueryResult(typeHandler.getTypes(), list);
  136. queryResult.setSql(sql);
  137. return queryResult;
  138. } catch (SQLException e) {
  139. // 没有返回值
  140. if(e.getMessage().contains("not generate a result set")) {
  141. log.warn("execute sql: '"+sql+"' success, no result set.", e);
  142. QueryResult queryResult = new QueryResult(Collections.<Map<String, Object>>emptyList(), Collections.<Map<String, Object>>emptyList());
  143. queryResult.setSql(sql);
  144. return queryResult;
  145. }
  146. throw e;
  147. } finally {
  148. close(conn, statement, rs);
  149. }
  150. }
  151. }
  152. /**
  153. * 查询 sql,带参数
  154. * @param sql
  155. * @param params
  156. * @return
  157. * @throws SQLException
  158. */
  159. public QueryResult queryOne(String sql, Object[] params) throws SQLException {
  160. if(params.length == 0) {
  161. // 不带参数的查询
  162. return query(sql);
  163. }
  164. // 没有参数,QueryRunner 会报错
  165. QueryRunner runner = new QueryRunner(this.ds);
  166. RSTypeHandler typeHandler = new RSTypeHandler();
  167. List<Map<String, Object>> list = runner.query(sql, typeHandler, params);
  168. QueryResult queryResult = new QueryResult(typeHandler.getTypes(), list);
  169. queryResult.setSql(sql);
  170. return queryResult;
  171. }
  172. @Override
  173. public void close() throws IOException {
  174. try {
  175. ((BasicDataSource)ds).close();
  176. } catch (SQLException e) {
  177. }
  178. }
  179. /**
  180. * 安静的关闭数据库链接。
  181. *
  182. * @param conn
  183. * @param ps
  184. * @param rs
  185. */
  186. public static void close(Connection conn, Statement ps, ResultSet rs) {
  187. try {
  188. if (rs != null) {
  189. rs.close();
  190. }
  191. } catch (Exception e) { }
  192. try {
  193. if (ps != null) {
  194. ps.close();
  195. }
  196. } catch (Exception e) {}
  197. try {
  198. if (conn != null) {
  199. conn.close();
  200. }
  201. } catch (Exception e) {}
  202. }
  203. /**
  204. * 根据 SQL 的 ${field} 按照 map 中的参数替换,组成一个新的 SQL 返回。
  205. * @param sql 支持 ${field} 的变量替换
  206. * @param params 参数,如果没有参数则会原路返回
  207. * @return 返回新的变量替换的 SQL
  208. */
  209. public static String getMatchSQL(String sql, Map<String, Object> params){
  210. Matcher matcher = Pattern.compile("(\\$\\{\\w+\\})").matcher(sql);
  211. StringBuffer sb = new StringBuffer();
  212. while (matcher.find()) {
  213. String group = matcher.group();
  214. String field = StringUtils.trim(group.substring(2, group.length() - 1));
  215. String val = (String)params.get(field);
  216. if(val == null) {
  217. continue;
  218. }
  219. matcher.appendReplacement(sb, val);
  220. }
  221. matcher.appendTail(sb);
  222. return sb.toString();
  223. }
  224. /**
  225. * 获取一个 sql 内 from table 的table 名称,如果是join sql 则获取多个from的表名
  226. * @param sql
  227. * @return
  228. */
  229. public static String[] getSQLTable(String sql) {
  230. //select sql 里 from 后的字符和join后的字符,都是表名
  231. //正则表达式,不区分大小写的模式
  232. Pattern compile = Pattern.compile("(TABLE|JOIN|FROM){1}\\s+(\\w+)", Pattern.CASE_INSENSITIVE);
  233. Matcher matcher = compile.matcher(sql);
  234. List<String> names = new ArrayList<>(3);
  235. while (matcher.find()) {
  236. String name = matcher.group(2);
  237. names.add(name);
  238. }
  239. return names.toArray(new String[names.size()]);
  240. }
  241. /**
  242. *
  243. * 把值 val 转为 type 的类型, type 为数据库的类型
  244. *
  245. * @param val 字段值
  246. * @param type 字段类型
  247. * @return
  248. */
  249. public static Object convertVal(Object val, String type) {
  250. if(val == null) {
  251. return null;
  252. }
  253. type = type.toUpperCase();
  254. switch (type){
  255. case "VARCHAR":
  256. case "VARCHAR2":
  257. case "TEXT":
  258. case "BLOB":
  259. return val instanceof String ? (String)val : String.valueOf(val);
  260. case "TINYINT":
  261. case "SMALLINT":
  262. case "INT":
  263. return val instanceof Number ? ((Number)val).intValue() : Integer.parseInt(String.valueOf(val));
  264. case "DECIMAL":
  265. case "FLOAT":
  266. return val instanceof Number ? ((Number)val).floatValue() : Float.parseFloat(String.valueOf(val));
  267. case "DOUBLE":
  268. return val instanceof Number ? ((Number)val).doubleValue() : Float.parseFloat(String.valueOf(val));
  269. case "BIGINT":
  270. return val instanceof Number ? ((Number)val).longValue() : Long.parseLong(String.valueOf(val));
  271. case "DATETIME":
  272. if(val instanceof java.util.Date){
  273. return new Timestamp(((java.util.Date)val).getTime());
  274. } else if(val instanceof Number) {
  275. return new Timestamp(((Number) val).longValue());
  276. }
  277. try {
  278. return new Timestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(val.toString()).getTime());
  279. } catch (ParseException e) {
  280. throw new IllegalArgumentException(e);
  281. }
  282. case "DATE":
  283. if(val instanceof java.util.Date){
  284. return new Date(((java.util.Date)val).getTime());
  285. } else if(val instanceof Number) {
  286. return new Date(((Number) val).longValue());
  287. }
  288. try {
  289. return new Date(new SimpleDateFormat("yyyy-MM-dd").parse(val.toString()).getTime());
  290. } catch (ParseException e) {
  291. throw new IllegalArgumentException(e);
  292. }
  293. case "TIME":
  294. if(val instanceof java.util.Date){
  295. return new Time(((java.util.Date)val).getTime());
  296. } else if(val instanceof Number) {
  297. return new Time(((Number) val).longValue());
  298. }
  299. try {
  300. return new Time(new SimpleDateFormat("HH:mm:ss").parse(val.toString()).getTime());
  301. } catch (ParseException e) {
  302. throw new IllegalArgumentException(e);
  303. }
  304. default:
  305. return val instanceof String ? (String)val : String.valueOf(val);
  306. }
  307. }
  308. }