hibernate 批量插入數據


如題,有兩種方法

1)使用FLUSH

2)使用JDBC

 

分別來解釋:

1)hibernate在進行數據庫操作的時候,都要有事務支持的。可能你曾遇到過,沒有加事務,程序會報錯的情況。

    而事務每次提交的時候,都會和數據庫交互,即讓數據庫執行SQL語句。

     在說到hibernate中的save() 或者saveOrUpdate()方法,其實,它們都是利用hibernate的一級緩存,在事務沒有提交的時候,所有對象,並沒有寫入數據庫。而是保存在內存中。在事務提交的時候,hibernate會把這些對象持久化到數據庫中。另一方面,hibernate提供了一個顯式的API來強制寫數據庫。就是FLUSH。當程序執行session.flush(),就會持久化數據,而不必等到事務提交時才執行。

     本人寫了一個DEMO,一個線程產生USER,一個保存USER。

生產者代碼如下:

package com.baidu.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.baidu.model.User;

public class test extends Thread {

    public static int count = 0;
    public static List<User> userlist = Collections.synchronizedList(new ArrayList()); 
    public User user;

    public static void main(String[] args) {

        new test().start();
        new HandleThread().start();
    }
    public static int usercount=0;
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            User t = new User();
            t.setId(usercount);
            t.setUsername("name_" + usercount);
            userlist.add(t);
            System.out.println("生產出一個user_"+usercount);
            usercount++;
        }
    }

}

消費者代碼如下:

package com.baidu.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.baidu.model.User;

public class HandleThread extends Thread {
    @Override
    public void run() {
        boolean flag=false;
        Configuration config = new Configuration();
        config.configure();
        SessionFactory factory = config.buildSessionFactory();
        Session session = factory.openSession();
        while (true) {
            if (test.userlist.size() > 0) {
                for (int i = 0; i < test.userlist.size(); i++) {
                    System.out.println("處理了"
                            + test.userlist.get(i).getId());
                    insert(test.userlist.get(i),session);
                }
                test.userlist.clear();
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(flag)
                break;
        }
        session.close();
    }

    public void insert(User user,Session session) {
    
        Transaction tran = session.beginTransaction();
        session.save(user);
        if (test.count++ % 10 == 0) {
            System.out.println(test.count);
            session.flush();
            session.clear();
        }
        tran.commit();
        
    }

}
        if (test.count++ % 10 == 0) { System.out.println(test.count); session.flush(); session.clear(); }
這段代碼就是執行批量操作的核心。當然這個需要在hibernate配置文件中配置下 
<property name="hibernate.jdbc.batch_size">10</property>
這個值,從網上得到的說法是一次推送SQL語句的條數。暫且相信了,后續我將驗證(通過抓包)。

至此,第一種批量處理已經完成。

2) to be continue...



Hibernate批量處理其實從性能上考慮,它是很不可取的,浪費了很大的內存。從它的機制上講,Hibernate它是先把符合條件的數據查出來,放到內存當中,然后再進行操作。實際使用下來性能非常不理想,在筆者的實際
使用中采用下面的第三種優化方案的數據是:100000條數據插入數據庫,主流台式機的配置,需要約30分鍾,呵呵,暈倒.

總結下來有三種來處理以解決性能問題:

1:繞過Hibernate API ,直接通過 JDBC API 來做,這個方法性能上是比較好的。也是最快的.

2:運用存儲過程。

3:還是用Hibernate API 來進行常規的批量處理,可以也有變,變就變在,我們可以在查找出一定的量的時候,及時的將這些數據做完操作就

刪掉,session.flush();session.evict(XX對象集); 這樣也可以挽救一點性能損失。這個“一定的量”要就要根據實際情況做定量參考了。一般為30-60左右,但效果仍然不理想.





1:繞過Hibernate API ,直接通過 JDBC API 來做,這個方法性能上是比較好的,也是最快的。(實例為 更新操作)



Transaction tx=session.beginTransaction(); //注意用的是hibernate事務處理邊界

Connection conn=session.connection();

PreparedStatement stmt=conn.preparedStatement("update CUSTOMER as C set C.sarlary=c.sarlary+1 where c.sarlary>1000");

stmt.excuteUpdate();

tx.commit(); //注意用的是hibernate事務處理邊界

這小程序中,采用的是直接調用JDBC 的API 來訪問數據庫,效率很高。避免了Hibernate 先查詢出來加載到內存,再進行操作引發的性能問題



2:運用存儲過程。但這種方式考慮到易植和程序部署的方便性,不建議使用.(實例為 更新操作)

如果底層數據庫(如Oracle)支持存儲過程,也可以通過存儲過程來執行批量更新。存儲過程直接在數據庫中運行,速度更加快。在Oracle數

據庫中可以定義一個名為batchUpdateCustomer()的存儲過程,代碼如下:


代碼內容
create or replace procedure batchUpdateCustomer(p_age in number) as
begin
update CUSTOMERS set AGE=AGE+1 where AGE>p_age;
end; 


以上存儲過程有一個參數p_age,代表客戶的年齡,應用程序可按照以下方式調用存儲過程:

代碼內容
tx = session.beginTransaction();
Connection con=session.connection();
String procedure = "{call batchUpdateCustomer(?) }";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0); //把年齡參數設為0
cstmt.executeUpdate();
tx.commit(); 


從上面程序看出,應用程序也必須繞過Hibernate API,直接通過JDBC API來調用存儲過程。

3:還是用Hibernate API 來進行常規的批量處理,可以也有變,變就變在,我們可以在查找出一定的量的時候,及時的將這些數據做完操作就

刪掉,session.flush();session.evict(XX對象集); 這樣也可以挽救一點性能損失。這個“一定的量”要就要根據實際情況做定量參考了。。

(實例為 保存操作)

業務邏輯為:我們要想數據庫插入10 0000 條數據

tx=session.beginTransaction();

for(int i=0;i<100000;i++)

{

Customer custom=new Customer();

custom.setName("user"+i);

session.save(custom);

if(i%50==0) // 以每50個數據作為一個處理單元,也就是我上面說的“一定的量”,這個量是要酌情考慮的

{

session.flush();

session.clear();

}

}

這樣可以把系統維持在一個穩定的范圍....


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM