亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Hibernate批量處理(Batch processing)

系統(tǒng) 1522 0
使用Hibernate將 100 000 條記錄插入到數(shù)據(jù)庫(kù)的一個(gè)很自然的做法可能是這樣的

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
??? Customer customer = new Customer(.....);
??? session.save(customer);
}
tx.commit();
session.close();
這段程序大概運(yùn)行到 50 000 條記錄左右會(huì)失敗并拋出 內(nèi)存溢出異常(OutOfMemoryException) 。 這是因?yàn)?Hibernate 把所有新插入的 客戶(Customer)實(shí)例在 session級(jí)別的緩存區(qū)進(jìn)行了緩存的緣故。

我們會(huì)在本章告訴你如何避免此類問題。首先,如果你要執(zhí)行批量處理并且想要達(dá)到一個(gè)理想的性能, 那么使用JDBC的批量(batching)功能是至關(guān)重要。將JDBC的批量抓取數(shù)量(batch size)參數(shù)設(shè)置到一個(gè)合適值 (比如,10-50之間):

hibernate.jdbc.batch_size 20
注意,假若你使用了identiy標(biāo)識(shí)符生成器,Hibernate在JDBC級(jí)別透明的關(guān)閉插入語(yǔ)句的批量執(zhí)行。

你也可能想在執(zhí)行批量處理時(shí)關(guān)閉二級(jí)緩存:

hibernate.cache.use_second_level_cache false
但是,這不是絕對(duì)必須的,因?yàn)槲覀兛梢燥@式設(shè)置CacheMode來(lái)關(guān)閉與二級(jí)緩存的交互。

13.1. 批量插入(Batch inserts)
如果要將很多對(duì)象持久化,你必須通過(guò)經(jīng)常的調(diào)用 flush() 以及稍后調(diào)用 clear() 來(lái)控制第一級(jí)緩存的大小。

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 //20,與JDBC批量設(shè)置相同
??????? //flush a batch of inserts and release memory:
??????? //將本批插入的對(duì)象立即寫入數(shù)據(jù)庫(kù)并釋放內(nèi)存
??????? session.flush();
??????? session.clear();
??? }
}
??
tx.commit();
session.close();
13.2. 批量更新(Batch updates)
此方法同樣適用于檢索和更新數(shù)據(jù)。此外,在進(jìn)行會(huì)返回很多行數(shù)據(jù)的查詢時(shí), 你需要使用 scroll() 方法以便充分利用服務(wù)器端游標(biāo)所帶來(lái)的好處。

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
??
ScrollableResults customers = session.getNamedQuery("GetCustomers")
??? .setCacheMode(CacheMode.IGNORE)
??? .scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
??? Customer customer = (Customer) customers.get(0);
??? customer.updateStuff(...);
??? if ( ++count % 20 == 0 ) {
??????? //flush a batch of updates and release memory:
??????? session.flush();
??????? session.clear();
??? }
}
??
tx.commit();
session.close();
13.3. StatelessSession (無(wú)狀態(tài)session)接口
作為選擇,Hibernate提供了基于命令的API,可以用detached object的形式把數(shù)據(jù)以流的方法加入到數(shù)據(jù)庫(kù),或從數(shù)據(jù)庫(kù)輸出。StatelessSession沒有持久化上下文,也不提供多少高層的生命周期語(yǔ)義。特別是,無(wú)狀態(tài)session不實(shí)現(xiàn)第一級(jí)cache,也不和第二級(jí)緩存,或者查詢緩存交互。它不實(shí)現(xiàn)事務(wù)化寫,也不實(shí)現(xiàn)臟數(shù)據(jù)檢查。用stateless session進(jìn)行的操作甚至不級(jí)聯(lián)到關(guān)聯(lián)實(shí)例。stateless session忽略集合類(Collections)。通過(guò)stateless session進(jìn)行的操作不觸發(fā)Hibernate的事件模型和攔截器。無(wú)狀態(tài)session對(duì)數(shù)據(jù)的混淆現(xiàn)象免疫,因?yàn)樗鼪]有第一級(jí)緩存。無(wú)狀態(tài)session是低層的抽象,和低層JDBC相當(dāng)接近。

StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
??
ScrollableResults customers = session.getNamedQuery("GetCustomers")
??? .scroll(ScrollMode.FORWARD_ONLY);
while ( customers.next() ) {
??? Customer customer = (Customer) customers.get(0);
??? customer.updateStuff(...);
??? session.update(customer);
}
??
tx.commit();
session.close();
注意在上面的例子中,查詢返回的Customer實(shí)例立即被脫管(detach)。它們與任何持久化上下文都沒有關(guān)系。

