当前位置:Gxlcms > 数据库问题 > 自定义数据库连接池实现方式 MySQL

自定义数据库连接池实现方式 MySQL

时间:2021-07-01 10:21:17 帮助过:10人阅读

com.herbert.test.db; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.LinkedList; import java.util.Properties; import java.util.logging.Logger; /** * 实现数据库连接池 */ public class JdbcConnectionsPool implements DataSource { // /* * 使用静态块代码,初始化连接池,创建连接池的中最小链接数量连接, * 创建linkedlist集合,将这些连接放入集合中 */ //创建linkedlist集合 private static LinkedList<Connection> linkedlist1 = new LinkedList<Connection>(); public static String GENERATOR_JDBCDRIVER = ""; public static String GENERATOR_JDBCURL = ""; public static String GENERATOR_JDBCUSERNAME = ""; public static String GENERATOR_JDBCPASSWORD = ""; private static int jdbcConnectionInitSize;//最小连接数量 private static int max = 1; //当前最大连接数量=max*jdbcConnectionInitSize private static Properties prop = new Properties(); static { //通过反射机制获取访问db.properties文件 InputStream in = Object.class.getResourceAsStream("/generator.properties"); try { //加载db.properties文件 prop.load(in); //获取db.properties文件中的数据库连接信息 GENERATOR_JDBCDRIVER = prop.getProperty("generator.jdbc.driver").trim(); GENERATOR_JDBCURL = prop.getProperty("generator.jdbc.url").trim(); GENERATOR_JDBCUSERNAME = prop.getProperty("generator.jdbc.username").trim(); GENERATOR_JDBCPASSWORD = prop.getProperty("generator.jdbc.password").trim(); jdbcConnectionInitSize = Integer.parseInt(prop.getProperty("jdbcConnectionInitSize")); Class.forName(GENERATOR_JDBCDRIVER); //创建最小连接数个数据库连接对象以备使用 for (int i = 0; i < jdbcConnectionInitSize; i++) { Connection conn = DriverManager.getConnection(GENERATOR_JDBCURL, GENERATOR_JDBCUSERNAME, GENERATOR_JDBCPASSWORD); System.out.println("获取到了链接" + conn); //将创建好的数据库连接对象添加到Linkedlist集合中 linkedlist1.add(conn); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public Connection getConnection() throws SQLException { //如果集合中没有数据库连接对象了,且创建的数据库连接对象没有达到最大连接数量,可以再创建一组数据库连接对象以备使用 if (linkedlist1.size() == 0 && max <= jdbcConnectionInitSize) { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } for (int i = 0; i < jdbcConnectionInitSize; i++) { Connection conn = DriverManager.getConnection(GENERATOR_JDBCURL, GENERATOR_JDBCUSERNAME, GENERATOR_JDBCPASSWORD); System.out.println("获取到了链接" + conn); //将创建好的数据库连接对象添加到Linkedlist集合中 linkedlist1.add(conn); } max++; } if (linkedlist1.size() > 0) { //从linkedlist集合中取出一个数据库链接对象Connection使用 final Connection conn1 = linkedlist1.removeFirst(); System.out.println("linkedlist1数据库连接池大小是" + linkedlist1.size()); /*返回一个Connection对象,并且设置Connection对象方法调用的限制, *当调用connection类对象的close()方法时会将Connection对象重新收集放入linkedlist集合中。 */ return (Connection) Proxy.newProxyInstance(JdbcConnectionsPool.class.getClassLoader(),//这里换成JdbcConnectionsPool.class.getClassLoader();也行 new Class[] { Connection.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (!method.getName().equalsIgnoreCase("close")) { return method.invoke(conn1, args); } else { linkedlist1.add(conn1); System.out.println(conn1 + "对象被释放,重新放回linkedlist集合中!"); System.out.println("此时Linkedlist集合中有" + linkedlist1.size() + "个数据库连接对象!"); return null; } } }); } else { System.out.println("连接数据库失败!"); } return null; } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } }

 

技术图片

对方法进行进一步封装

package com.herbert.test.db;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Created by Herbert on 2018/7/23.
 */
public class JdbcConnectionPoolUtil {
    /**
     * @Field: pool
     * 数据库连接池
     */
    private static JdbcConnectionsPool pool = new JdbcConnectionsPool();

    /**
     * @return Connection数据库连接对象
     * @throws SQLException
     * @Method: getConnection
     * @Description: 从数据库连接池中获取数据库连接对象
     */
    public static Connection getConnection() throws SQLException {
        return pool.getConnection();
    }

    /**
     * @param conn
     * @param st
     * @param rs
     * @Method: release
     * @Description: 释放资源,
     * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
     */
    public static void release(Connection conn, Statement st, ResultSet rs) {
        if (rs != null) {
            try {
                //关闭存储查询结果的ResultSet对象
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (st != null) {
            try {
                //关闭负责执行SQL命令的Statement对象
                st.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                //关闭Connection数据库连接对象
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

 

技术图片

测试方法

 public static void main(String[] args) throws SQLException {

        JdbcConnectionPoolUtil jcpt = new JdbcConnectionPoolUtil();
        List list = new ArrayList();
        Connection c = null;
        Statement stmt = null;
        try {
            c = jcpt.getConnection();
            c.setAutoCommit(false);
            stmt = c.createStatement();
            String sql = "SELECT id FROM test";
            PreparedStatement preState = c.prepareStatement(sql);

            ResultSet rs = preState.executeQuery();

            while (rs.next()) {
                String id = rs.getString("id");
                list.add(id);
            }
            jcpt.release(c, stmt, rs);
        } catch (Exception e) {
            System.err.println(e.getClass().getName() + ": " + e.getMessage());
            System.exit(0);
        }
        System.out.println("测试:"+list.toString());

    }

 

技术图片

输出结果:

获取到了链接com.mysql.jdbc.JDBC4Connection@b1a58a3
获取到了链接com.mysql.jdbc.JDBC4Connection@46ee7fe8
获取到了链接com.mysql.jdbc.JDBC4Connection@722c41f4
获取到了链接com.mysql.jdbc.JDBC4Connection@2957fcb0
获取到了链接com.mysql.jdbc.JDBC4Connection@f2a0b8e
获取到了链接com.mysql.jdbc.JDBC4Connection@64a294a6
获取到了链接com.mysql.jdbc.JDBC4Connection@61e717c2
获取到了链接com.mysql.jdbc.JDBC4Connection@504bae78
获取到了链接com.mysql.jdbc.JDBC4Connection@5fcfe4b2
获取到了链接com.mysql.jdbc.JDBC4Connection@3f8f9dd6
linkedlist1数据库连接池大小是9
com.mysql.jdbc.JDBC4Connection@b1a58a3对象被释放,重新放回linkedlist集合中!
此时Linkedlist集合中有10个数据库连接对象!
测试:[1, 2]

 

技术图片

异常处理

java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection异常问题解决
技术图片

代码如下

Connection proxy = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(),
                Connection.class.getInterfaces(), new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        if ("close".equals(method.getName())) {
                            returnConn(conn);
                            return null;
                        } else {
                            return method.invoke(conn, args);
                        }
                    }
                });

 

技术图片

在使用动态代理增强Connection连接对象的close方法时,我碰到了如题所示的异常。通过搜索我发现这个异常出现的原因在于我使用的mysql数据库驱动的问题,由于数据库驱动不同,Connection.class.getInterfaces()返回的结果也不同,它返回的是一个Class[]数组,然而此数组的第一个元素必须是Connection才能把创建的代理类转为Connection对象,否则就会报错。

  所以这里我们可以采取一个替代方式替换Connection.class.getInterfaces(),即new Class[] { Connection.class },这样无论数据库驱动是什么版本的驱动,都能保证这个类型转换不出错。

 

 欢迎关注公众号

技术图片技术图片?

自定义数据库连接池实现方式 MySQL

标签:row   use   tor   height   load   case   inpu   wrapper   关闭   

人气教程排行