DynamicDBUtil.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. package org.jeecg.common.util.dynamic.db;
  2. import com.alibaba.druid.pool.DruidDataSource;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.commons.lang3.ArrayUtils;
  5. import org.jeecg.common.exception.JeecgBootException;
  6. import org.jeecg.common.exception.JeecgBootException;
  7. import org.jeecg.common.system.vo.DynamicDataSourceModel;
  8. import org.jeecg.common.util.ReflectHelper;
  9. import org.jeecg.common.util.oConvertUtils;
  10. import org.springframework.jdbc.core.JdbcTemplate;
  11. import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
  12. import javax.sql.DataSource;
  13. import java.sql.SQLException;
  14. import java.util.HashMap;
  15. import java.util.List;
  16. import java.util.Map;
  17. /**
  18. * Spring JDBC 实时数据库访问
  19. *
  20. * @author chenguobin
  21. * @version 1.0
  22. * @date 2014-09-05
  23. */
  24. @Slf4j
  25. public class DynamicDBUtil {
  26. /**
  27. * 获取数据源【最底层方法,不要随便调用】
  28. *
  29. * @param dbSource
  30. * @return
  31. */
  32. private static DruidDataSource getJdbcDataSource(final DynamicDataSourceModel dbSource) {
  33. DruidDataSource dataSource = new DruidDataSource();
  34. String driverClassName = dbSource.getDbDriver();
  35. String url = dbSource.getDbUrl();
  36. String dbUser = dbSource.getDbUsername();
  37. String dbPassword = dbSource.getDbPassword();
  38. dataSource.setDriverClassName(driverClassName);
  39. dataSource.setUrl(url);
  40. //dataSource.setValidationQuery("SELECT 1 FROM DUAL");
  41. dataSource.setTestWhileIdle(true);
  42. dataSource.setTestOnBorrow(false);
  43. dataSource.setTestOnReturn(false);
  44. dataSource.setBreakAfterAcquireFailure(true);
  45. dataSource.setConnectionErrorRetryAttempts(0);
  46. dataSource.setUsername(dbUser);
  47. dataSource.setMaxWait(30000);
  48. dataSource.setPassword(dbPassword);
  49. log.info("******************************************");
  50. log.info("* *");
  51. log.info("*====【"+dbSource.getCode()+"】=====Druid连接池已启用 ====*");
  52. log.info("* *");
  53. log.info("******************************************");
  54. return dataSource;
  55. }
  56. /**
  57. * 通过 dbKey ,获取数据源
  58. *
  59. * @param dbKey
  60. * @return
  61. */
  62. public static DruidDataSource getDbSourceByDbKey(final String dbKey) {
  63. //获取多数据源配置
  64. DynamicDataSourceModel dbSource = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey);
  65. //先判断缓存中是否存在数据库链接
  66. DruidDataSource cacheDbSource = DataSourceCachePool.getCacheBasicDataSource(dbKey);
  67. if (cacheDbSource != null && !cacheDbSource.isClosed()) {
  68. log.debug("--------getDbSourceBydbKey------------------从缓存中获取DB连接-------------------");
  69. return cacheDbSource;
  70. } else {
  71. DruidDataSource dataSource = getJdbcDataSource(dbSource);
  72. if(dataSource!=null && dataSource.isEnable()){
  73. DataSourceCachePool.putCacheBasicDataSource(dbKey, dataSource);
  74. }else{
  75. throw new JeecgBootException("动态数据源连接失败,dbKey:"+dbKey);
  76. }
  77. log.info("--------getDbSourceBydbKey------------------创建DB数据库连接-------------------");
  78. return dataSource;
  79. }
  80. }
  81. /**
  82. * 关闭数据库连接池
  83. *
  84. * @param dbKey
  85. * @return
  86. */
  87. public static void closeDbKey(final String dbKey) {
  88. DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
  89. try {
  90. if (dataSource != null && !dataSource.isClosed()) {
  91. dataSource.getConnection().commit();
  92. dataSource.getConnection().close();
  93. dataSource.close();
  94. }
  95. } catch (SQLException e) {
  96. e.printStackTrace();
  97. }
  98. }
  99. private static JdbcTemplate getJdbcTemplate(String dbKey) {
  100. DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
  101. return new JdbcTemplate(dataSource);
  102. }
  103. /**
  104. * 根据数据源获取NamedParameterJdbcTemplate
  105. * @param dbKey
  106. * @return
  107. */
  108. private static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(String dbKey) {
  109. DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
  110. return new NamedParameterJdbcTemplate(dataSource);
  111. }
  112. /**
  113. * Executes the SQL statement in this <code>PreparedStatement</code> object,
  114. * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
  115. * <code>DELETE</code>; or an SQL statement that returns nothing,
  116. * such as a DDL statement.
  117. */
  118. public static int update(final String dbKey, String sql, Object... param) {
  119. int effectCount;
  120. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  121. if (ArrayUtils.isEmpty(param)) {
  122. effectCount = jdbcTemplate.update(sql);
  123. } else {
  124. effectCount = jdbcTemplate.update(sql, param);
  125. }
  126. return effectCount;
  127. }
  128. /**
  129. * 支持miniDao语法操作的Update
  130. *
  131. * @param dbKey 数据源标识
  132. * @param sql 执行sql语句,sql支持minidao语法逻辑
  133. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  134. * @return
  135. */
  136. public static int updateByHash(final String dbKey, String sql, HashMap<String, Object> data) {
  137. int effectCount;
  138. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  139. //根据模板获取sql
  140. sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
  141. NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
  142. effectCount = namedParameterJdbcTemplate.update(sql, data);
  143. return effectCount;
  144. }
  145. public static Object findOne(final String dbKey, String sql, Object... param) {
  146. List<Map<String, Object>> list;
  147. list = findList(dbKey, sql, param);
  148. if (oConvertUtils.listIsEmpty(list)) {
  149. log.error("Except one, but not find actually");
  150. return null;
  151. }
  152. if (list.size() > 1) {
  153. log.error("Except one, but more than one actually");
  154. }
  155. return list.get(0);
  156. }
  157. /**
  158. * 支持miniDao语法操作的查询 返回HashMap
  159. *
  160. * @param dbKey 数据源标识
  161. * @param sql 执行sql语句,sql支持minidao语法逻辑
  162. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  163. * @return
  164. */
  165. public static Object findOneByHash(final String dbKey, String sql, HashMap<String, Object> data) {
  166. List<Map<String, Object>> list;
  167. list = findListByHash(dbKey, sql, data);
  168. if (oConvertUtils.listIsEmpty(list)) {
  169. log.error("Except one, but not find actually");
  170. }
  171. if (list.size() > 1) {
  172. log.error("Except one, but more than one actually");
  173. }
  174. return list.get(0);
  175. }
  176. /**
  177. * 直接sql查询 根据clazz返回单个实例
  178. *
  179. * @param dbKey 数据源标识
  180. * @param sql 执行sql语句
  181. * @param clazz 返回实例的Class
  182. * @param param
  183. * @return
  184. */
  185. @SuppressWarnings("unchecked")
  186. public static <T> Object findOne(final String dbKey, String sql, Class<T> clazz, Object... param) {
  187. Map<String, Object> map = (Map<String, Object>) findOne(dbKey, sql, param);
  188. return ReflectHelper.setAll(clazz, map);
  189. }
  190. /**
  191. * 支持miniDao语法操作的查询 返回单个实例
  192. *
  193. * @param dbKey 数据源标识
  194. * @param sql 执行sql语句,sql支持minidao语法逻辑
  195. * @param clazz 返回实例的Class
  196. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  197. * @return
  198. */
  199. @SuppressWarnings("unchecked")
  200. public static <T> Object findOneByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
  201. Map<String, Object> map = (Map<String, Object>) findOneByHash(dbKey, sql, data);
  202. return ReflectHelper.setAll(clazz, map);
  203. }
  204. public static List<Map<String, Object>> findList(final String dbKey, String sql, Object... param) {
  205. List<Map<String, Object>> list;
  206. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  207. if (ArrayUtils.isEmpty(param)) {
  208. list = jdbcTemplate.queryForList(sql);
  209. } else {
  210. list = jdbcTemplate.queryForList(sql, param);
  211. }
  212. return list;
  213. }
  214. /**
  215. * 查询数量
  216. * @param dbKey
  217. * @param sql
  218. * @param param
  219. * @return
  220. */
  221. public static Map<String, Object> queryCount(String dbKey, String sql, Map<String, Object> param){
  222. NamedParameterJdbcTemplate npJdbcTemplate = getNamedParameterJdbcTemplate(dbKey);
  223. return npJdbcTemplate.queryForMap(sql, param);
  224. }
  225. /**
  226. * 查询列表数据
  227. * @param dbKey
  228. * @param sql
  229. * @param param
  230. * @return
  231. */
  232. public static List<Map<String, Object>> findListByNamedParam(final String dbKey, String sql, Map<String, Object> param) {
  233. NamedParameterJdbcTemplate npJdbcTemplate = getNamedParameterJdbcTemplate(dbKey);
  234. List<Map<String, Object>> list = npJdbcTemplate.queryForList(sql, param);
  235. return list;
  236. }
  237. /**
  238. * 支持miniDao语法操作的查询
  239. *
  240. * @param dbKey 数据源标识
  241. * @param sql 执行sql语句,sql支持minidao语法逻辑
  242. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  243. * @return
  244. */
  245. public static List<Map<String, Object>> findListByHash(final String dbKey, String sql, HashMap<String, Object> data) {
  246. List<Map<String, Object>> list;
  247. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  248. //根据模板获取sql
  249. sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
  250. NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
  251. list = namedParameterJdbcTemplate.queryForList(sql, data);
  252. return list;
  253. }
  254. /**
  255. * 此方法只能返回单列,不能返回实体类
  256. * @param dbKey 数据源的key
  257. * @param sql sal
  258. * @param clazz 类
  259. * @param param 参数
  260. * @param <T>
  261. * @return
  262. */
  263. public static <T> List<T> findList(final String dbKey, String sql, Class<T> clazz, Object... param) {
  264. List<T> list;
  265. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  266. if (ArrayUtils.isEmpty(param)) {
  267. list = jdbcTemplate.queryForList(sql, clazz);
  268. } else {
  269. list = jdbcTemplate.queryForList(sql, clazz, param);
  270. }
  271. return list;
  272. }
  273. /**
  274. * 支持miniDao语法操作的查询 返回单列数据list
  275. *
  276. * @param dbKey 数据源标识
  277. * @param sql 执行sql语句,sql支持minidao语法逻辑
  278. * @param clazz 类型Long、String等
  279. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  280. * @return
  281. */
  282. public static <T> List<T> findListByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
  283. List<T> list;
  284. JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey);
  285. //根据模板获取sql
  286. sql = FreemarkerParseFactory.parseTemplateContent(sql, data);
  287. NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
  288. list = namedParameterJdbcTemplate.queryForList(sql, data, clazz);
  289. return list;
  290. }
  291. /**
  292. * 直接sql查询 返回实体类列表
  293. *
  294. * @param dbKey 数据源标识
  295. * @param sql 执行sql语句,sql支持 minidao 语法逻辑
  296. * @param clazz 返回实体类列表的class
  297. * @param param sql拼接注入中需要的数据
  298. * @return
  299. */
  300. public static <T> List<T> findListEntities(final String dbKey, String sql, Class<T> clazz, Object... param) {
  301. List<Map<String, Object>> queryList = findList(dbKey, sql, param);
  302. return ReflectHelper.transList2Entrys(queryList, clazz);
  303. }
  304. /**
  305. * 支持miniDao语法操作的查询 返回实体类列表
  306. *
  307. * @param dbKey 数据源标识
  308. * @param sql 执行sql语句,sql支持minidao语法逻辑
  309. * @param clazz 返回实体类列表的class
  310. * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据
  311. * @return
  312. */
  313. public static <T> List<T> findListEntitiesByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) {
  314. List<Map<String, Object>> queryList = findListByHash(dbKey, sql, data);
  315. return ReflectHelper.transList2Entrys(queryList, clazz);
  316. }
  317. }