StatelessSession 接口定義的insert(), update() 和 delete()操作是直接的數(shù)據(jù)庫(kù)行級(jí)別操作,其結(jié)果是立刻執(zhí)行一條INSERT, UPDATE 或 DELETE 語(yǔ)句。因此,它們的語(yǔ)義和Session 接口定義的save(), saveOrUpdate() 和delete() 操作有很大的不同。
13.4. DML(數(shù)據(jù)操作語(yǔ)言)風(fēng)格的操作(DML-style operations)
hence manipulating (using the SQL Data Manipulation Language (DML) statements: INSERT, UPDATE, DELETE) data directly in the database will not affect in-memory state. However, Hibernate provides methods for bulk SQL-style DML statement execution which are performed through the Hibernate Query Language (第 14 章 HQL: Hibernate查詢語(yǔ)言). 就像已經(jīng)討論的那樣,自動(dòng)和透明的 對(duì)象/關(guān)系 映射(object/relational mapping)關(guān)注于管理對(duì)象的狀態(tài)。 這就意味著對(duì)象的狀態(tài)存在于內(nèi)存,因此直接操作 (使用 SQL Data Manipulation Language(DML,數(shù)據(jù)操作語(yǔ)言)語(yǔ)句 :INSERT ,UPDATE 和 DELETE) 數(shù)據(jù)庫(kù)中的數(shù)據(jù)將不會(huì)影響內(nèi)存中的對(duì)象狀態(tài)和對(duì)象數(shù)據(jù)。 不過(guò),Hibernate提供通過(guò)Hibernate查詢語(yǔ)言(第 14 章 HQL: Hibernate查詢語(yǔ)言)來(lái)執(zhí)行大批 量SQL風(fēng)格的DML語(yǔ)句的方法。

UPDATE 和 DELETE語(yǔ)句的語(yǔ)法為: ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)? 有幾點(diǎn)說(shuō)明:

在FROM子句(from-clause)中,F(xiàn)ROM關(guān)鍵字是可選的

在FROM子句(from-clause)中只能有一個(gè)實(shí)體名,它可以是別名。如果實(shí)體名是別名,那么任何被引用的屬性都必須加上此別名的前綴;如果不是別名,那么任何有前綴的屬性引用都是非法的。

不能在大批量HQL語(yǔ)句中使用第 14.4 節(jié) “join 語(yǔ)法的形式”(顯式或者隱式的都不行)。不過(guò)在WHERE子句中可以使用子查詢。可以在where子句中使用子查詢,子查詢本身可以包含join。

整個(gè)WHERE子句是可選的。

