2011-09-08 147 views
15

我需要從每日CSV文件中消耗相當多的數據。 CSV包含大約120K條記錄。使用休眠時,這會減慢抓取速度。基本上,看起來在使用saveOrUpdate()時,hibernate在每一個INSERT(或UPDATE)之前都會執行SELECT操作。對於每個使用saveOrUpdate()持久化的實例,都會在實際的INSERT或UPDATE之前發出SELECT。我可以理解爲什麼它這樣做,但它做非常低效的批量處理,我正在尋找替代品批量插入或更新與休眠?

我相信性能問題在於我使用hibernate的方式,因爲我得到了另一個版本與原生SQL工作(解析CSV的激動人心的相同方式)和它的字面上圍繞這個新版本的字面上運行的圓)

所以,到實際的問題,做一個休眠替代mysqls「INSERT ... ON DUPLICATE「語法存在嗎?或者,如果我選擇爲此執行原生SQL,我可以在hibernate事務中執行原生SQL嗎?意思是說,它會支持提交/回滾嗎?

+0

你是什麼意思「Hibernate是每一個插入(或更新)之前執行SELECT使用saveOrUpdate時,()。」 ?你可以發佈你用來保存數據的代碼嗎?順便說一下,12萬條記錄是一個巨大的數據! – Rakesh

+0

剛剛發現一篇關於[休眠時批處理]的文章(http://onetouchcode.com/2016/08/21/batch-processing-example-in-hibernate/) – Shailendra

回答

22

批量操作有很多可能的瓶頸。最好的方法在很大程度上取決於你的數據是什麼樣子。查看關於批處理的Hibernate Manual部分。

在最低限度,確保您使用的是以下模式(從手動複製):

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

for (int i=0; i<100000; i++) { 
Customer customer = new Customer(.....); 
session.save(customer); 
    if (i % 20 == 0) { //20, same as the JDBC batch size 
     //flush a batch of inserts and release memory: 
     session.flush(); 
     session.clear(); 
    } 
} 

tx.commit(); 
session.close(); 

如果你映射一個平面文件到一個非常複雜的對象圖,你可能需要獲得更多的創造性,但基本原理是,您必須在每次刷新/提交時將大小適當的數據塊推送到數據庫並避免爆炸會話級別緩存的大小之間找到平衡點。

最後,如果您不需要Hibernate處理任何集合或級聯數據以便正確插入,請考慮使用StatelessSession

+0

我正在沖洗一個清理會話,我沒有內存問題與代碼。我有額外的選擇問題! :P我通讀手冊,我找不到任何東西。數據非常簡單,不需要級聯。我只是需要擺脫這個任務,被稱爲120K次的冗餘選擇:P – JustDanyul

+0

@JustDanyul這個操作中新實體的近似百分比是多少(即實際上不需要多少百分比的選擇)?你在使用版本控制嗎? – jcwayne

+0

實際百分比會每天都在變化。但是,沒有一項選擇確實是必要的。現在大多數數據庫(甚至像SQLite這樣的「玩具」數據庫)提供的功能可以讓你在數據已經存在的情況下自動更新記錄。 (不必先輪詢它,找出它是否存在:)) – JustDanyul

0

「額外」選擇是爲您的數據生成唯一標識符。

切換到HiLo序列生成,您可以通過分配大小減少到數據庫的序列往返。請注意,會出現在主鍵的空隙,除非你對希洛發電機調整序列值

1

如果使用序列或天然生成Hibernate將使用選擇來獲取ID:

<id name="id" column="ID"> 
    <generator class="native" /> 
</id> 

你應該使用希洛或seqHiLo發生器:

<id name="id" type="long" column="id"> 
    <generator class="seqhilo"> 
     <param name="sequence">SEQ_NAME</param> 
     <param name="max_lo">100</param> 
    </generator> 
</id> 
3

Hibernate Batch Processing 對於更新我用下面的:

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(); 

但對於插入我會去jcwayne答案