2007/06/14 18:00
Hibernate 기초 학습[45] Batch Basic
2007/06/14 18:00 in Hibernate 지식 공유하기/Hibernate_Basic

십만 번의 insert 작업을 수행하면 OutOfMemoryException 이 발생하게 됩니다. Hibernate는 insert를 Session의 2차 캐시(session-level cache)를 일차적으로 거쳐서 작업을 하게 되어있는데, 십만 번의 insert 작업은 session이 감당하기에는 지나치게 큰 작업이기 때문입니다.
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();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
}
tx.commit();
session.close();
이 문제를 피해갈 수 있는 방법에는 여러 가지가 있습니다.
첫 번째로 JDBC batch 설정을 해주는 방법입니다. 성능을 고려해 적당한 값을 설정해야 합니다. 일반적으로 레퍼런스에서는 10-50이 적당하다고 하네요..
hibernate.jdbc.batch_size 20
또 다른 방법은 Session level의 2차 cache를 꺼놓는 방법입니다. 당연히 비추입니다. '소'를 위해 '대'를 희생하는 경우가 되버립니다^^;
hibernate.cache.use_second_level_cache false
batch insert 작업을 할 경우에는 설정해 놓은 batch size에 맞춰서 session을 flush 해주고, 다시 깨끗이 session을 비워주면 됩니다.
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();
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();
batch update를 할 경우에는 scroll을 적절히 활용해서 Session의 사용 메모리를 최소화해야 합니다.
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();
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();
StatelessSession interface
하이버네이트는 batch 작업을 위해서 command-oriented API를 제공합니다.
StatelessSession는 higher-level의 라이프사이클을 제공하는 Persistence context 역할을 하지는 않습니다.
StatelessSession는 Persistence Context의 역할을 하는 Session이 제공하는 많은 기능등을 보장하지 않는데, StatelessSession이 보장하지 않는 기능에는 다음과 같은 것들이 있습니다.
- first-level cache
- transactional write-behind
- automatic dirty checking
- cascade to associated instance
- collection ignore
- bypass Hibernate's event model and interceptor
- transactional write-behind
- automatic dirty checking
- cascade to associated instance
- collection ignore
- bypass Hibernate's event model and interceptor
위와 같은 작업을 하지 않으면서, 보다 낮은 수준의 추상화 레벨에 접근하고, 일반적인 JDBC 수준의 작업을 이끌어 내서 데이터에 관련된 작업에만 집중하겠다는 생각인 것 같습니다.
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();
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();
StatelessSession에서 받은 Customer 인스턴스는 받자 마자 detached object 가 되버립니다. StatelessSession는 Persistence Context가 아니기 때문에(역할을 하지 않기 때문에)이죠.
StatelessSession로 수행된 insert() / update() / delete() 는 Persistence mechanism을 거치지 않고, SQL INSERT / UPDATE / DELETE를 통해서 바로 연결된 데이터베이스에 적용되게 됩니다.
Prev

Rss Feed