hibernate scroll 和 list

原文:https://forum.hibernate.org/viewtopic.php?p=2386803


Hi, I've written a small test to measure the memory consumption of my Hibernate code. It seem that getting a List of objects with the list() method of a Query uses much more memory than creating the List manually by using a ScrollableResult.

The ScrollableResult memory consumption is almost identical to the consumption of a pure JDBC implementation. The list() memory consumption needs much more MB. In my case with my Database 50.000 Object need approximately 13 MB with ScrollableResult and 23 MB with list()!!

Can anybody explain this behaviour? Is my code wrong?

Hibernate Version: 3.2.2ga
Windows XP SP2
Database: Oracel 10g

Testcode:
Note: You have to replace the HQL Query with your Hibernate Objects!


Code:

public class HibernateMemoryConsumptionTest extends TestCase {

private int size = 50000;

private int repeats = 2;

private boolean trackMemoryConsumption = true;

private Runtime runtime;

protected void setUp() throws Exception {
super.setUp();
runtime = Runtime.getRuntime();
}

protected void tearDown() throws Exception {
super.tearDown();
runtime = null;
}

public void testHibernateWithOneSession() {
// init
HibernateUtil.getSessionFactory();
long heap1 = 0;
long heap2 = 0;

long start = System.currentTimeMillis();

StatelessSession session = null;
Transaction tx = null;
List results = null;
try {
session = HibernateUtil.getSessionFactory().openStatelessSession();

for (int i = 0; i < repeats; i++) {
if (trackMemoryConsumption) {
System.err
.println("Note: Memory measurement can influence time measurement!");
runGC();
heap1 = usedMemory(); // Take a before heap snapshot
}

tx = session.beginTransaction();
Query query = session
.createQuery("FROM Cashflow ");
query.setFirstResult(1);
query.setMaxResults(size);
results = query.list();
tx.commit();

assertEquals(size, results.size());

if (trackMemoryConsumption) {
heap2 = usedMemory(); // Take an after heap snapshot:
final long heapsizeDiff = heap2 - heap1;
System.out.println("'before' heap: " + heap1
+ ", 'after' heap: " + heap2);
System.out.println("heap delta: " + heapsizeDiff / 1024d
/ 1024d + " MB");
}

results = null;

runGC();// aufräumen für nächste schleife

}
} catch (Throwable t) {
t.printStackTrace();
if (tx != null) {
tx.rollback();
}
throw new PersistenceException(t);
}

long end = System.currentTimeMillis();

System.out.println("runtime with list() "
+ repeats + " repeats with " + size + " Cashflows = "
+ ((end - start) / (double) repeats));
}

public void testHibernateWithScrollableResult() {
// init wird nicht mitgezählt!
HibernateUtil.getSessionFactory();
long heap1 = 0;
long heap2 = 0;

long start = System.currentTimeMillis();

StatelessSession session = null;
Transaction tx = null;
ScrollableResults results = null;
List cashFlows = null;
try {
session = HibernateUtil.getSessionFactory().openStatelessSession();

for (int i = 0; i < repeats; i++) {
cashFlows = new ArrayList();
if (trackMemoryConsumption) {
System.err.println("Note: Memory measurement can influence time measurement!");
runGC();
heap1 = usedMemory(); // Take a before heap snapshot
}

tx = session.beginTransaction();
Query query = session
.createQuery("FROM Cashflow ");
query.setFirstResult(1);
query.setMaxResults(size);

results = query.scroll(ScrollMode.FORWARD_ONLY);

while (results.next()) {
cashFlows.add(results.get(0));
}
tx.commit();

assertEquals(size, cashFlows.size());

if (trackMemoryConsumption) {
heap2 = usedMemory(); // Take an after heap snapshot:
final long heapsizeDiff = heap2 - heap1;
System.out.println("'before' heap: " + heap1
+ ", 'after' heap: " + heap2);
System.out.println("heap delta: " + heapsizeDiff / 1024d
/ 1024d + " MB");
}

results = null;
cashFlows = null;

runGC();// aufräumen für nächste schleife

}
} catch (Throwable t) {
t.printStackTrace();
if (tx != null) {
tx.rollback();
}
throw new PersistenceException(t);
}

long end = System.currentTimeMillis();

System.out.println("runtime with ScrollableResults "
+ repeats + " repeats with " + size + " Cashflows = "
+ ((end - start) / (double) repeats));
}

private void runGC() throws Exception {
// It helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r)
_runGC();
}

private void _runGC() throws Exception {
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++i) {
runtime.runFinalization();
runtime.gc();
Thread.currentThread().yield();

usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}

private long usedMemory() {
return runtime.totalMemory() - runtime.freeMemory();
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hibernate中的query 博客分类: • Hibernate HibernateSQLSQL ServerMySQLJDBC Hibernate中的query.setFirstResult(),query.setMaxResults(); 一、query.scroll()和query.setFirstResult(),query.setMaxResults();这两种方法都可以取到一定范围内的数据,用来数据分页显示。那么两者区别,以及两者的效率如何? 答:1.scroll是用JDBC2.0的可滚动结果集实现;query.setMaxResults();query.setFirstResult()是数据库SQL语句实现。 2.你说是在数据库就分页好呢?还是把结果集都取到内存再分页好呢?(应该是在数据库就分了好些吧,但是如果在内存分页的话,换页的时候是不是更快一些呢?) 3.在数据库进行分页是首选的方式。数据库分页实际上是利用数据库本身SQL扩展的功能进行分页,例如MySQL的 limit 0,50这样的SQL语句。不但速度快,而且非常节省内存。不过不是每种数据库的都有这种分页支持的SQL,例如SQL Server就不支持。 4.scroll是利用JDBC2.0的功能做分页的,那么就完全取决于特定数据库的JDBC Driver的实现了。事实上大部分JDBC Driver都是把所有的结果集都一次取到内存,然后再分页的。如果这个结果集非常大,例如几万条,不但程序执行速度会很慢,而且很容易导致out of memory。当然个别JDBC Driver使用了服务器端游标来实现,那么就不会导致这种问题,例如jTDS。 二、Hibernate可以使用Query.setMaxResults方法简单地设置需要查询的最大结果集。 然后Hibernate会自动根据所设置的数据库方言翻译成相应的SQL语句提交给数据库。比如如果数据库是Oracle,SQL Server等,则翻译为类似select ... top 10之类的SQL语句,若是MySQL,则翻译为select ... limit 10之类的SQL。 三、举例: Java代码 1. import org.hibernate.Query; 2. 3. query.setFirstResult(0),query.setMaxResults(4);相当于MySQL中的limit 0, 4; 4. public void testQuery() { 5. Session session = null; 6. try { 7. session = HibernateUtils.getSession(); 8. session.beginTransaction(); 9. Query query = session.createQuery("from User"); 10. query.setFirstResult(0);//从第一条记录开始 11. query.setMaxResults(4);//取出四条记录 12. List userList = query.list(); 13. for (Iterator iter=userList.iterator(); iter.hasNext();) { 14. User user = (User)iter.next(); 15. System.out.println(user.getId()); 16. System.out.println(user.getName()); 17. } 18. session.getTransaction().commit(); 19. }catch(Exception e) { 20. e.printStackTrace(); 21. session.getTransaction().rollback(); 22. }finally { 23. HibernateUtils.closeSession(session); 24. } 25. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值