ConnUtil.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package jnpf.database.util;
  2. import cn.hutool.core.util.ReflectUtil;
  3. import com.alibaba.druid.pool.DruidDataSource;
  4. import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
  5. import jnpf.database.model.dto.PrepSqlDTO;
  6. import jnpf.database.model.entity.DbLinkEntity;
  7. import jnpf.database.model.interfaces.DbSourceOrDbLink;
  8. import jnpf.database.source.DbBase;
  9. import jnpf.database.source.impl.DbOracle;
  10. import jnpf.exception.DataException;
  11. import jnpf.util.StringUtil;
  12. import jnpf.util.TenantHolder;
  13. import lombok.extern.slf4j.Slf4j;
  14. import java.sql.Connection;
  15. import java.sql.DriverManager;
  16. import java.sql.SQLException;
  17. import java.util.Objects;
  18. import java.util.Properties;
  19. /**
  20. * Connection数据连接相关工具类
  21. *
  22. * @author JNPF开发平台组
  23. * @version V3.2.0
  24. * @copyright 引迈信息技术有限公司
  25. * @date 2021/10/6
  26. */
  27. @Slf4j
  28. public class ConnUtil {
  29. public static Connection getConnOrDefault(DbSourceOrDbLink dbSourceOrDbLink) throws DataException {
  30. if(dbSourceOrDbLink == null){
  31. dbSourceOrDbLink = DynamicDataSourceUtil.getDataSourceUtil();
  32. }
  33. return PrepSqlDTO.getConn(dbSourceOrDbLink.init());
  34. }
  35. public static Connection getConn(DbSourceOrDbLink dbSourceOrDbLink) throws DataException {
  36. return PrepSqlDTO.getConn(dbSourceOrDbLink.init());
  37. }
  38. public static Connection getConn(DbSourceOrDbLink dbSourceOrDbLink, String dbName) throws DataException {
  39. return PrepSqlDTO.getConn(dbSourceOrDbLink.init(dbName));
  40. }
  41. public static Connection getConn(String userName, String password, String url) throws DataException {
  42. DbLinkEntity dbLinkEntity = new DbLinkEntity();
  43. dbLinkEntity.setUserName(userName);
  44. dbLinkEntity.setPassword(password);
  45. dbLinkEntity.setUrl(url);
  46. dbLinkEntity.setDbType(DbTypeUtil.getDb(url).getJnpfDbEncode());
  47. return PrepSqlDTO.getConn(dbLinkEntity);
  48. }
  49. /**
  50. * 连接Connection
  51. */
  52. @Deprecated
  53. private static Connection getConnection(DbSourceOrDbLink dbSourceOrDbLink) throws DataException {
  54. return getConnection(dbSourceOrDbLink, null);
  55. }
  56. /**
  57. * 指定库名(多租户)
  58. */
  59. @Deprecated
  60. private static Connection getConnection(DbSourceOrDbLink dataSourceUtil, String dbName) throws DataException {
  61. DbLinkEntity dbLinkEntity = dataSourceUtil.init();
  62. // Oracle特殊连接
  63. if(DbTypeUtil.checkOracle(dbLinkEntity)){ return getOracleConn(dbLinkEntity); }
  64. return getConnection(dbLinkEntity.getAutoUsername(), dbLinkEntity.getAutoPassword(), getUrl(dbLinkEntity));
  65. }
  66. /**
  67. * 基础连接方式
  68. */
  69. @Deprecated
  70. private static Connection getConnection(String userName, String password, String url) throws DataException {
  71. DbBase db = DbTypeUtil.getDb(url);
  72. return ConnCommon.createConn(db.getDriver(), userName, password, url);
  73. }
  74. /* ==================================================== */
  75. /**
  76. * oracle特殊连接方式
  77. */
  78. private static Connection getOracleConn(DbLinkEntity dsd) throws DataException {
  79. DbOracle dbOracle = new DbOracle();
  80. return dbOracle.getOracleConn(dsd, getUrl(dsd));
  81. }
  82. /*==============获取数据连接URL==============*/
  83. public static String getUrl(DbSourceOrDbLink dbSourceOrDbLink) {
  84. return getUrl(dbSourceOrDbLink, null);
  85. }
  86. /**
  87. * 指定库名(多租户)
  88. *
  89. * @param dbSourceOrDbLink 数据源
  90. * @param dbName 数据库名
  91. * @return url连接
  92. */
  93. public static String getUrl(DbSourceOrDbLink dbSourceOrDbLink, String dbName) {
  94. return DbBase.BaseCommon.getDbBaseConnUrl(dbSourceOrDbLink, dbName);
  95. }
  96. public static void switchConnectionSchema(Connection conn) throws SQLException {
  97. if(TenantDataSourceUtil.isMultiTenancy() && DynamicDataSourceUtil.isPrimaryDataSoure() && TenantHolder.getLocalTenantCache() != null) {
  98. String schema = TenantDataSourceUtil.getTenantDbName();
  99. if (StringUtil.isNotEmpty(schema)) {
  100. Connection tmpConnection = getRealConnection(conn);
  101. //多租户模式, Schema模式下降连接切换至租户库
  102. //判断数据库类型
  103. try {
  104. switch (DynamicDataSourceUtil.getPrimaryDbType()) {
  105. case DbBase.SQL_SERVER:
  106. case DbBase.MYSQL:
  107. if(!Objects.equals(tmpConnection.getCatalog(), schema)) {
  108. tmpConnection.setCatalog(schema);
  109. }
  110. break;
  111. case DbBase.POSTGRE_SQL:
  112. //POSTGRE转小写
  113. schema = schema.toLowerCase();
  114. if(!Objects.equals(tmpConnection.getSchema(), schema)) {
  115. tmpConnection.setSchema(schema);
  116. }
  117. break;
  118. case DbBase.ORACLE:
  119. //Oracle转大写
  120. schema = schema.toUpperCase();
  121. if(!Objects.equals(tmpConnection.getSchema(), schema)) {
  122. tmpConnection.setSchema(schema);
  123. }
  124. break;
  125. case DbBase.KINGBASE_ES:
  126. case DbBase.DM:
  127. default:
  128. if(!Objects.equals(tmpConnection.getSchema(), schema)) {
  129. tmpConnection.setSchema(schema);
  130. }
  131. }
  132. }catch (Exception e){
  133. //切库失败 连接不可用 需要先手动关闭链接
  134. conn.close();
  135. String url = "";
  136. if(tmpConnection instanceof ConnectionProxy){
  137. try {
  138. url = ((ConnectionProxy) tmpConnection).getDirectDataSource().getUrl();
  139. }catch (Exception ee){}
  140. }
  141. log.error("切库失败, 租户:{}, URL: {}, Msg: {}", TenantHolder.getDatasourceId(), url, e.getMessage());
  142. throw e;
  143. }
  144. }
  145. }
  146. }
  147. public static String getConnectionDbName(Connection conn) throws SQLException {
  148. Connection tmpConnection = getRealConnection(conn);
  149. String dbName;
  150. String dbCode = DbTypeUtil.getDb(tmpConnection.getMetaData().getURL()).getJnpfDbEncode();
  151. //多租户模式, Schema模式下降连接切换至租户库
  152. //判断数据库类型
  153. switch (dbCode) {
  154. case DbBase.ORACLE://DBName:Schema
  155. case DbBase.DM://DBName:Schema
  156. dbName = tmpConnection.getSchema();
  157. break;
  158. case DbBase.SQL_SERVER://DBName:CataLog
  159. case DbBase.MYSQL://DBName:CataLog
  160. case DbBase.POSTGRE_SQL://DBName:CataLog, Schema:Schema
  161. case DbBase.KINGBASE_ES://DBName:CataLog, Schema:Schema
  162. default:
  163. dbName = tmpConnection.getCatalog();
  164. }
  165. return dbName;
  166. }
  167. public static String getConnectionSchema(Connection conn) throws SQLException {
  168. Connection tmpConnection = getRealConnection(conn);
  169. String dbName;
  170. String dbCode = DbTypeUtil.getDb(tmpConnection.getMetaData().getURL()).getJnpfDbEncode();
  171. //多租户模式, Schema模式下降连接切换至租户库
  172. //判断数据库类型
  173. switch (dbCode) {
  174. case DbBase.ORACLE://DBName:Schema
  175. case DbBase.DM://DBName:Schema
  176. case DbBase.POSTGRE_SQL://DBName:CataLog, Schema:Schema
  177. case DbBase.KINGBASE_ES://DBName:CataLog, Schema:Schema
  178. case DbBase.SQL_SERVER://DBName:CataLog
  179. dbName = tmpConnection.getSchema();
  180. break;
  181. case DbBase.MYSQL://DBName:CataLog
  182. default:
  183. dbName = tmpConnection.getCatalog();
  184. }
  185. return dbName;
  186. }
  187. /**
  188. * 获取包装连接中的数据连接
  189. * @param connection
  190. * @return
  191. */
  192. public static Connection getRealConnection(Connection connection){
  193. Connection tmpConnection = connection;
  194. //Druid连接包装只允许Mysql切换Schema
  195. for (int i = 0; i < 6; i++) {
  196. //最大6次避免有不知名的数据源自己获取自己无限循环
  197. try{
  198. tmpConnection = ReflectUtil.invoke(tmpConnection, "getConnection");
  199. }catch (Exception e){
  200. break;
  201. }
  202. }
  203. return tmpConnection;
  204. }
  205. /**
  206. * 获取DruidDataSource
  207. */
  208. public static DruidDataSource getDruidDataSource(DataSourceUtil dataSourceUtil) throws DataException {
  209. DruidDataSource druidDataSource = new DruidDataSource();
  210. druidDataSource.setUsername(dataSourceUtil.getUserName());
  211. druidDataSource.setPassword(dataSourceUtil.getPassword());
  212. //jdbc-url
  213. druidDataSource.setUrl(ConnUtil.getUrl(dataSourceUtil));
  214. //数据库驱动
  215. druidDataSource.setDriverClassName(DbTypeUtil.getDb(dataSourceUtil).getDriver());
  216. return druidDataSource;
  217. }
  218. /**
  219. * 以下为ConnUtil上面非显性的公开方法
  220. * 让调用者只关注getConn方法而不造成干扰
  221. */
  222. public static class ConnCommon {
  223. /**
  224. * (基础)获取数据连接
  225. *
  226. * @param driver 驱动
  227. * @param userName 用户
  228. * @param password 密码
  229. * @param url url
  230. * @return 数据库连接
  231. * @throws DataException ignore
  232. */
  233. public static Connection createConn(String driver, String userName, String password, String url) throws DataException {
  234. try {
  235. Class.forName(driver);
  236. return DriverManager.getConnection(url, userName, password);
  237. } catch (Exception e) {
  238. e.printStackTrace();
  239. throw DataException.errorLink(e.getMessage());
  240. }
  241. }
  242. public static Connection createConnByProp(String driver, String userName, String password, String url, Properties conProps) throws DataException {
  243. try {
  244. conProps.put("user", userName);
  245. conProps.put("password", password);
  246. Class.forName(driver);
  247. return DriverManager.getConnection(url, conProps);
  248. } catch (Exception e) {
  249. throw new DataException(e.getMessage());
  250. }
  251. }
  252. /**
  253. * 开启数据库获取表注解连接
  254. *
  255. * @param dbSourceOrDbLink 数据源对象
  256. * @return ignore
  257. */
  258. public static Connection getConnRemarks(DataSourceUtil dbSourceOrDbLink) throws DataException {
  259. Properties props = new Properties();
  260. //设置可以获取remarks信息
  261. props.setProperty("remarks", "true");
  262. props.setProperty("remarksReporting", "true");
  263. //设置可以获取tables remarks信息
  264. props.setProperty("useInformationSchema", "true");
  265. return createConnByProp(DbTypeUtil.getDb(getUrl(dbSourceOrDbLink)).getDriver(), dbSourceOrDbLink.getUserName(), dbSourceOrDbLink.getPassword(),
  266. getUrl(dbSourceOrDbLink), props);
  267. }
  268. }
  269. }