Hibernate批量處理
考慮這樣一種情況,當需要使用Hibernate上傳大量的記錄到數據庫中。以下是代碼片段實現這一使用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();
因為默認情況下,Hibernate會緩存所有的持久對象在session級彆的緩存,並最終應用程序會失敗並發生OutOfMemoryException某處50,000條記錄左右。如果使用的是批量處理與Hibernate解決這個問題。
要使用批量處理功能,首先設置hibernate.jdbc.batch_size為批量大小若乾無論是在20或50根據對象的大小。這將告訴每X行插入批次hibernate的容器。為了實現這個在代碼中,我們需要做一點修改如下:
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();
上麵的代碼將正常工作INSERT操作,但如果願意做UPDATE操作,那麼可以使用下麵的代碼實現:
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();
批處理示例:
讓我們修改配置文件作為補充hibernate.jdbc.batch_size屬性:
<?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>
考慮下麵的POJO Employee類:
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; } }
讓我們創建下麵的EMPLOYEE表來存儲Employee對象:
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) );
下麵將映射文件映射員工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>
最後,我們將創建與應用程序類main()方法來運行,我們將使用flush() 和 clear()可Session對象方法,使Hibernate的繼續寫這些記錄到數據庫中,而不是它們緩存中的應用內存。
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 ; } }
編譯和執行:
下麵是步驟來編譯並運行上述應用程序。請確保您已在進行的編譯和執行之前,適當地設置PATH和CLASSPATH。
-
創建hibernate.cfg.xml配置文件,如上麵所述。
-
創建Employee.hbm.xml映射文件,如上圖所示。
-
創建Employee.java源文件,如上圖所示,並編譯它。
-
創建ManageEmployee.java源文件,如上圖所示,並編譯它。
-
執行ManageEmployee二進製運行將在EMPLOYEE表中創建100000條記錄程序。