Java Web基础的查漏补缺——编写一个自己的数据库连接池
发布日期:2021-06-30 18:04:35 浏览次数:2 分类:技术文章

本文共 12989 字,大约阅读时间需要 43 分钟。

其实,在这篇文章中,我就已详细介绍过如何编写一个自己的数据库连接池了。本文只不过是再一次的重温。

一个非常简单的自定义数据库连接池

该小节只是简单模拟一个池子的概念,让大家有个对连接池有个认识。待会我们自己编写的数据库连接池因为要存放一些数据库连接,所以关于如何获取数据库连接的操作,我们就抽取到一个工具类中,例如JDBCUtil类。

package com.meimeixia.util;import java.io.InputStream;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;public class JDBCUtil {
static String driverClass = null; static String url = null; static String name = null; static String password= null; static{
try {
//1. 创建一个属性配置对象 Properties properties = new Properties();// InputStream is = new FileInputStream("jdbc.properties"); //使用类加载器,去读取src底下的资源文件。 InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); //导入输入流。 properties.load(is); //读取属性 driverClass = properties.getProperty("driverClass"); url = properties.getProperty("url"); name = properties.getProperty("name"); password = properties.getProperty("password"); } catch (Exception e) {
e.printStackTrace(); } } /** * 获取连接对象 * @return */ public static Connection getConn(){
Connection conn = null; try {
Class.forName(driverClass); //静态代码块 ---> 类加载了,就执行。 java.sql.DriverManager.registerDriver(new Driver()); //DriverManager.registerDriver(new com.mysql.jdbc.Driver()); //DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb"); //2. 建立连接 参数一: 协议 + 访问的数据库 , 参数二: 用户名 , 参数三: 密码。 conn = DriverManager.getConnection(url, name, password); } catch (Exception e) {
e.printStackTrace(); } return conn; } /** * 释放资源 * @param conn * @param st * @param rs */ public static void release(Connection conn , Statement st , ResultSet rs){
closeRs(rs); closeSt(st); closeConn(conn); } public static void release(Connection conn , Statement st){
closeSt(st); closeConn(conn); } private static void closeRs(ResultSet rs){
try {
if(rs != null){
rs.close(); } } catch (SQLException e) {
e.printStackTrace(); }finally{
rs = null; } } private static void closeSt(Statement st){
try {
if(st != null){
st.close(); } } catch (SQLException e) {
e.printStackTrace(); }finally{
st = null; } } private static void closeConn(Connection conn){
try {
if(conn != null){
conn.close(); } } catch (SQLException e) {
e.printStackTrace(); }finally{
conn = null; } }}

接着,正式来编写我们自己的数据库连接池。一开始先往池子里面放10个连接,即开始就创建10个连接,来的程序可以通过getConnection方法获取连接,用完之后,使用addBack方法归还连接,而且,记得还要扩容。

在这里插入图片描述
最后,对我们自己编写的数据库连接池进行测试。

