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。具体步骤如下。

  1. 首先创建几个必要的类: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);
        }
    }
  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);
        }
    }