Hibernate - Xử lý hàng loạt

Hãy xem xét một tình huống khi bạn cần tải lên một số lượng lớn các bản ghi vào cơ sở dữ liệu của mình bằng Hibernate. Sau đây là đoạn mã để đạt được điều này bằng Hibernate -

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
}
tx.commit();
session.close();

Theo mặc định, Hibernate sẽ lưu vào bộ nhớ cache tất cả các đối tượng còn tồn tại trong bộ nhớ cache cấp phiên và cuối cùng ứng dụng của bạn sẽ rơi vào OutOfMemoryExceptionở đâu đó xung quanh hàng thứ 50.000. Bạn có thể giải quyết vấn đề này, nếu bạn đang sử dụngbatch processing với Hibernate.

Để sử dụng tính năng xử lý hàng loạt, trước tiên hãy đặt hibernate.jdbc.batch_sizedưới dạng kích thước lô thành một số ở mức 20 hoặc 50 tùy thuộc vào kích thước đối tượng. Điều này sẽ cho vùng chứa ngủ đông biết rằng mọi hàng X sẽ được chèn dưới dạng lô. Để triển khai điều này trong mã của bạn, chúng tôi sẽ cần thực hiện một số sửa đổi nhỏ như sau:

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
   Employee employee = new Employee(.....);
   session.save(employee);
   if( i % 50 == 0 ) { // Same as the JDBC batch size
      //flush a batch of inserts and release memory:
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Mã trên sẽ hoạt động tốt cho hoạt động INSERT, nhưng nếu bạn sẵn sàng thực hiện thao tác CẬP NHẬT, thì bạn có thể đạt được bằng cách sử dụng mã sau:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE").scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee); 
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Ví dụ về xử lý hàng loạt

Hãy để chúng tôi sửa đổi tệp cấu hình để thêm hibernate.jdbc.batch_size tài sản -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>

      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         root123
      </property>
   
      <property name = "hibernate.jdbc.batch_size">
         50
      </property>

      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>

   </session-factory>
</hibernate-configuration>

Hãy xem xét lớp Nhân viên POJO sau:

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Hãy để chúng tôi tạo bảng EMPLOYEE sau đây để lưu trữ các đối tượng Nhân viên -

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Sau đây sẽ là tệp ánh xạ để ánh xạ các đối tượng Nhân viên với bảng EMPLOYEE -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Cuối cùng, chúng tôi sẽ tạo lớp ứng dụng của mình với phương thức main () để chạy ứng dụng mà chúng tôi sẽ sử dụng flush()clear() các phương thức có sẵn với đối tượng Session để Hibernate tiếp tục ghi các bản ghi này vào cơ sở dữ liệu thay vì lưu chúng vào bộ nhớ đệm.

import java.util.*; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   private static SessionFactory factory; 
   public static void main(String[] args) {
      
      try {
         factory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) { 
         System.err.println("Failed to create sessionFactory object." + ex);
         throw new ExceptionInInitializerError(ex); 
      }
      ManageEmployee ME = new ManageEmployee();

      /* Add employee records in batches */
      ME.addEmployees( );
   }
   
   /* Method to create employee records in batches */
   public void addEmployees( ){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         for ( int i=0; i<100000; i++ ) {
            String fname = "First Name " + i;
            String lname = "Last Name " + i;
            Integer salary = i;
            Employee employee = new Employee(fname, lname, salary);
            session.save(employee);
         	if( i % 50 == 0 ) {
               session.flush();
               session.clear();
            }
         }
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return ;
   }
}

Biên dịch và Thực hiện

Dưới đây là các bước để biên dịch và chạy ứng dụng được đề cập ở trên. Đảm bảo rằng bạn đã đặt PATH và CLASSPATH thích hợp trước khi tiếp tục biên dịch và thực thi.

  • Tạo tệp cấu hình hibernate.cfg.xml như đã giải thích ở trên.

  • Tạo tệp ánh xạ Employee.hbm.xml như hình trên.

  • Tạo tệp nguồn Employee.java như hình trên và biên dịch nó.

  • Tạo tệp nguồn ManageEaffee.java như hình trên và biên dịch nó.

  • Thực thi mã nhị phân ManageE Jobee để chạy chương trình, chương trình này sẽ tạo 100000 bản ghi trong bảng EMPLOYEE.