This topic describes how to configure dependencies and configuration files for a CommonPool connection pool and provides relevant sample code.
Configure dependencies
Perform operations on OceanBase Databases based on Hibernate and CommonPool.
<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.alipay.oceanbase</groupId>
<artifactId>oceanbase-client</artifactId>
<version>3.2.3</version>
</dependency>
</dependencies>
Entity class
import javax.persistence.*;
@Entity
@Table(name = "user_test")
public class User {
public User() { }
@Id
// Auto-increment is not supported for the specified primary key in Oracle mode.
//@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
Entity class mapping file:
<?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>
<!-- The mapping between classes and tables is printed on the class element. -->
<!-- name: the full path class name. -->
<!-- table: the table name. -->
<class name="pojo.User" table="user_test">
<!-- The primary key mapping is printed on the id element. -->
<!-- name: the name of the attribute that serves as the primary key in the object. -->
<!-- column: the name of the primary key field in the table. -->
<!-- If the values of name and column are the same, the value of column can be ignored. -->
<id name="id" column="id">
<!--**Pay attention to the strategy for generating the Hibernate primary key.**-->
</id>
<!-- The mapping between attributes and fields is printed on the property element. -->
<!-- name: the attribute name in the class. -->
<!-- column: the field name in the table. -->
<!-- If the values of name and column are the same, the value of column can be ignored. -->
<property name="username" />
<property name="birthday" />
</class>
</hibernate-mapping>
Hibernate configuration file:
<?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>
<!-- Database connection configuration -->
<!--oceanbase-->
<property name="connection.driver_class">com.alipay.oceanbase.jdbc.Driver</property>
<property name="connection.url">jdbc:oceanbase://10.100.xxx.xxx:18815/test</property>
<property name="connection.username">admin@oracle</property>
<property name="connection.password">admin</property>
<!-- Optional configuration -->
<!-- Specifies whether to support dialects. -->
<!--<property name="dialect">org.hibernate.dialect.MySQLDialect</property>-->
<!-- In Oracle mode, the following configuration is required. -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- Specifies whether to print SQL statements when create, read, update, and delete (CRUD) operations are performed. -->
<property name="show_sql">true</property>
<!-- Automatic table creation. You can open or close the comment as needed. -->
<!--<property name="hbm2ddl.auto">update</property>-->
<!--<property name="hbm2ddl.auto">create</property>-->
<!-- Resource registration. Set the path of the entity class mapping file. -->
<mapping resource="./UserModel.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Sample code
Manage Hibernate by using CommonPool.
Hibernate operates the database in Session.xxxx() mode. Therefore, one SessionPool is implemented. Perform the following steps:
Create the necessary classes, including SessionPool, SessionFactory, and 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 { //The common object pool, where the generic type determines that the object type in the pool is 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); } // Obtain the connection session. 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; } // Return the connection session to the pool upon completion. 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> { // Create a new database connection session. @Override public Session create() throws Exception { // Load the configuration information. Configuration conf = new Configuration().configure(); // Create a SessionFactory object based on the configuration information. org.hibernate.SessionFactory sessionFactory = conf.buildSessionFactory(); // Open a session object related to the database. Session session = sessionFactory.openSession(); return session; } // Use PooledObject to wrap the database connection session. @Override public PooledObject<Session> wrap(Session session) { return new DefaultPooledObject(session); } // Called when the object instance is removed from the object pool due to a validateObject failure or other reasons. // The status of the object instance cannot be guaranteed when it is removed. public void destroyObject(PooledObject<Session> pooledConnection) throws Exception { Session session = pooledConnection.getObject(); session.close(); } // It can be called only by an object instance in the active state. // Get an object instance from the object pool and call this method to verify the status of the object instance before it is returned to the object pool. // When an object instance is returned to the object pool, use this method to verify the status of the object instance before you call the passivateObject method. 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; } } // The passivateObject method is called when an object instance is returned to the object pool. This object instance is retrieved again from the object pool. // This method must be called before the object instance is returned to the object pool. public void activateObject(PooledObject<Session> pooledConnection) throws Exception { //... . . . . . . . . } // Called when an object instance is returned to the object pool. 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); } }Perform a test.
@Test public void test() throws Exception { // Create a public pool configuration class. SessionPoolConfig sessionPoolConfig = new SessionPoolConfig(); // Create a session factory. SessionFactory sessionFactory = new SessionFactory(); // Configure session pool properties. sessionPoolConfig.setMaxTotal(4); sessionPoolConfig.setMaxIdle(3); sessionPoolConfig.setMinIdle(2); sessionPoolConfig.setMaxWaitMillis(200); sessionPoolConfig.setTestOnBorrow(false); sessionPoolConfig.setTestOnReturn(false); // Build a session pool. SessionPool sessionPool = new SessionPool(sessionPoolConfig,sessionFactory); // Perform a test. 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(The "+i+"th database operation. The hash value of the session object is "+session.hashCode()); transaction.commit(); // Return the session to the pool. sessionPool.returnSession(session); } }