对象池化是目前非常常用的一种系统优化技术。
在程序中使用数据库连接池和线程池,可以有效地改善系统在高并发下的性能。
数据库连接池
目前应用较为广泛的数据库连接池组件有C3PO和Proxool。其中C3PO是伴随着Hibernate一起发布,与Hibernate联系紧密的数据库连接池。
若在Hibernate中使用C3PO连接池,只需要将C3PO的jar包复制到开发环境中,并且在hibernate.cfg.xml中加入以下配置项即可:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="connection.url">
jdbc:mysql://172.21.78.121:3306/utconf?useUnicode=true
&characterEncoding=UTF-8&mysqlEncoding=utf8
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.show_sql">
true
</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.jdbc.batch_size">20</property>
<property name="default_catalog">utconf</property>
<property name="connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
<property name="connection.autoReconnect">true</property>
<property name="connection.autoReconnectForPools">true</property>
<property name="connection.is-connection-validation-required">true</property>
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 最大的PreparedStatement的数量 -->
<property name="hibernate.c3p0.max_statements">100</property>
<!-- 每隔120秒检查连接池里的空闲连接 ,单位是秒-->
<property name="hibernate.c3p0.idle_test_period">120</property>
<!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都验证连接是否可用 -->
<property name="hibernate.c3p0.validate">true</property>
<mapping resource="com/utstar/mtassis/dbbean/Deviceparameter.hbm.xml" />
<mapping resource="com/utstar/mtassis/dbbean/Userrole.hbm.xml" />
<mapping resource="com/utstar/mtassis/dbbean/Userinfo.hbm.xml" />
</session-factory>
</hibernate-configuration>
当然,也可以脱离Hibernate单独在应用程序中使用C3PO。以下代码构造了一个C3PO的数据库连接池,并从中获得一个数据库连接:
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.DataSources;
public final class DBConnectionPoolDemo {
public static Object getInnter(Object con){
Object re=null;
Field f;
try {
f = con.getClass().getDeclaredField("inner");
f.setAccessible(true);
re= f.get(con); //取得内部包装的Connection
f.setAccessible(false);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return re;
}
public static void main(String[] argv) {
try {
Class.forName("com.mysql.jdbc.Driver");
DataSource unpooled = DataSources
.unpooledDataSource(
"jdbc:mysql://127.0.0.1:3306/test",
"root", "");
DataSource pooled = DataSources.pooledDataSource(unpooled);
//DataSource pooled =unpooled;
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
con = pooled.getConnection(); //第一次取得数据库连接
System.out.println("con Class Type is:"+con.getClass().getName());
Object o1=getInnter(con); //取得内部的实际数据库连接
System.out.println("Inner con Class Type is:"+o1.getClass().getName());
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM user");
while (rs.next())
System.out.println("Data from DB:"+rs.getString(1));
rs.close();
stmt.close();
con.close();
Thread.sleep(1000); //等待连接返回池中
con = pooled.getConnection(); //第二次取得数据库连接
Object o2=getInnter(con);
if(o1==o2) //相同,则说明数据库连接被复用
System.out.println("o1 and o2 is same object.");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT * FROM user");
while (rs.next())
System.out.println("Data from DB:"+rs.getString(1));
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static void attemptClose(ResultSet o) {
try {
if (o != null)
o.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static void attemptClose(Statement o) {
try {
if (o != null)
o.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static void attemptClose(Connection o) {
try {
if (o != null)
o.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private DBConnectionPoolDemo() {
}
}
线程池
在Apache中,已经提供了一个Jakarta Commons Pool对象池组件,可以直接使用。
Java中提供了Thread对象和Runnable接口用于创建进程内的线程。其次,为了优化并行程序性能,JDK还提供了java.util.concurrent并发包,内置各种多线程性能优化工具和组件,如线程池、各种并发数据结构等