Jika kita menggunakan Hibernate ORM framework bersama dengan
JPA tentu kita tidak asing dengan keyword LAZY. Biasanya digunakan pada
relationship di suatu domain atau entity object.
Jika suatu relasi mengunakan fetch Lazy, maka relasi pada
suatu entity tidak akan diGet datanya secara langsung pada saat query, melainkan saat dipanggil (get objectnya) saja baru dia diQuery. Maka
dinamakan LAZY Initialization.
Secara default suatu relasi jika tidak didefinisikan
fetchnya otomatis akan LAZY.
LAZY mempunyai keuntungan jika jumlah data si object relasi
itu cukup besar, tidak akan diload secara langsung dan tidak membebani query.
Berikut ini contohnya :
Kita memiliki entity Employee dan Address yang saling
berelasi.
Class Employee {
@Id
private Integer id;
private String firstname;
private String lastname;
private String phone;
@OneToMany(mappedBy = "addressId", targetEntity = Address.class ,cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Address> address ;
// settes + getter
}
Class Address {
@Id
private Integer id;
private String street;
private String city;
private Integer postal;
@ManyToOne
@JoinColumn(name = "ADDRESS_ID", insertable = true, updatable = true)
private Address addressId;
// setter + getter
}
Kemudian kita punya script query di class DAO :
public List<Address> getAddress() {
Query query = EntityManager.createQuery(“select e from Employee e where e.id=1”);
Employee employee = query.getSingleResult();
/// disini baru diquery : select e from employee e where e.id=1
List<Address> listAddress = employee.getAddress();
/// pada saat di getAddress() maka object address baru diquery;
/// select a from address a where a.address_id=…
/// Get Exception
}
Nah disinilah akan muncul error exception (Hibernate
LazyInitializationException), seperti ini :
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:86)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at com.freightgate.domain.SecurityFiling_$$_javassist_7.getSfSubmissionType(SecurityFiling_$$_javassist_7.java)
at com.freightgate.dao.SecurityFilingTest.test(SecurityFilingTest.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)......
Hal ini disebabkan karena query menggunakan
HibernateSession. Nah setelah query di getResult(). Session otomatis disclose
oleh JPA EntityManager.
Pada saat akan melakukan getAddress() tentu akan membutuhkan
HibernateSession juga untuk melakukan query ke database.
Karena HibernateSession sudah terlanjur di close(), muncul
exception diatas; could not initialize proxy – no Session at…
Biasanya muncul pada relasi OneToMany dan ManyToMany.
Bagaimana cara mengatasinya ?
1. Fetch di relasi diubah jadi EAGER.
Artinya object relasi akan di get langsung
pada saat query dijalankan. Cara ini tidak direkomendasikan karena jika data dari object relasi jumlahnya besar, query akan menjadi berat.
@OneToMany(mappedBy = "addressId", targetEntity = Addresss.class ,cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<Address> address ;
2. Memakai class native hibernateSession pada saat
query. Jadi bisa diatur kapan session open kapan session close. Tapi
kekurangannya jika JPA providernya diganti bukan Hibernate lagi. Maka akan
butuhkan banyak perubahan di code kita. Mungkin cara ini bisa dipakai di code kita menggunakan Hibernate murni tanpa JPA.
Session session = getHibernateSession();
Query query = session.getNamedQuery("Employee.getEmployeeById");
query.setParameter("ID", employeeId);
Expense result = (Employee) query.uniqueResult();
if(result != null){
Hibernate.initialize(result.getAddress());
return result;
}
session.close();
3. Menggunakan openEntityManagerFilter di WEB.XML. Session akan dimaintain oleh filter ini. Maka jika
ada request yang membutuhkan hibernateSession, maka entity filter tersebut akan
membukakan session ke database. Cara ini paling direkomendasikan.
<!-- hibernate session filter -->
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Selamat mencoba. :)
No comments:
Post a Comment