• jdbc 使用数据源连接池技术升级 BaseDao


    1. jdbc.driver=com.mysql.cj.jdbc.Driver
    2. jdbc.url=jdbc:mysql:///fruitdb
    3. jdbc.user=root
    4. jdbc.pwd=123456
    5. jdbc.init_size=5
    6. jdbc.max_active=20
    7. jdbc.max_wait=3000
    1. package com.csdn.mymvc.dao;
    2. import com.alibaba.druid.pool.DruidDataSource;
    3. import com.csdn.mymvc.util.ClassUtil;
    4. import javax.sql.DataSource;
    5. import java.io.IOException;
    6. import java.io.InputStream;
    7. import java.lang.reflect.ParameterizedType;
    8. import java.lang.reflect.Type;
    9. import java.sql.*;
    10. import java.util.ArrayList;
    11. import java.util.List;
    12. import java.util.Properties;
    13. public abstract class BaseDao {
    14. private String entityClassName;
    15. public BaseDao() {
    16. // this 是谁? this代表的是 FruitDaoImpl 的实例对象,因为 BaseDao是抽象类,不能直接创建对象,所以 new 的是它的子类对象 FruitDaoImpl
    17. // this.getClass() 获取的是 FruitDaoImpl 的Class对象
    18. // getGenericSuperclass() 获取到的是:BaseDao
    19. // Type 是顶层接口,表示所有的类型。它有一个子接口:ParameterizedType
    20. ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
    21. // Actual:实际的
    22. // getActualTypeArguments() 获取实际的类型参数
    23. Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
    24. Type actualTypeArgument = actualTypeArguments[0];
    25. // System.out.println(actualTypeArgument.getTypeName());//com.csdn.fruit.pojo.Fruit
    26. entityClassName = actualTypeArgument.getTypeName();
    27. initDataSource();
    28. }
    29. private DataSource dataSource;
    30. //加载jdbc.properties文件
    31. private void initDataSource() {
    32. try {
    33. InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
    34. Properties properties = new Properties();
    35. properties.load(inputStream);
    36. String driver = properties.getProperty("jdbc.driver", "com.mysql.cj.jdbc.Driver");
    37. String url = properties.getProperty("jdbc.url", "jdbc:mysql:///fruitdb");
    38. String user = properties.getProperty("jdbc.user", "root");
    39. String pwd = properties.getProperty("jdbc.pwd", "123456");
    40. Integer initSize = Integer.parseInt(properties.getProperty("jdbc.init_size", "5"));
    41. Integer maxActive = Integer.parseInt(properties.getProperty("jdbc.max_active", "10"));
    42. Integer maxWait = Integer.parseInt(properties.getProperty("jdbc.max_wait", "5000"));
    43. DruidDataSource druidDataSource = new DruidDataSource();
    44. druidDataSource.setDriverClassName(driver);
    45. druidDataSource.setUrl(url);
    46. druidDataSource.setUsername(user);
    47. druidDataSource.setPassword(pwd);
    48. druidDataSource.setInitialSize(initSize);
    49. druidDataSource.setMaxActive(maxActive);
    50. druidDataSource.setMaxWait(maxWait);
    51. dataSource = druidDataSource;
    52. } catch (IOException e) {
    53. throw new RuntimeException(e);
    54. }
    55. }
    56. private Connection getConn() throws SQLException {
    57. return dataSource.getConnection();
    58. }
    59. private void close(Connection conn, PreparedStatement psmt, ResultSet rs) {
    60. try {
    61. if (rs != null) {
    62. rs.close();
    63. }
    64. if (psmt != null) {
    65. psmt.close();
    66. }
    67. if (conn != null && !conn.isClosed()) {
    68. conn.close();
    69. }
    70. } catch (SQLException e) {
    71. throw new RuntimeException(e);
    72. }
    73. }
    74. //抽取执行更新方法
    75. //执行更新,返回影响行数
    76. //如果是执行 insert,那么可以尝试返回自增列的值
    77. protected int executeUpdate(String sql, Object... params) {
    78. boolean insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
    79. Connection conn = null;
    80. PreparedStatement psmt = null;
    81. try {
    82. conn = getConn();
    83. psmt = insertFlag ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
    84. setParams(psmt, params);
    85. int count = psmt.executeUpdate();
    86. if (insertFlag) {
    87. ResultSet rs = psmt.getGeneratedKeys();
    88. if (rs.next()) {
    89. Long id = rs.getLong(1);
    90. count = id.intValue();
    91. }
    92. }
    93. return count;
    94. } catch (SQLException e) {
    95. throw new RuntimeException(e);
    96. } finally {
    97. close(conn, psmt, null);
    98. }
    99. }
    100. //设置参数
    101. private void setParams(PreparedStatement psmt, Object... params) throws SQLException {
    102. if (params != null && params.length > 0) {
    103. for (int i = 0; i < params.length; i++) {
    104. psmt.setObject(i + 1, params[i]);
    105. }
    106. }
    107. }
    108. //执行查询,返回集合
    109. protected List executeQuery(String sql, Object... params) {
    110. List list = new ArrayList<>();
    111. Connection conn = null;
    112. PreparedStatement psmt = null;
    113. ResultSet rs = null;
    114. try {
    115. conn = getConn();
    116. psmt = conn.prepareStatement(sql);
    117. setParams(psmt, params);
    118. rs = psmt.executeQuery();
    119. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    120. while (rs.next()) {
    121. //T t = new T(); T仅仅是一个符号,所以不能 new
    122. T t = (T) ClassUtil.createInstance(entityClassName);
    123. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    124. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    125. for (int i = 1; i <= columnCount; i++) {
    126. //假设循环 5 次,得到 5 个值,应该对应的是一个对象的 5 个属性的值
    127. String columnName = rsmd.getColumnLabel(i);
    128. Object columnValue = rs.getObject(i);
    129. //给 t 这个对象的 columnName 属性赋 columnValue 值
    130. ClassUtil.setProperty(t, columnName, columnValue);
    131. }
    132. list.add(t);
    133. }
    134. return list;
    135. } catch (SQLException e) {
    136. throw new RuntimeException(e);
    137. } finally {
    138. close(conn, psmt, rs);
    139. }
    140. }
    141. protected T load(String sql, Object... params) {
    142. Connection conn = null;
    143. PreparedStatement psmt = null;
    144. ResultSet rs = null;
    145. try {
    146. conn = getConn();
    147. psmt = conn.prepareStatement(sql);
    148. setParams(psmt, params);
    149. rs = psmt.executeQuery();
    150. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    151. if (rs.next()) {
    152. //T t = new T(); T仅仅是一个符号,所以不能 new
    153. T t = (T) ClassUtil.createInstance(entityClassName);
    154. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    155. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    156. for (int i = 1; i <= columnCount; i++) {
    157. //假设循环 5 次,得到 5 个值,应该对应的是一个对象的 5 个属性的值
    158. String columnName = rsmd.getColumnLabel(i);
    159. Object columnValue = rs.getObject(i);
    160. //给 t 这个对象的 columnName 属性赋 columnValue 值
    161. ClassUtil.setProperty(t, columnName, columnValue);
    162. }
    163. return t;
    164. }
    165. } catch (SQLException e) {
    166. throw new RuntimeException(e);
    167. } finally {
    168. close(conn, psmt, rs);
    169. }
    170. return null;
    171. }
    172. //select max(age) as max_age , avg(age) as avg_age from t_user
    173. // 28 24.5
    174. //select deptNo,avg(sal) as avg_sal from emp group by deptNo
    175. /**
    176. * d001 3500
    177. * d002 3650
    178. * d003 2998
    179. */
    180. protected List executeComplexQuery(String sql, Object... params) {
    181. List list = new ArrayList<>();
    182. Connection conn = null;
    183. PreparedStatement psmt = null;
    184. ResultSet rs = null;
    185. try {
    186. conn = getConn();
    187. psmt = conn.prepareStatement(sql);
    188. setParams(psmt, params);
    189. rs = psmt.executeQuery();
    190. ResultSetMetaData rsmd = rs.getMetaData();//元数据,结果集的结构数据
    191. while (rs.next()) {
    192. int columnCount = rsmd.getColumnCount();//获取结果集的列的数据
    193. Object[] arr = new Object[columnCount];
    194. //jdbc中都是从 1 开始,所以要把 i 改成 从 1 开始
    195. for (int i = 1; i <= columnCount; i++) {
    196. Object columnValue = rs.getObject(i);
    197. //数组从 0 开始,所以要减 1
    198. arr[i - 1] = columnValue;
    199. }
    200. list.add(arr);
    201. }
    202. return list;
    203. } catch (SQLException e) {
    204. throw new RuntimeException(e);
    205. } finally {
    206. close(conn, psmt, rs);
    207. }
    208. }
    209. }

    • 只有增删改查方法才去处理异常,其他的辅助性的方法都直接往外抛 ,因为这些方法将来都会在增删改查方法里面去调用

     

    •  一旦我们用数据源连接池对象技术,这里的 conn.close() 就不是真正的关闭,而是把这个对象重新归还给池子,我们把这个称为面向对象的多态现象,说明他仅仅是把他的一个标签从正在使用设置为空闲,但是这个对象没有关闭,这个close()相当于是一个多态。

    •  真正的实现类是DruidPooledConnection,德鲁伊池子的连接,下面是close方法的源码
    1. public void close() throws SQLException {
    2. if (!this.disable) {
    3. DruidConnectionHolder holder = this.holder;
    4. if (holder == null) {
    5. if (this.dupCloseLogEnable) {
    6. LOG.error("dup close");
    7. }
    8. } else {
    9. DruidAbstractDataSource dataSource = holder.getDataSource();
    10. boolean isSameThread = this.getOwnerThread() == Thread.currentThread();
    11. if (!isSameThread) {
    12. dataSource.setAsyncCloseConnectionEnable(true);
    13. }
    14. if (dataSource.isAsyncCloseConnectionEnable()) {
    15. this.syncClose();
    16. } else if (CLOSING_UPDATER.compareAndSet(this, 0, 1)) {
    17. try {
    18. Iterator var4 = holder.getConnectionEventListeners().iterator();
    19. while(true) {
    20. if (!var4.hasNext()) {
    21. List filters = dataSource.getProxyFilters();
    22. if (filters.size() > 0) {
    23. FilterChainImpl filterChain = new FilterChainImpl(dataSource);
    24. filterChain.dataSource_recycle(this);
    25. } else {
    26. this.recycle();
    27. }
    28. break;
    29. }
    30. ConnectionEventListener listener = (ConnectionEventListener)var4.next();
    31. listener.connectionClosed(new ConnectionEvent(this));
    32. }
    33. } finally {
    34. CLOSING_UPDATER.set(this, 0);
    35. }
    36. this.disable = true;
    37. }
    38. }
    39. }
    40. }

  • 相关阅读:
    Linux中定时任务以及开机自启相关
    商业智能中的决策, 数据和数据处理方法
    Postgresql源码(64)查询执行——子模块Executor(2)执行前的数据结构和执行过程
    C专家编程 第8章 为什么程序员无法分清万圣节和圣诞节 8.10 轻松一下---国际C语言混乱代码大赛
    NX二次开发-远程开发模式(客户端和服务端).Ner和Jave远程框架
    【大模型系列】指令微调
    【Gradio-Windows-Linux】解决share=True无法创建共享链接,缺少frpc_windows_amd64_v0.2
    java: 错误: 无效的源发行版:17
    药师帮再冲刺上市:研发远低于营销,债务高企,张步镇为董事长
    基于复杂环境下的雷达目标检测技术(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/m0_65152767/article/details/134078743