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