全部產品
Search
文件中心

ApsaraDB for OceanBase (Deprecated):CommonPool 配置樣本

更新時間:Jul 01, 2024

本文介紹 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);
        }
    }