舉個(gè)例子,使用Query.executeUpdate()方法執(zhí)行一個(gè)HQL UPDATE語(yǔ)句(: (方法命名是來(lái)源于JDBC's PreparedStatement.executeUpdate()):

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

? String hqlUpdate = "update Customer c set c.name = :newName where c.name = ldName";
? // or String hqlUpdate = "update Customer set name = :newName where name = ldName";
? int updatedEntities = s.createQuery( hqlUpdate )
????????? .setString( "newName", newName )
????????? .setString( "oldName", oldName )
????????? .executeUpdate();
? tx.commit();
? session.close();
HQL UPDATE語(yǔ)句,默認(rèn)不會(huì)影響更新實(shí)體的第 5.1.7 節(jié) “版本(version)(可選)”或者第 5.1.8 節(jié) “timestamp (可選)”屬性值。這和EJB3規(guī)范是一致的。但是,通過(guò)使用versioned update,你可以強(qiáng)制Hibernate正確的重置version或者timestamp屬性值。這通過(guò)在UPDATE關(guān)鍵字后面增加VERSIONED關(guān)鍵字來(lái)實(shí)現(xiàn)的。

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = ldName";
int updatedEntities = s.createQuery( hqlUpdate )
??????? .setString( "newName", newName )
??????? .setString( "oldName", oldName )
??????? .executeUpdate();
tx.commit();
session.close();
注意,自定義的版本類型(org.hibernate.usertype.UserVersionType)不允許和update versioned語(yǔ)句聯(lián)用。

執(zhí)行一個(gè)HQL DELETE,同樣使用 Query.executeUpdate() 方法:

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

? String hqlDelete = "delete Customer c where c.name = ldName";
? // or String hqlDelete = "delete Customer where name = ldName";
? int deletedEntities = s.createQuery( hqlDelete )
????????? .setString( "oldName", oldName )
????????? .executeUpdate();
? tx.commit();
? session.close();
由Query.executeUpdate()方法返回的整型值表明了受此操作影響的記錄數(shù)量。 注意這個(gè)數(shù)值可能與數(shù)據(jù)庫(kù)中被(最后一條SQL語(yǔ)句)影響了的“行”數(shù)有關(guān),也可能沒有。一個(gè)大批量HQL操作可能導(dǎo)致多條實(shí)際的SQL語(yǔ)句被執(zhí)行, 舉個(gè)例子,對(duì)joined-subclass映射方式的類進(jìn)行的此類操作。這個(gè)返回值代表了實(shí)際被語(yǔ)句影響了的記錄數(shù)量。在那個(gè)joined-subclass的例子中, 對(duì)一個(gè)子類的刪除實(shí)際上可能不僅僅會(huì)刪除子類映射到的表而且會(huì)影響“根”表,還有可能影響與之有繼承關(guān)系的joined-subclass映射方式的子類的表。

INSERT語(yǔ)句的偽碼是: INSERT INTO EntityName properties_list select_statement. 要注意的是:

只支持INSERT INTO ... SELECT ...形式,不支持INSERT INTO ... VALUES ...形式.

properties_list和SQL INSERT語(yǔ)句中的字段定義(column speficiation)類似。對(duì)參與繼承樹映射的實(shí)體而言,只有直接定義在給定的類級(jí)別的屬性才能直接在properties_list中使用。超類的屬性不被支持;子類的屬性無(wú)意義。換句話說(shuō),INSERT天生不支持多態(tài)。

select_statement可以是任何合法的HQL選擇查詢,不過(guò)要保證返回類型必須和要插入的類型完全匹配。目前,這一檢查是在查詢編譯的時(shí)候進(jìn)行的,而不是把它交給數(shù)據(jù)庫(kù)。注意,在HibernateType間如果只是等價(jià)(equivalent)而非相等(equal),會(huì)導(dǎo)致問題。定義為org.hibernate.type.DateType和org.hibernate.type.TimestampType的兩個(gè)屬性可能會(huì)產(chǎn)生類型不匹配錯(cuò)誤,雖然數(shù)據(jù)庫(kù)級(jí)可能不加區(qū)分或者可以處理這種轉(zhuǎn)換。

對(duì)id屬性來(lái)說(shuō),insert語(yǔ)句給你兩個(gè)選擇。你可以明確地在properties_list表中指定id屬性(這樣它的值是從對(duì)應(yīng)的select表達(dá)式中獲得),或者在properties_list中省略它(此時(shí)使用生成指)。后一種選擇只有當(dāng)使用在數(shù)據(jù)庫(kù)中生成值的id產(chǎn)生器時(shí)才能使用;如果是“內(nèi)存”中計(jì)算的類型生成器,在解析時(shí)會(huì)拋出一個(gè)異常。注意,為了說(shuō)明這一問題,數(shù)據(jù)庫(kù)產(chǎn)生值的生成器是org.hibernate.id.SequenceGenerator(和它的子類),以及任何org.hibernate.id.PostInsertIdentifierGenerator接口的實(shí)現(xiàn)。這兒最值得注意的意外是org.hibernate.id.TableHiLoGenerator,它不能在此使用,因?yàn)樗鼪]有得到其值的途徑。

對(duì)映射為version 或 timestamp的屬性來(lái)說(shuō),insert語(yǔ)句也給你兩個(gè)選擇,你可以在properties_list表中指定(此時(shí)其值從對(duì)應(yīng)的select表達(dá)式中獲得),或者在properties_list中省略它(此時(shí),使用在org.hibernate.type.VersionType 中定義的seed value(種子值))。

執(zhí)行HQL INSERT語(yǔ)句的例子如下:

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

String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery( hqlInsert )
??????? .executeUpdate();
tx.commit();
session.close();

Hibernate批量處理(Batch processing)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产精品深爱在线 | 最新日本中文字幕 | 激情五月婷婷基地 | aaa一级黑人毛片 | 久久青青草原精品国产麻豆 | 国产精品久久免费观看 | 欧美日韩国产成人综合在线影院 | 夜夜爽夜夜| 国产在视频线在精品 | 欧美亚洲欧美日韩中文二区 | 干干操操 | 久草精品视频在线播放 | 视频一区在线免费观看 | 老司机亚洲精品 | 精品国产品香蕉在线观看 | 四虎精品影院 | 亚洲爽爽 | www.久草| 麻豆精品久久精品色综合 | 小说区图片区综合久久亚洲 | 日本久久中文字幕 | 乡下女色又黄一级毛片 | 97精品福利视频在线 | 一区二区三区四区国产精品 | 天天操综合网 | 欧美精品99| 亚洲欧洲国产精品你懂的 | 四虎影院成人在线观看 | 特级一级黄色片 | 欧美成人禁片在线www | 久久香蕉国产线看观看8青草 | 日韩一区二区精品久久高清 | videos欧美黑白爆交 | 美女撒尿毛片免费看 | 色综合色综合色综合色综合网 | 精品国产自在现线看久久 | 亚洲欧美日韩精品中文乱码 | 国产亚洲欧美在线 | 亚洲欧美综合乱码精品成人网 | 97理论三级九七午夜在线观看 | 亚洲欧美综合乱码精品成人网 |