Batch processing trong Hibernate

Trong bài trước tôi đã có giới thiệu về cách sử dụng công cụ Hiberante tool để atuto generate ra các entities mapping với database.

Trong bài này tôi sẽ giới thiệu về 1 phần quan trọng của Hibernate trong quá trình thao tác với cơ sở dữ liệu đó chính là batch processing hay còn gọi là xử lý hàng loạt.

c4437dfea863366b4d77810e939e6dcb02c0e7cc.png

1.Batch processing

Đối với cách viết "ngây thơ" của người mới bắt đầu tiếp cận sử dụng hibernate trong việc insert 100.000 bản ghi vào database bằng việc việc sử dụng hibernate sẽ là thế này:

    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    for ( int i=0; i<100000; i++ ) {
        User user = new User(...);
        session.save(user);
    }
    tx.commit();
    session.close();

Việc insert này sẽ thất bại với việc bắn ra 1 exception OutOfMemmeryException khi insert đến độ khoảng 50,000 bản ghỉ. Điều này xảy ra do việc caches dữ liệu insert mới vào trong session-level cache. Vậy có cách nào để khắc phục điều này? Đó chính là sử dụng bath processing trong Hibernate.

Trước hết muốn sự dụng batch process trong hibernate, bạn phải enable sử dụng JDBC batching. Điều này cực kỳ quan trọng nếu như bạn muốn tối ưu hiệu suất thác tác với database. Tiếp đó chúng ta sẽ thiết lập size batch JDBC đẻ caching dữ liệu cần thao tác. (Tùy vào đối tượng dữ liệu mà số size batch được đề suất trong khoảng 10-50)

hibernate.jdbc.batch_size 20

1.1. Batch inserts

Chúng ta cần tạo mới đối tựong persistent flush() để synchronize với trạng JDBC connection's state với trạng thái thiết lập đối tượng trong bộ nhớ. Sau đó cần clear() session để control size batch tại first-level cache.

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

    for ( int i=0; i<100000; i++ ) {
        User user = new User(....);
        session.save(user);
        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();

1.2 Batch update

Để lấy ra và update dữ liệu, chúng ta cần sử dụng scroll() để tận dụng con trỏ máy chủ truy vấn trả về nhièu dòng dữ liệu.

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

    ScrollableResults users = session.getNamedQuery("getListUsers")
        .setCacheMode(CacheMode.IGNORE)
        .scroll(ScrollMode.FORWARD_ONLY);
    int count=0;
    while ( users.next() ) {
        User user = (User) users.get(0);
        customer.updateStuff(...);
        if ( ++count % 20 == 0 ) {
            //flush a batch of updates and release memory:
            session.flush();
            session.clear();
        }
    }
    tx.commit();
    session.close();