CommonPool 配置示例
本文介绍 CommonPool 连接池配置依赖、配置文件和示例代码。
配置依赖
结合 hibernate 及 commonpool 对 oceanbase 数据库进行操作。
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>com.oceanbase</groupId>
<artifactId>oceanbase-client</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
实体类
import javax.persistence.*;
@Entity
@Table(name = "user_test")
public class User {
public User() { }
@Id
//oracle 模式不支持该主键自增
//@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String username;
@Column
private String birthday;
public User(Integer id, String username, String birthday) {
this.id = id;
this.username = username;
this.birthday = birthday;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday='" + birthday + '\'' +
'}';
}
}
hibernate
实体类映射文件如下。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
'http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd'>
<hibernate-mapping>
<!-- 类与表的映射制作在 class 元素上 -->
<!-- name:全路径类名 -->
<!-- table:表名 -->
<class name="pojo.User" table="user_test">
<!-- 主键的映射制作在 id 元素上 -->
<!-- name:对象中用于作为主键的属性名 -->
<!-- colomn:表中主键字段名 -->
<!-- 如果 name 与 column 值相同,可以省略 column -->
<id name="id" column="id">
<!--**要注意 Hibernate 主键生成策略**-->
</id>
<!-- 属性与字段的映射制作在 property 元素上 -->
<!-- name:类中的属性名 -->
<!-- column:表中的字段名 -->
<!-- 如果 name 与 column 值相同,可以省略 column -->
<property name="username" />
<property name="birthday" />
</class>
</hibernate-mapping>
hibernate 配置文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库连接的配置 -->
<!--oceanbase-->
<property name="connection.driver_class">com.oceanbase.jdbc.Driver</property>
<property name="connection.url">jdbc:oceanbase://xxx.xxx.xxx.xxx:1521/</property>
<property name="connection.username">a****</property>
<property name="connection.password">******</property>
<!-- 可选配置 -->
<!--是否支持方言 -->
<!--在 Oracle 模式下,必须有如下配置-->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!--执行 CURD 时是否打印sql 语句 -->
<property name="show_sql">true</property>
<!--自动建表 该处注释根据需求打开或关闭-->
<!--<property name="hbm2ddl.auto">update</property>-->
<!--<property name="hbm2ddl.auto">create</property>-->
<!-- 资源注册,此处即为实体类映射文件路径 -->
<mapping resource="./UserModel.hbm.xml"/>
</session-factory>
</hibernate-configuration>
示例代码
实现 CommonPool 管理 Hibernate。
由于 Hibernate 操作数据库的方式为Session.xxxx();
,此处选择实现一个 SessionPool。具体步骤如下。
首先创建几个必要的类:SessionPool(会话池),SessionFactory(会话工厂),SessionPoolConfig(会话池配置类)。
package sess; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.hibernate.Session; import java.io.Closeable; public class SessionPool implements Closeable { //通用对象池,此处泛型决定了池中对象类型为 org.hibernate.Session private GenericObjectPool<Session> internalPool; public SessionPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory factory){ if (this.internalPool != null) { try { closeInternalPool(); } catch (Exception e) { } } this.internalPool = new GenericObjectPool(factory, poolConfig); } // 获取连接会话 public Session getSession(){ Session session = null; try { session = internalPool.borrowObject(); } catch (Exception e) { throw new RuntimeException("Could not get session from the pool", e); } return session; } // 返还连接会话(将使用完毕的对象返回到池) public void returnSession(Session session){ internalPool.returnObject(session); } @Override public void close(){ this.closeInternalPool(); } private void closeInternalPool() { try { internalPool.close(); } catch (Exception e) { throw new RuntimeException("Could not destroy the pool", e); } } }
package sess; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.hibernate.Session; import org.hibernate.cfg.Configuration; public class SessionFactory extends BasePooledObjectFactory<Session> { // 创建新的数据库连接会话 @Override public Session create() throws Exception { //加载配置信息 Configuration conf = new Configuration().configure(); //基于配置信息,创建 SessionFactory 对象 org.hibernate.SessionFactory sessionFactory = conf.buildSessionFactory(); //打开一个与数据库相关的 session 对象 Session session = sessionFactory.openSession(); return session; } // 使用 PooledObject 对数据库连接会话进行包装 @Override public PooledObject<Session> wrap(Session session) { return new DefaultPooledObject(session); } // 由于 validateObject 失败或其它什么原因,对象实例从对象池中移除时调用 // 不能保证对象实例被移除时所处的状态 public void destroyObject(PooledObject<Session> pooledConnection) throws Exception { Session session = pooledConnection.getObject(); session.close(); } // 仅能被 active 状态的对象实例调用 // 从对象池获取对象实例,在对象池返回该对象实例前,调用该方法校验其状态 // 对象实例归还给对象池时,在调用 passivateObject 方法前,使用该方法校验其状态 public boolean validateObject(PooledObject<Session> pooledConnection) { Session session = pooledConnection.getObject(); try { // if (session.isValid(1)) if (session.isOpen()) return true; else return false; }catch(Exception e){ return false; } } // 对象实例在归还给对象池时调用了 passivateObject 方法,通过对象池再次取到该对象实例 // 在对象池返回该对象实例前,需要调用该方法 public void activateObject(PooledObject<Session> pooledConnection) throws Exception { //。。。。。。。。。 } // 对象实例归还给对象池时调用 public void passivateObject(PooledObject<Session> pooledConnection) throws Exception { //。。。。。。。。。 } }
package sess; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class SessionPoolConfig extends GenericObjectPoolConfig { public SessionPoolConfig(){ setMaxTotal(10); setMaxIdle(5); setMinIdle(2); } }
进行测试。
@Test public void test() throws Exception { //创建公共池配置类 SessionPoolConfig sessionPoolConfig = new SessionPoolConfig(); //创建会话工厂 SessionFactory sessionFactory = new SessionFactory(); //配置会话池属性 sessionPoolConfig.setMaxTotal(4); sessionPoolConfig.setMaxIdle(3); sessionPoolConfig.setMinIdle(2); sessionPoolConfig.setMaxWaitMillis(200); sessionPoolConfig.setTestOnBorrow(false); sessionPoolConfig.setTestOnReturn(false); //构建会话池 SessionPool sessionPool = new SessionPool(sessionPoolConfig,sessionFactory); //测试 for (int i = 1; i <= 10; i++) { User user = new User(); user.setId(i); user.setUsername("Test"); user.setBirthday("test"); Session session = sessionPool.getSession(); Transaction transaction = session.beginTransaction(); session.save(user); System.out.println("第"+i+"次数据库操作,会话对象哈希值为:"+session.hashCode()); transaction.commit(); //将该 session 返回到池 sessionPool.returnSession(session); } }