JDBC/InvocationHandler动态代理实现数据库连接池、数据源
来源:互联网 发布:linux终端退出命令 编辑:程序博客网 时间:2024/05/17 08:40
Java的JDBC编程中,数据库的连接和关闭是十分耗费资源的。当对数据库的访问不是很频繁时,可以在每次访问数据库时建立一个连接,用完之后关闭。但是,对于一个复杂的数据库应用,频繁的建立、关闭连接,会极大的减低系统性能,造成瓶颈。所以可以使用数据库连接池来达到连接资源的共享,使得对于数据库的连接可以使高效、安全的复用。
MyDataSource 实现数据库连接池
通过自定义数据库了连接MyConnection(包裹了真正的Connection),使用一个LinkedList存放MyConnection,当一个数据库连接使用完成后,重新添加到LinkedList中,实现连接的复用。数据库连接池初始化时,构造多个数据库连接,虽然此时比较耗时,但是能够实现连接池的复用,提高效率。
package com.jdbc.datasource;import java.sql.*;import java.util.LinkedList;/** * 数据库连接池 * 自定义实现数据源 * */public class MyDataSource { private static final String URL = "jdbc:postgresql://localhost:5432/db"; private static final String USER = "postgres"; private static final String PASSWORD = "root"; private static final int INI_COUNT = 5; // 初始连接数 private static final int MAX_COUNT = 10; // 最大连接数 public int curCount= 0; // 当前连接数 // add remove频繁,LinkedList 效率由于 ArrayList LinkedList<Connection> connsPool = new LinkedList<Connection>(); /** * 初始构造多个数据库连接 */ public MyDataSource() { try { for (int i = 0; i < INI_COUNT; i++) { this.connsPool.add(this.createConnection()); curCount++; } } catch (SQLException e) { e.printStackTrace(); } } /** * 创建连接 * @return * @throws SQLException */ public Connection createConnection() throws SQLException { Connection realConn = DriverManager.getConnection(URL, USER, PASSWORD); // MyConnection conn = new MyConnection(this, realConn); /*** Connection 的代理类,绑定真正的Connection,拦截 close()方法 ***/ MyConnectionHandler pHandler = new MyConnectionHandler(this); return pHandler.bind(realConn); } /** * 释放 * @param conn 数据库连接 */ public void free(Connection conn) { this.connsPool.addLast(conn); } /** * 获取连接 * @return * @throws SQLException */ public Connection getConnection() throws SQLException { Connection conn = null; /*** 同步加锁 ***/ synchronized (connsPool) { if (this.connsPool.size() > 0) { conn = this.connsPool.removeFirst(); return conn; } else if (curCount < MAX_COUNT) { // 连接池里面没有连接,且当前连接数没有达到最大连接 this.curCount++; // 创建新连接 conn = this.createConnection(); return conn; } throw new SQLException(" 连接池里已无可用连接 ... "); } }}
MyConnection 实现 Connection接口方式
将自定义类MyConnection实现Connection接口,重写close()方法,关闭时重新放入连接池,其他的非close()方法则直接转交给真正的Connection实现即可。该方式的缺点是,需要实现Connection接口的所有方法。
package com.jdbc.datasource;import java.sql.*;import java.util.*;import java.util.concurrent.Executor;/** * MyConnection 代理 Connection,实现 Connection接口 * 相当于Connection的子类,可以和Connection一样操作 * 代理了所有对真正的Connection操作 * 重要:close()方法重写,关闭时重新放入连接池 * 不足:需要重写所有方法 * 改进:改用Proxy代理模式实现,只对close()方法进行拦截,不修改其他方法 * */public class MyConnection implements Connection { private MyDataSource myDataSource = null; // 数据源 private Connection realConn = null; // 真正的connection private static final int MAX_USE_COUNT = 5; // 最大使用次数 private int curUseCount = 0; // 当前使用次数 MyConnection(MyDataSource myDataSource, Connection realConn) { this.myDataSource = myDataSource; this.realConn = realConn; } /** * close()方法重写 * 未超过最大使用次数,关闭时重新放入连接池 * @throws SQLException */ @Override public void close() throws SQLException { curUseCount++; if (curUseCount < MAX_USE_COUNT) { this.myDataSource.connsPool.addLast(this); } else { this.realConn.close(); this.myDataSource.curCount--; } } /** * 其他方法直接交给realConn实现 * @throws SQLException */ @Override public boolean isClosed() throws SQLException { return this.realConn.isClosed(); } //其他方法略...}
InvocationHandler动态代理实现方式
MyConnectionHandler类实现InvocationHandler接口,最主要包括两个步骤:
- Proxy.newProxyInstance()方法
this.warpedConn = (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { Connection.class }, this);
使用包裹后的Connection代理真正的Connection - 重写invoke()方法
public Object invoke(Object proxy, Method method, Object[] args)
拦截代理对应的方法。
package com.jdbc.datasource;import java.lang.reflect.*;import java.sql.Connection;/** * Connection 代理类 * 拦截 close()方法 * */public class MyConnectionHandler implements InvocationHandler { private Connection realConn = null; // 真正的连接 private Connection warpedConn = null; // 包裹的连接(代理连接) private MyDataSource myDataSource = null; // 连接池 private static final int MAX_USE_COUNT = 5; // 最大使用次数 private int curUseCount = 0; // 当前使用次数 /** * 构造方法 * @param myDataSource 连接池 */ public MyConnectionHandler(MyDataSource myDataSource) { this.myDataSource = myDataSource; } /** * 绑定真正的连接到包裹连接 * @param realConn 真正的连接 * @return */ public Connection bind(Connection realConn) { /*** 真正的连接,用于数据库的其他操作 ***/ this.realConn = realConn; /*** 代理模式动态生成类 ,实现了Connection.Class 接口, 其方法作用在当前handler上 ***/ /*** 用于拦截 realConn.close() 方法 ***/ this.warpedConn = (Connection) Proxy.newProxyInstance(this.getClass() .getClassLoader(), new Class[] { Connection.class }, this); return this.warpedConn; // 返回包裹后的连接 } /** * 重写 invoke() 方法 * 拦截close()方法,关闭连接是重新放回到数据库连接池 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*** 拦截 realConn.close() 方法 ***/ if (method.getName().equals("close")) { curUseCount++; if (curUseCount < MAX_USE_COUNT) { this.myDataSource.connsPool.addLast(this.warpedConn); } else { this.realConn.close(); this.myDataSource.curCount--; } } /*** 其他方法,直接执行到realConn上 ***/ return method.invoke(this.realConn, args); }}
Apache Commons DBCP 数据源
数据源一般不需要自己实现,apache DBCP数据源就是一种很好的开源实现。
将数据源的相关配置信息以配置文件的方式进行设置,读取配置文件,生成数据源即可。DBCP数据源会自动管理数据库连接池,JDBC操作直接从数据源中获取Connection即可。
DBCP数据源配置信息:
#连接设置driverClassName=org.postgresql.Driverurl=jdbc:postgresql://localhost:5432/dbusername=postgrespassword=root#<!-- 初始化连接 -->initialSize=10#最大连接数量maxActive=50#<!-- 最大空闲连接 -->maxIdle=20#<!-- 最小空闲连接 -->minIdle=5#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->maxWait=60000#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。connectionProperties=useUnicode=true;characterEncoding=gbk#指定由连接池所创建的连接的自动提交(auto-commit)状态。defaultAutoCommit=true#driver default 指定由连接池所创建的连接的只读(read-only)状态。#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)defaultReadOnly=#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLEdefaultTransactionIsolation=READ_UNCOMMITTED
JdbcUtil类使用DBCP数据源:
package com.utils;import java.io.*;import java.sql.*;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp2.BasicDataSourceFactory;//import com.jdbc.datasource.MyDataSource;public class JdbcUtil {/* private static final String URL = "jdbc:postgresql://localhost:5432/db"; private static final String USER = "postgres"; private static final String PASSWORD = "root";*/ // 使用自定义数据源 // private static MyDataSource myDataSource = null; // 使用Apache的框架,提供数据源,实现了DataSource接口 private static DataSource myDataSource = null; /** * 私有构造方法 */ private JdbcUtil() { } /** * 静态代码注册驱动 */ static { try { Class.forName("org.postgresql.Driver").newInstance(); // 使用自定义数据源 // myDataSource = new MyDataSource(); // 使用Apache的框架,提供数据源,实现了DataSource接口 Properties prop = new Properties(); InputStream is = JdbcUtil.class.getClassLoader(). getResourceAsStream("dbcpconfig.properties"); prop.load(is); myDataSource = BasicDataSourceFactory.createDataSource(prop); } catch (Exception e) { e.printStackTrace(); } } /** * 获取datasource * @return */ public static final DataSource GetDataSource() { return myDataSource; } /** * 获取数据库连接 * @return */ public static final Connection GetConnection() { Connection conn = null; try { // conn = DriverManager.getConnection(URL, USER, PASSWORD); conn = myDataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 关闭相关资源 * @param rs * @param st * @param conn */ public static final void Free(ResultSet rs, Statement st, Connection conn) { try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (st != null) st.close(); } catch (SQLException e) { e.printStackTrace(); } finally { if (conn != null) try { conn.close(); // myDataSource.free(conn); } catch (Exception e) { e.printStackTrace(); } } } }}
0 0
- JDBC/InvocationHandler动态代理实现数据库连接池、数据源
- JDBC(三)数据库连接池,动态代理
- JAVA动态代理实现 Proxy InvocationHandler
- InvocationHandler+工厂设计模式 实现动态代理
- Java动态代理实现接口invocationHandler
- 动态代理 Proxy InvocationHandler
- 动态代理proxy ,InvocationHandler
- 动态代理 Proxy InvocationHandler
- 关于InvocationHandler动态代理
- jbdc数据库连接池----动态代理实现MyConnectionPool
- JDK使用InvocationHandler和Proxy实现动态代理
- Java动态代理借助Proxy与InvocationHandler实现
- 使用JDK中的InvocationHandler、Proxy实现动态代理
- 动态代理两个类Proxy和InvocationHandler的模拟实现
- java动态代理实现Proxy和InvocationHandler cglib
- Java 基于JDK中的InvocationHandler实现动态代理
- 数据库连接池、动态代理
- java动态代理-InvocationHandler Proxy
- leetcode_c++:树:Recover Binary Search Tree(099)
- python+webdriver自动化测试第一天
- 一个应用启动另一个应用+开机启动应用
- java编程题及答案
- Spark相关
- JDBC/InvocationHandler动态代理实现数据库连接池、数据源
- L2-013. 红色警报-PAT团体程序设计天梯赛GPLT(图的连通分量个数统计)
- WPF中的命令(一)- 使用命令的步骤
- Nike Shoes younger sister for more
- 使用EmBitz编译mbed提示mbed_wait_api.c:(.text.wait+0x0): multiple definition of `wait'
- ConcurrentHashMap从jdk1.7到jdk1.8的变化
- Hello,my new world
- Linux /dev目录详解------/dev/null和/dev/zero
- HDU 1024 Max Sum Plus Plus DP