All Products
Search
Document Center

ApsaraDB for OceanBase:CommonPool configuration example

Last Updated:Aug 01, 2023

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.oceanbase</groupId>
        <artifactId>oceanbase-client</artifactId>
        <version>2.4.0</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.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>

        <!-- Optional configuration -->
        <!-- Specifies whether to support dialects. -->
        <!-- 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:

  1. 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);
        }
    }
  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);
        }
    }