package com.meimeixia.util;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import javax.sql.DataSource;import org.junit.Test;public class TestPool {
@Test public void testPool() {
Connection conn = null; PreparedStatement ps = null; MyDataSource dataSource = new MyDataSource(); try {
conn = dataSource.getConnection(); String sql = "insert into account values(NULL,'xilali',10)"; ps = conn.prepareStatement(sql); ps.executeUpdate(); } catch (SQLException e) {
e.printStackTrace(); } finally {
try {
ps.close(); } catch (SQLException e) {
e.printStackTrace(); } //归还连接 //conn.close(); dataSource.addBack(conn); //JDBCUtil.release(conn, ps); } } }

自定义数据库连接池出现的问题

以上自定义数据库连接池出现了如下一些问题:

  • 对象没有做成单例的。在哪里使用,都需要new MyDataSource(),这就会造成有多个对象的情况出现,那就不只一个池子了;

  • 需要额外记住addBack这个方法。sun公司定义的数据库连接池里面并没有这个addBack方法,所以谁需要用我们这个连接池,就需要记住这个方法是用来回收连接对象的;

  • 无法面向接口编程。由于我们的连接池直接定义成了一个类,并且里面还额外添加了一个addBack方法,这就造成了我们无法面向接口编程。即我们再也不能编写如下代码了:

    DataSource dataSource = new MyDataSource();//因为DataSource接口里面没有定义addBack方法

解决自定义数据库连接池出现的问题

怎么解决以上那些问题呢?这里以addBack方法为切入点。由于多了一个addBack方法,所以使用这个连接池的地方,需要额外记住这个方法,并且还不能面向接口编程。我们不打算添加addBack方法,而是扩展原来的close方法。让close方法不关闭连接,而是把连接对象归还给池子。要想实现这个需求,有以下几种方式:

  • 直接修改JDBC里面的那个Connection接口的具体实现,让它的close方法别关闭连接,而是变成回收连接对象。答案是无法办到,因为咱们没办法修改人家的源代码;
  • 既然不能直接修改,那么我们改成自己定义一个类,然后继承那个Connection接口的实现类,然后在它的close方法基础上,加入我们的回收逻辑。答案也是无法办到,因为我们根本不知道Connection接口的实现类是哪一个;
  • 使用装饰者模式来实现;
  • 使用动态代理技术,拦截你对真实业务对象的访问,采用拦截的方式进行增强,这也是终极解决方案。例如Spring AOP(向切面编程)。

下面,我们就以装饰者模式来改进上面编写的自定义数据库连接池。首先,编写一个ConnectionWrap包装类来继承Connection接口。

package com.meimeixia.util;import java.sql.Array;import java.sql.Blob;import java.sql.CallableStatement;import java.sql.Clob;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.NClob;import java.sql.PreparedStatement;import java.sql.SQLClientInfoException;import java.sql.SQLException;import java.sql.SQLWarning;import java.sql.SQLXML;import java.sql.Savepoint;import java.sql.Statement;import java.sql.Struct;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.concurrent.Executor;public class ConnectionWrap implements Connection {
Connection connection = null; List
list; public ConnectionWrap(Connection connection, List
list) {
super(); this.connection = connection; this.list = list; } @Override public void close() throws SQLException {
//connection.close(); System.out.println("有人来归还连接对象了,归还之前,池子里面是:" + list.size()); list.add(connection); System.out.println("有人来归还连接对象了,归还之后...,池子里面是:" + list.size()); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql); } @Override public
T unwrap(Class
iface) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class
iface) throws SQLException {
// TODO Auto-generated method stub return false; } @Override public Statement createStatement() throws SQLException {
// TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public String nativeSQL(String sql) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public void setAutoCommit(boolean autoCommit) throws SQLException {
// TODO Auto-generated method stub } @Override public boolean getAutoCommit() throws SQLException {
// TODO Auto-generated method stub return false; } @Override public void commit() throws SQLException {
// TODO Auto-generated method stub } @Override public void rollback() throws SQLException {
// TODO Auto-generated method stub } @Override public boolean isClosed() throws SQLException {
// TODO Auto-generated method stub return false; } @Override public DatabaseMetaData getMetaData() throws SQLException {
// TODO Auto-generated method stub return null; } @Override public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub } @Override public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub return false; } @Override public void setCatalog(String catalog) throws SQLException {
// TODO Auto-generated method stub } @Override public String getCatalog() throws SQLException {
// TODO Auto-generated method stub return null; } @Override public void setTransactionIsolation(int level) throws SQLException {
// TODO Auto-generated method stub } @Override public int getTransactionIsolation() throws SQLException {
// TODO Auto-generated method stub return 0; } @Override public SQLWarning getWarnings() throws SQLException {
// TODO Auto-generated method stub return null; } @Override public void clearWarnings() throws SQLException {
// TODO Auto-generated method stub } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
// TODO Auto-generated method stub return null; } @Override public Map
> getTypeMap() throws SQLException {
// TODO Auto-generated method stub return null; } @Override public void setTypeMap(Map
> map) throws SQLException { // TODO Auto-generated method stub } @Override public void setHoldability(int holdability) throws SQLException { // TODO Auto-generated method stub } @Override public int getHoldability() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Savepoint setSavepoint() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Savepoint setSavepoint(String name) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void rollback(Savepoint savepoint) throws SQLException { // TODO Auto-generated method stub } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { // TODO Auto-generated method stub } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Clob createClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Blob createBlob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public NClob createNClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public SQLXML createSQLXML() throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isValid(int timeout) throws SQLException { // TODO Auto-generated method stub return false; } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public String getClientInfo(String name) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Properties getClientInfo() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setSchema(String schema) throws SQLException { // TODO Auto-generated method stub } @Override public String getSchema() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void abort(Executor executor) throws SQLException { // TODO Auto-generated method stub } @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getNetworkTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } }

紧接着,改进我们自定义的数据库连接池。这里,我并没有使用单例模式来设计该类,实际上,这里应使用单例模式。

在这里插入图片描述
最后,对完善好的自定义数据库连接池进行测试。

package com.meimeixia.util;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import javax.sql.DataSource;import org.junit.Test;public class TestPool {
@Test public void testPool() {
Connection conn = null; PreparedStatement ps = null; MyDataSource dataSource = new MyDataSource(); try {
conn = dataSource.getConnection(); String sql = "insert into account values(NULL,'xilali',10)"; ps = conn.prepareStatement(sql); ps.executeUpdate(); } catch (SQLException e) {
e.printStackTrace(); } finally {
try {
ps.close(); } catch (SQLException e) {
e.printStackTrace(); } //归还连接 //conn.close(); //dataSource.addBack(conn); JDBCUtil.release(conn, ps); } } }

转载地址:https://liayun.blog.csdn.net/article/details/94969231 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Ajax进阶篇(一)——异步校验用户名
下一篇:Java Web基础的查漏补缺——事务的安全隐患

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月23日 20时59分01秒