- 浏览: 48939 次
- 性别:
- 来自: 沈阳
最新评论
我们都知道数据库连接是一种有限和非常昂贵的应用资源,怎样对这些资源进行高效的管理,能有效的改善整个系统的性能和健壮性。数据库连接池正是针对这个问题而提出来的。
数据库连接负责分配、释放和管理数据库连接。使数据库连接可以重复利用,而不是用一次建立一次数据库连接。
基本思路
建立一个容器
每次到这个容器里得到连接,如果为空则建立一个新连接。
当连接使用完后归还给这个容器
这里就有二个难点
1. 容器必需是同步的,线程安全的。
2. 连接怎归还连接池
方案:
针对这二个难点,我们分别提出了二个解决方法
1.使用ConcurrentLinkedQueue实现先进先出队列
ConcurrentLinkedQueue无界线程安全队列介绍
这个类在java.util.concurrent包中,我们来看看官方是怎描述这个类的
一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素.此实现采用了有效的“无等待 (wait-free)”算法
2.动态代理实现连接归还连接池
大家也可以参考刘冬在IBM发表的文章
http://www.ibm.com/developerworks/cn/java/l-connpoolproxy/
接下来我们来看看整体代码
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.Driver;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.sql.DataSource;
public class JavaGGDataSource implements DataSource {
//连接队列
private ConcurrentLinkedQueue<_Connection> connQueue = new ConcurrentLinkedQueue<_Connection>();
//存放所有连接容器
private List<_Connection> conns = new ArrayList<_Connection>();
private Driver driver = null;
private String jdbcUrl = null;
private String user = null;
private String password = null;
private int maxActive = -1;// -1为不限制连接数
private String driverClass = null;
private int timeout = 1000 * 60 * 60 * 4;// 默认为4小时,即4小时没有任何sql操作就把所有连接重新建立连接
private AtomicLong lastCheckout = new AtomicLong(System.currentTimeMillis());
private AtomicInteger connCount = new AtomicInteger();
//线程锁,主要用于新建连接和清空连接时
private ReentrantLock lock = new ReentrantLock();
public void closeAllConnection() {
}
/**
* 归还连接给连接池
*
* @param conn
*@date 2009-8-13
*@author eric.chan
*/
public void offerConnection(_Connection conn) {
connQueue.offer(conn);
}
@Override
public Connection getConnection() throws SQLException {
return getConnection(user, password);
}
/**
* 从池中得到连接,如果池中没有连接,则建立新的sql连接
*
* @param username
* @param password
* @author eric.chan
*/
@Override
public Connection getConnection(String username, String password)
throws SQLException {
checkTimeout();
_Connection conn = connQueue.poll();
if (conn == null) {
if (maxActive > 0 && connCount.get() >= maxActive) {
for (;;) {// 采用自旋方法 从已满的池中得到一个连接
conn = connQueue.poll();
if (conn != null)
break;
else
continue;
}
}
lock.lock();
try {
if (maxActive > 0 && connCount.get() >= maxActive) {
// 处理并发问题
return getConnection(username, password);
}
Properties info = new Properties();
info.put("user", username);
info.put("password", password);
Connection conn1 = loadDriver().connect(jdbcUrl, info);
conn = new _Connection(conn1, this);
int c = connCount.incrementAndGet();// 当前连接数加1
conns.add(conn);
System.out.println("info : init no. " + c + " connectioned");
} finally {
lock.unlock();
}
}
lastCheckout.getAndSet(System.currentTimeMillis());
return conn.getConnection();
}
/**
* 检查最后一次的连接时间
*
* @throws SQLException
*@date 2009-8-13
*@author eric.chan
*/
private void checkTimeout() throws SQLException {
long now = System.currentTimeMillis();
long lt = lastCheckout.get();
if ((now - lt) > timeout) {
_Connection conn = null;
lock.lock();
try {
if(connCount.get()==0)return;
while ((conn = connQueue.poll()) != null) {
System.out.println("connection " + conn + " close ");
conn.close();
conn = null;
}
for(_Connection con:conns){
con.close();
}
conns.clear();
System.out.println("info : reset all connections");
connCount.getAndSet(0);// 重置连接数计数器
lastCheckout.getAndSet(System.currentTimeMillis());
} finally {
lock.unlock();
}
}
}
/**
*
* @return
*@date 2009-8-13
*@author eric.chan
*/
private Driver loadDriver() {
if (driver == null) {
try {
driver = (Driver) Class.forName(driverClass).newInstance();
} catch (ClassNotFoundException e) {
System.out.println("error : can not find driver class " + driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
return driver;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public boolean isWrapperFor(Class iface) throws SQLException {
throw new SQLException("no Implemented isWrapperFor method");
}
@Override
public T unwrap(Class iface) throws SQLException {
throw new SQLException("no Implemented unwrap method");
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public String getUsername() {
return user;
}
public void setUsername(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClass() {
return driverClass;
}
public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout * 1000;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxActive() {
return maxActive;
}
}
/**
* 数据连接的自封装 ,是java.sql.Connection的一个钩子,主要是处理close方法
*
* @author eric
*
*/
class _Connection implements InvocationHandler {
private final static String CLOSE_METHOD_NAME = "close";
private final Connection conn;
private final JavaGGDataSource ds;
_Connection(Connection conn, JavaGGDataSource ds) {
this.conn = conn;
this.ds = ds;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
// 判断是否调用了close的方法,如果调用close方法则把连接置为无用状态
if (CLOSE_METHOD_NAME.equals(method.getName())) {
// 归还连接给连接池
ds.offerConnection(this);
} else {
// 运行非close的方法
obj = method.invoke(conn, args);
}
return obj;
}
public Connection getConnection() {
// 返回数据库连接conn的接管类,以便截住close方法
Connection conn2 = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[] { Connection.class }, this);
return conn2;
}
public void close() throws SQLException {
// 调用真正的close方法,一但调用此方法就直接关闭连接
if(conn!=null&&!conn.isClosed())
conn.close();
}
}
_Connection类是一个私有类,主要实现一个对Connection动态代理的功能(有点象windows的钩子)
说白了就是实现调用connection.close方法时我们映射到另一个方法上.
呵呵,是不是好简单呢,代码没有多复杂。
这里有一个问题要说明一吓:如果设置的maxActive值小于当前线程总数,那么当并发非常大时会出现资源争夺情况,一吓子cpu就会提高不小,所以建议设为无限制,或大于线程总数的值。
接下来我们测试测试
开五十个线程,对同一个表进行select/insert 10000次操作,每次select/insert一条记录
代码如下:
public static void main(String[] args) {
JavaGGDataSource ds = new JavaGGDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://192.168.1.6:3306/test");
ds.setPassword("ps");
ds.setUsername("name");
ds.setTimeout(300);
// ds.setMaxActive(60);
for (int i = 0; i < 50; i++) {
new GG(ds).start();
}
}
class GG extends Thread {
JavaGGDataSource ds = null;
long l = System.currentTimeMillis();
public GG(JavaGGDataSource ds) {
this.ds = ds;
}
static String sql = "insert into testgg(col1,cols) values (?,?)";
static String selectsql = "select * from testgg where id=?";
public void run() {
for (int t = 0; t < 10000; t++) {
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
//以下为insert
ps.setInt(1, 133664);
ps.setString(2, "ddd");
ps.executeUpdate();
//以下为select
ResultSet rs=ps.executeQuery();
while(rs.next()){
rs.getInt("id");
rs.getInt("col1");
}
rs.close();
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (conn != null) {
// ds.offerConnection(conn);
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println(System.currentTimeMillis() - l);
}
测试结果
50个线程select 10000*50次结果
Javaggds 406à2156毫秒 连接池有50个连接(和线程数一样)
C3p0 1235à1657毫秒 连接池有500个连接(和设置的最大连接数一样 )
50个线程insert 10000*50次结果
Javaggds 39125à52734 连接池有50个连接(和线程数一样)
C3p0 60000à65141毫秒 连接池有500个连接(和设置的最大连接数一样 )
测试分析:
c3p0是使用同锁或同步块对连接池进行同步的,所以它的时间会控制在一定范围之内
但带来的问题是线程竞争和线程等待。
Javaggds是使用了concurrent包中的无等待算法队列,这个同步是在cpu层面上做的,所以同步的块非常小,大家有兴趣可以看看CAS同步算法。
Hibernate结合
编辑hibernate 加入/修改配置为
<property name="connection.provider_class">
com.javagg.datasource.DataSourceConnectionProvider<property>
<property name="db.driverClass">com.mysql.jdbc.Driver<property>
<property name="db.jdbcUrl">jdbc:mysql://192.168.1.6:3306/test<property>
<property name="db.username">name<property>
<property name="db.password">password<property>
<property name="db.datasource">
com.javagg.datasource.JavaGGDataSource<property>
<property name="db.maxActive">-1<property>< 无限制连接数 >
<property name="db.timeout">3600<property>< 一小时timeout 单位为秒 >
DataSourceConnectonProvider代码如下:
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
public class DataSourceConnectionProvider implements ConnectionProvider {
private final static String BASE_KEY = "db.";
private final static String DATASOURCE_KEY = "db.datasource";
protected DataSource dataSource;
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#configure(java.util.Properties
* )
*/
public void configure(Properties props) throws HibernateException {
initDataSource(props);
}
/*
* (non-Javadoc)
*
* @see org.hibernate.connection.ConnectionProvider#getConnection()
*/
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#closeConnection(java.sql.
* Connection)
*/
public void closeConnection(Connection conn) throws SQLException {
if (conn != null)
conn.close();
}
/*
* (non-Javadoc)
*
* @see org.hibernate.connection.ConnectionProvider#close()
*/
public void close() throws HibernateException {
if (dataSource != null)
try {
Method mClose = dataSource.getClass().getMethod("close");
mClose.invoke(dataSource);
} catch (Exception e) {
throw new HibernateException(e);
}
dataSource = null;
}
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#supportsAggressiveRelease()
*/
public boolean supportsAggressiveRelease() {
return false;
}
/**
* Initialize the datasource
*
* @param props
* @throws HibernateException
*/
protected void initDataSource(Properties props) throws HibernateException {
String dataSourceClass = null;
Properties new_props = new Properties();
Iterator keys = props.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
if (key.equals(DATASOURCE_KEY)) {
dataSourceClass=props.getProperty(key);
} else if (key.startsWith(BASE_KEY)) {
String value = props.getProperty(key);
new_props.setProperty(key.substring(BASE_KEY.length()), value);
}
}
if (dataSourceClass == null)
throw new HibernateException("Property 'db.datasource' no defined.");
try {
dataSource = (DataSource) Class.forName(dataSourceClass).newInstance();
BeanUtils.populate(dataSource, new_props);
} catch (Exception e) {
throw new HibernateException(e);
}
}
}
接下来我们测试配置有没有成功
代码如下:
public static void main(String args[]) {
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sf = cfg.buildSessionFactory();
for (int i = 0; i < 100; i++) {
Session sess = sf.openSession();
TestGGBean pc = new TestGGBean();
pc.setCol1(1111);
pc.setCols("ddaaaa");
sess.save(pc);
sess.flush();
sess.close();
}
}
数据库连接负责分配、释放和管理数据库连接。使数据库连接可以重复利用,而不是用一次建立一次数据库连接。
基本思路
建立一个容器
每次到这个容器里得到连接,如果为空则建立一个新连接。
当连接使用完后归还给这个容器
这里就有二个难点
1. 容器必需是同步的,线程安全的。
2. 连接怎归还连接池
方案:
针对这二个难点,我们分别提出了二个解决方法
1.使用ConcurrentLinkedQueue实现先进先出队列
ConcurrentLinkedQueue无界线程安全队列介绍
这个类在java.util.concurrent包中,我们来看看官方是怎描述这个类的
一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素.此实现采用了有效的“无等待 (wait-free)”算法
2.动态代理实现连接归还连接池
大家也可以参考刘冬在IBM发表的文章
http://www.ibm.com/developerworks/cn/java/l-connpoolproxy/
接下来我们来看看整体代码
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.Driver;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.sql.DataSource;
public class JavaGGDataSource implements DataSource {
//连接队列
private ConcurrentLinkedQueue<_Connection> connQueue = new ConcurrentLinkedQueue<_Connection>();
//存放所有连接容器
private List<_Connection> conns = new ArrayList<_Connection>();
private Driver driver = null;
private String jdbcUrl = null;
private String user = null;
private String password = null;
private int maxActive = -1;// -1为不限制连接数
private String driverClass = null;
private int timeout = 1000 * 60 * 60 * 4;// 默认为4小时,即4小时没有任何sql操作就把所有连接重新建立连接
private AtomicLong lastCheckout = new AtomicLong(System.currentTimeMillis());
private AtomicInteger connCount = new AtomicInteger();
//线程锁,主要用于新建连接和清空连接时
private ReentrantLock lock = new ReentrantLock();
public void closeAllConnection() {
}
/**
* 归还连接给连接池
*
* @param conn
*@date 2009-8-13
*@author eric.chan
*/
public void offerConnection(_Connection conn) {
connQueue.offer(conn);
}
@Override
public Connection getConnection() throws SQLException {
return getConnection(user, password);
}
/**
* 从池中得到连接,如果池中没有连接,则建立新的sql连接
*
* @param username
* @param password
* @author eric.chan
*/
@Override
public Connection getConnection(String username, String password)
throws SQLException {
checkTimeout();
_Connection conn = connQueue.poll();
if (conn == null) {
if (maxActive > 0 && connCount.get() >= maxActive) {
for (;;) {// 采用自旋方法 从已满的池中得到一个连接
conn = connQueue.poll();
if (conn != null)
break;
else
continue;
}
}
lock.lock();
try {
if (maxActive > 0 && connCount.get() >= maxActive) {
// 处理并发问题
return getConnection(username, password);
}
Properties info = new Properties();
info.put("user", username);
info.put("password", password);
Connection conn1 = loadDriver().connect(jdbcUrl, info);
conn = new _Connection(conn1, this);
int c = connCount.incrementAndGet();// 当前连接数加1
conns.add(conn);
System.out.println("info : init no. " + c + " connectioned");
} finally {
lock.unlock();
}
}
lastCheckout.getAndSet(System.currentTimeMillis());
return conn.getConnection();
}
/**
* 检查最后一次的连接时间
*
* @throws SQLException
*@date 2009-8-13
*@author eric.chan
*/
private void checkTimeout() throws SQLException {
long now = System.currentTimeMillis();
long lt = lastCheckout.get();
if ((now - lt) > timeout) {
_Connection conn = null;
lock.lock();
try {
if(connCount.get()==0)return;
while ((conn = connQueue.poll()) != null) {
System.out.println("connection " + conn + " close ");
conn.close();
conn = null;
}
for(_Connection con:conns){
con.close();
}
conns.clear();
System.out.println("info : reset all connections");
connCount.getAndSet(0);// 重置连接数计数器
lastCheckout.getAndSet(System.currentTimeMillis());
} finally {
lock.unlock();
}
}
}
/**
*
* @return
*@date 2009-8-13
*@author eric.chan
*/
private Driver loadDriver() {
if (driver == null) {
try {
driver = (Driver) Class.forName(driverClass).newInstance();
} catch (ClassNotFoundException e) {
System.out.println("error : can not find driver class " + driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
return driver;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public boolean isWrapperFor(Class iface) throws SQLException {
throw new SQLException("no Implemented isWrapperFor method");
}
@Override
public T unwrap(Class iface) throws SQLException {
throw new SQLException("no Implemented unwrap method");
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public String getUsername() {
return user;
}
public void setUsername(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClass() {
return driverClass;
}
public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout * 1000;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxActive() {
return maxActive;
}
}
/**
* 数据连接的自封装 ,是java.sql.Connection的一个钩子,主要是处理close方法
*
* @author eric
*
*/
class _Connection implements InvocationHandler {
private final static String CLOSE_METHOD_NAME = "close";
private final Connection conn;
private final JavaGGDataSource ds;
_Connection(Connection conn, JavaGGDataSource ds) {
this.conn = conn;
this.ds = ds;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
// 判断是否调用了close的方法,如果调用close方法则把连接置为无用状态
if (CLOSE_METHOD_NAME.equals(method.getName())) {
// 归还连接给连接池
ds.offerConnection(this);
} else {
// 运行非close的方法
obj = method.invoke(conn, args);
}
return obj;
}
public Connection getConnection() {
// 返回数据库连接conn的接管类,以便截住close方法
Connection conn2 = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[] { Connection.class }, this);
return conn2;
}
public void close() throws SQLException {
// 调用真正的close方法,一但调用此方法就直接关闭连接
if(conn!=null&&!conn.isClosed())
conn.close();
}
}
_Connection类是一个私有类,主要实现一个对Connection动态代理的功能(有点象windows的钩子)
说白了就是实现调用connection.close方法时我们映射到另一个方法上.
呵呵,是不是好简单呢,代码没有多复杂。
这里有一个问题要说明一吓:如果设置的maxActive值小于当前线程总数,那么当并发非常大时会出现资源争夺情况,一吓子cpu就会提高不小,所以建议设为无限制,或大于线程总数的值。
接下来我们测试测试
开五十个线程,对同一个表进行select/insert 10000次操作,每次select/insert一条记录
代码如下:
public static void main(String[] args) {
JavaGGDataSource ds = new JavaGGDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://192.168.1.6:3306/test");
ds.setPassword("ps");
ds.setUsername("name");
ds.setTimeout(300);
// ds.setMaxActive(60);
for (int i = 0; i < 50; i++) {
new GG(ds).start();
}
}
class GG extends Thread {
JavaGGDataSource ds = null;
long l = System.currentTimeMillis();
public GG(JavaGGDataSource ds) {
this.ds = ds;
}
static String sql = "insert into testgg(col1,cols) values (?,?)";
static String selectsql = "select * from testgg where id=?";
public void run() {
for (int t = 0; t < 10000; t++) {
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
//以下为insert
ps.setInt(1, 133664);
ps.setString(2, "ddd");
ps.executeUpdate();
//以下为select
ResultSet rs=ps.executeQuery();
while(rs.next()){
rs.getInt("id");
rs.getInt("col1");
}
rs.close();
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (conn != null) {
// ds.offerConnection(conn);
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println(System.currentTimeMillis() - l);
}
测试结果
50个线程select 10000*50次结果
Javaggds 406à2156毫秒 连接池有50个连接(和线程数一样)
C3p0 1235à1657毫秒 连接池有500个连接(和设置的最大连接数一样 )
50个线程insert 10000*50次结果
Javaggds 39125à52734 连接池有50个连接(和线程数一样)
C3p0 60000à65141毫秒 连接池有500个连接(和设置的最大连接数一样 )
测试分析:
c3p0是使用同锁或同步块对连接池进行同步的,所以它的时间会控制在一定范围之内
但带来的问题是线程竞争和线程等待。
Javaggds是使用了concurrent包中的无等待算法队列,这个同步是在cpu层面上做的,所以同步的块非常小,大家有兴趣可以看看CAS同步算法。
Hibernate结合
编辑hibernate 加入/修改配置为
<property name="connection.provider_class">
com.javagg.datasource.DataSourceConnectionProvider<property>
<property name="db.driverClass">com.mysql.jdbc.Driver<property>
<property name="db.jdbcUrl">jdbc:mysql://192.168.1.6:3306/test<property>
<property name="db.username">name<property>
<property name="db.password">password<property>
<property name="db.datasource">
com.javagg.datasource.JavaGGDataSource<property>
<property name="db.maxActive">-1<property>< 无限制连接数 >
<property name="db.timeout">3600<property>< 一小时timeout 单位为秒 >
DataSourceConnectonProvider代码如下:
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
public class DataSourceConnectionProvider implements ConnectionProvider {
private final static String BASE_KEY = "db.";
private final static String DATASOURCE_KEY = "db.datasource";
protected DataSource dataSource;
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#configure(java.util.Properties
* )
*/
public void configure(Properties props) throws HibernateException {
initDataSource(props);
}
/*
* (non-Javadoc)
*
* @see org.hibernate.connection.ConnectionProvider#getConnection()
*/
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#closeConnection(java.sql.
* Connection)
*/
public void closeConnection(Connection conn) throws SQLException {
if (conn != null)
conn.close();
}
/*
* (non-Javadoc)
*
* @see org.hibernate.connection.ConnectionProvider#close()
*/
public void close() throws HibernateException {
if (dataSource != null)
try {
Method mClose = dataSource.getClass().getMethod("close");
mClose.invoke(dataSource);
} catch (Exception e) {
throw new HibernateException(e);
}
dataSource = null;
}
/*
* (non-Javadoc)
*
* @see
* org.hibernate.connection.ConnectionProvider#supportsAggressiveRelease()
*/
public boolean supportsAggressiveRelease() {
return false;
}
/**
* Initialize the datasource
*
* @param props
* @throws HibernateException
*/
protected void initDataSource(Properties props) throws HibernateException {
String dataSourceClass = null;
Properties new_props = new Properties();
Iterator keys = props.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
if (key.equals(DATASOURCE_KEY)) {
dataSourceClass=props.getProperty(key);
} else if (key.startsWith(BASE_KEY)) {
String value = props.getProperty(key);
new_props.setProperty(key.substring(BASE_KEY.length()), value);
}
}
if (dataSourceClass == null)
throw new HibernateException("Property 'db.datasource' no defined.");
try {
dataSource = (DataSource) Class.forName(dataSourceClass).newInstance();
BeanUtils.populate(dataSource, new_props);
} catch (Exception e) {
throw new HibernateException(e);
}
}
}
接下来我们测试配置有没有成功
代码如下:
public static void main(String args[]) {
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sf = cfg.buildSessionFactory();
for (int i = 0; i < 100; i++) {
Session sess = sf.openSession();
TestGGBean pc = new TestGGBean();
pc.setCol1(1111);
pc.setCols("ddaaaa");
sess.save(pc);
sess.flush();
sess.close();
}
}
相关推荐
### JAVA 使用数据库连接池连接Oracle数据库全代码解析 #### 一、概述 本文将详细介绍如何在Java项目中使用Apache DBCP(Database Connection Pool)来连接Oracle数据库,并提供完整的示例代码。通过这种方式,我们...
在本文中,我们将探讨如何使用Java的动态代理来实现数据库连接池,从而解决传统连接池设计中的耦合度问题和资源管理问题。 首先,数据库连接池是应用程序管理数据库连接的一种高效方式。它通过复用已建立的数据库...
在Java中,实现数据库连接池的目的是为了高效地管理和复用数据库连接,避免频繁创建和销毁连接带来的性能开销。本文将深入探讨如何用Java编写一个简单的数据库连接池,并分析其在并发访问中的应用。 首先,数据库...
数据库连接池是Java应用程序中管理数据库连接的一种高效策略,它能显著提高系统性能并减少资源消耗。本篇文章将深入解析一个...理解并掌握数据库连接池的原理和实现,对于优化Java应用程序的性能和稳定性至关重要。
在Java中,有多种数据库连接池实现,包括C3P0、DBCP和Proxool等。 **C3P0连接池配置参数详解** 1. `acquireIncrement`:当连接池中的连接耗尽时,一次同时尝试获取的连接数。默认值为3,意味着如果连接池为空,它...
接下来,我们将以Java为例,简要介绍如何使用开源库如C3P0、HikariCP或Apache DBCP来实现数据库连接池。 1. **C3P0** 是一个开源的JDBC连接池,提供了数据库连接的自动获取、释放和管理功能。在使用C3P0时,我们...
在使用数据库连接池时,常见的连接池实现有DBCP、C3p0、TomcatJdbcPool、BoneCP和Druid等。以DBCP为例,使用它需要导入commons-dbcp.jar和commons-pool.jar包。在Maven项目中,需要在pom.xml配置文件中添加相应的...
数据库连接池是Java应用程序中非常重要的...9. **与框架的集成**:在Spring框架中,可以通过配置XML或Java配置来声明式地注入数据库连接池,例如使用`org.springframework.jdbc.datasource.DriverManagerDataSource`或`...
### Java中数据库连接池原理机制详解 #### 一、引言 在现代软件开发中,尤其是在基于Java的应用程序中,数据库连接池技术是一项至关重要的技术。它能够显著提高应用程序访问数据库的效率,减少资源消耗,并简化...
数据库连接池是数据库管理中的重要概念,它在Java Web应用中尤其常见,主要用于优化数据库的连接管理和资源利用。自定义数据库连接池是为了更好地适应特定应用的需求,提高数据存取的效率,减少系统开销,避免频繁...
数据库连接池在Java应用中扮演着至关重要的角色,...通过分析源码并运行示例,你可以深入理解数据库连接池的实现细节,这将对提升Java应用的数据库性能有很大帮助。同时,这也是一次了解和比较不同连接池实现的好机会。
- **HikariCP**:高效且稳定的连接池实现,被誉为最快的Java数据库连接池。其核心jar包为`hikaricp.jar`。 - **Apache DBCP**:Apache软件基金会提供的连接池组件,包含`commons-dbcp.jar`和`commons-pool.jar`。...
在Java Web开发中,JSP(JavaServer Pages)常用于创建动态网页,而与数据库的交互是其中不可或缺的一部分。...理解并正确使用数据库连接池是提高Web应用程序性能的关键步骤,也是每个Java开发者必备的技能。
虽然题目提供的部分内容无法直接翻译或解析为有意义的代码片段,但我们可以根据上述理论知识构造一段示例代码来展示如何使用Java实现一个简单的数据库连接池: ```java import java.sql.Connection; import java....
### 基于JDBC的数据库连接池技术研究 #### 一、引言 随着互联网技术的迅猛发展,特别是Web应用的广泛普及,传统的客户端/服务器(C/S)架构已经逐渐被浏览器/服务器(B/S)三层架构所取代。在这种背景下,为了提高...
在IT行业中,数据库连接池是优化应用程序性能的关键技术之一,特别是在使用Java服务器页面(JSP)进行Web开发时。数据库连接池允许程序高效地管理与数据库的连接,减少了创建和销毁连接的开销,提高了系统资源利用率...