2010-06-14 27 views
38

Đối với một câu trả lời cuộn xuống cuối này ...Hibernate/Spring: thất bại trong việc uể oải khởi - không có phiên làm việc hoặc phiên đã được đóng

Vấn đề cơ bản là giống như nhiều lần hỏi. Tôi có một chương trình đơn giản với hai Sự kiện và Người dùng POJOs - nơi người dùng có thể có nhiều sự kiện.

@Entity 
@Table 
public class Event { 
private Long id; 
private String name; 
private User user; 

@Column 
@Id 
@GeneratedValue 
public Long getId() {return id;} 
public void setId(Long id) { this.id = id; } 

@Column 
public String getName() {return name;} 
public void setName(String name) {this.name = name;} 

@ManyToOne 
@JoinColumn(name="user_id") 
public User getUser() {return user;} 
public void setUser(User user) {this.user = user;} 

} 

thành viên:

@Entity 
@Table 
public class User { 
private Long id; 
private String name; 
private List<Event> events; 

@Column 
@Id 
@GeneratedValue 
public Long getId() { return id; } 
public void setId(Long id) { this.id = id; } 

@Column 
public String getName() { return name; } 
public void setName(String name) { this.name = name; } 

@OneToMany(mappedBy="user", fetch=FetchType.LAZY) 
public List<Event> getEvents() { return events; } 
public void setEvents(List<Event> events) { this.events = events; } 

} 

Lưu ý: Đây là một dự án mẫu. Tôi thực sự muốn sử dụng tìm nạp Lười biếng ở đây.

Bây giờ chúng ta cần phải cấu hình mùa xuân và ngủ đông và có một cơ bản-db.xml đơn giản để tải:

 

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:aop="http://www.springframework.org/schema/aop" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
      http://www.springframework.org/schema/aop 
      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 


<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close" scope="thread"> 
    <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <property name="url" value="jdbc:mysql://192.168.1.34:3306/hibernateTest" /> 
    <property name="username" value="root" /> 
    <property name="password" value="" /> 
    <aop:scoped-proxy/> 
</bean> 

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> 
    <property name="scopes"> 
    <map> 
    <entry key="thread"> 
    <bean class="org.springframework.context.support.SimpleThreadScope" /> 
    </entry> 
    </map> 
    </property> 
</bean> 

<bean id="mySessionFactory" 
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope="thread"> 
    <property name="dataSource" ref="myDataSource" /> 
    <property name="annotatedClasses"> 
    <list> 
    <value>data.model.User</value> 
    <value>data.model.Event</value> 
    </list> 
    </property> 
    <property name="hibernateProperties"> 
    <props> 
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> 
    <prop key="hibernate.show_sql">true</prop> 
    <prop key="hibernate.hbm2ddl.auto">create</prop> 
    </props> 
    </property> 
    <aop:scoped-proxy/> 

</bean> 

<bean id="myUserDAO" class="data.dao.impl.UserDaoImpl"> 
    <property name="sessionFactory" ref="mySessionFactory" /> 
</bean> 

<bean id="myEventDAO" class="data.dao.impl.EventDaoImpl"> 
    <property name="sessionFactory" ref="mySessionFactory" /> 
</bean> 

</beans> 
 

Lưu ý: Tôi đã chơi xung quanh với các CustomScopeConfigurer và SimpleThreadScope, nhưng điều đó didnt thay đổi bất cứ điều gì.

Tôi có một đơn giản dao-impl (chỉ dán userDao - các EventDao là khá nhiều giống nhau - ngoại trừ với các chức năng "listWith":

 

public class UserDaoImpl implements UserDao{ 

private HibernateTemplate hibernateTemplate; 

public void setSessionFactory(SessionFactory sessionFactory) { 
    this.hibernateTemplate = new HibernateTemplate(sessionFactory); 

} 

@SuppressWarnings("unchecked") 
@Override 
public List listUser() { 
    return hibernateTemplate.find("from User"); 
} 

@Override 
public void saveUser(User user) { 
    hibernateTemplate.saveOrUpdate(user); 

} 

@Override 
public List listUserWithEvent() { 

    List users = hibernateTemplate.find("from User"); 
    for (User user : users) { 
    System.out.println("LIST : " + user.getName() + ":"); 
    user.getEvents().size(); 
    } 
    return users; 
} 

} 
 

Tôi nhận được org.hibernate.LazyInitializationException - không thể tạo một tập hợp vai trò: data.model.User.events, không phiên hoặc phiên nào được đóng tại dòng với user.getEvents(). size();

Và cuối cùng nhưng không kém phần quan trọng ở đây là lớp Bài kiểm tra tôi sử dụng:

 

public class HibernateTest { 

public static void main(String[] args) { 

    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("basic-db.xml"); 


    UserDao udao = (UserDao) ac.getBean("myUserDAO"); 
    EventDao edao = (EventDao) ac.getBean("myEventDAO"); 


    System.out.println("New user..."); 
    User user = new User(); 
    user.setName("test"); 

    Event event1 = new Event(); 
    event1.setName("Birthday1"); 
    event1.setUser(user); 

    Event event2 = new Event(); 
    event2.setName("Birthday2"); 
    event2.setUser(user); 

    udao.saveUser(user); 
    edao.saveEvent(event1); 
    edao.saveEvent(event2); 

    List users = udao.listUserWithEvent(); 
    System.out.println("Events for users"); 
    for (User u : users) { 

    System.out.println(u.getId() + ":" + u.getName() + " --"); 
    for (Event e : u.getEvents()) 
    { 
    System.out.println("\t" + e.getId() + ":" + e.getName()); 
    } 
    } 

    ((ConfigurableApplicationContext)ac).close(); 
} 

} 
 

và đây là ngoại lệ:

 
1621 [main] ERROR org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) 
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119) 
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248) 
at data.dao.impl.UserDaoImpl.listUserWithEvent(UserDaoImpl.java:38) 
at HibernateTest.main(HibernateTest.java:44) 
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: data.model.User.events, no session or session was closed 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) 
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) 
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119) 
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248) 
at data.dao.impl.UserDaoImpl.listUserWithEvent(UserDaoImpl.java:38) 
at HibernateTest.main(HibernateTest.java:44) 

Mọi thứ đã cố gắng nhưng đã không làm việc:

  • gán một threadScope và sử dụng BeanFactory (Tôi đã từng "yêu cầu" hoặc "chủ đề" - có sự khác biệt chú ý):
 
    // scope stuff 
    Scope threadScope = new SimpleThreadScope(); 
    ConfigurableListableBeanFactory beanFactory = ac.getBeanFactory(); 
    beanFactory.registerScope("request", threadScope); 
    ac.refresh(); 
... 
  • Thiết lập một giao dịch bằng cách nhận các đối tượng session từ deo:
 
... 
    Transaction tx = ((UserDaoImpl)udao).getSession().beginTransaction(); 
    tx.begin(); 
    users = udao.listUserWithEvent(); 
... 
  • nhận được một giao dịch trong listUserWithEvent()
 
public List listUserWithEvent() { 
    SessionFactory sf = hibernateTemplate.getSessionFactory(); 
    Session s = sf.openSession(); 
    Transaction tx = s.beginTransaction(); 
    tx.begin(); 

    List users = hibernateTemplate.find("from User"); 
    for (User user : users) { 
    System.out.println("LIST : " + user.getName() + ":"); 
    user.getEvents().size(); 
    } 
    tx.commit(); 
    return users; 
} 

Tôi thực sự ra khỏi ý tưởng bây giờ . Ngoài ra, việc sử dụng listUser hoặc listEvent chỉ hoạt động tốt.

Bước về phía trước:

Nhờ Thierry tôi đã thêm một bước nữa (tôi nghĩ). Tôi đã tạo ra lớp MyTransaction và làm toàn bộ công việc của tôi ở đó, nhận mọi thứ từ mùa xuân.Chính mới trông giống như sau:

 

public static void main(String[] args) { 

    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("basic-db.xml"); 

    // getting dao 
    UserDao udao = (UserDao) ac.getBean("myUserDAO"); 
    EventDao edao = (EventDao) ac.getBean("myEventDAO"); 

    // gettting transaction template 
    TransactionTemplate transactionTemplate = (TransactionTemplate) ac.getBean("transactionTemplate"); 

    MyTransaction mt = new MyTransaction(udao, edao); 
    transactionTemplate.execute(mt); 

    ((ConfigurableApplicationContext)ac).close(); 
} 
 

Thật không may bây giờ có một ngoại lệ con trỏ null @: user.getEvents(). Size(); (trong daoImpl).

Tôi biết rằng nó không được rỗng (không phải từ đầu ra trong bảng điều khiển cũng như từ bố cục db).

Đây là giao diện điều khiển đầu ra để biết thêm thông tin (tôi đã làm một tấm séc cho user.getEvent() == null và in "EVENT là NULL"):

 
New user... 
Hibernate: insert into User (name) values (?) 
Hibernate: insert into User (name) values (?) 
Hibernate: insert into Event (name, user_id) values (?, ?) 
Hibernate: insert into Event (name, user_id) values (?, ?) 
Hibernate: insert into Event (name, user_id) values (?, ?) 
List users: 
Hibernate: select user0_.id as id0_, user0_.name as name0_ from User user0_ 
1:User1 
2:User2 
List events: 
Hibernate: select event0_.id as id1_, event0_.name as name1_, event0_.user_id as user3_1_ from Event event0_ 
1:Birthday1 for 1:User1 
2:Birthday2 for 1:User1 
3:Wedding for 2:User2 
Hibernate: select user0_.id as id0_, user0_.name as name0_ from User user0_ 
Events for users 
1:User1 -- 
EVENT is NULL 
2:User2 -- 
EVENT is NULL 

Bạn có thể lấy dự án mẫu từ http://www.gargan.org/code/hibernate-test1.tgz (nó là một dự án eclipse/maven)

Các giải pháp (cho giao diện điều khiển ứng dụng)

thực tế, có hai giải pháp cho vấn đề này - tùy thuộc vào môi trường của bạn:

Đối với một ứng dụng giao diện điều khiển bạn cần một mẫu giao dịch mà chụp logic actutal db và sẽ chăm sóc của các giao dịch:

 

public class UserGetTransaction implements TransactionCallback{ 

public List users; 

protected ApplicationContext context; 

public UserGetTransaction (ApplicationContext context) { 
    this.context = context; 
} 

@Override 
public Boolean doInTransaction(TransactionStatus arg0) { 
    UserDao udao = (UserDao) ac.getBean("myUserDAO"); 
    users = udao.listUserWithEvent(); 
    return null; 
} 

} 
 

Bạn có thể sử dụng điều này bằng cách gọi:

 

TransactionTemplate transactionTemplate = (TransactionTemplate) context.getBean("transactionTemplate"); 
UserGetTransaction mt = new UserGetTransaction(context); 
transactionTemplate.execute(mt); 
 

Để cho điều này để làm việc bạn cần phải xác định lớp mẫu cho mùa xuân (ví dụ: trong cơ bản-db.xml của bạn):

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 
    <property name="transactionManager" ref="transactionManager"/> 
</bean> 

khác (có thể) giải pháp

nhờ andi

PlatformTransactionManager transactionManager = (PlatformTransactionManager) applicationContext.getBean("transactionManager"); 
    DefaultTransactionAttribute transactionAttribute = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED); 

transactionAttribute.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); 
    TransactionStatus status = transactionManager.getTransaction(transactionAttribute); 
    boolean success = false; 
    try { 
     new UserDataAccessCode().execute(); 
     success = true; 
    } finally { 
     if (success) { 
     transactionManager.commit(status); 
     } else { 
     transactionManager.rollback(status); 
     } 
    } 

Các giải pháp (cho servlets)

Servlets là không phải là vấn đề lớn. Khi bạn có một servlet bạn chỉ có thể bắt đầu và ràng buộc một giao dịch vào đầu chức năng của bạn và unbind nó một lần nữa ở cuối:

public void doGet(...) { 
    SessionFactory sessionFactory = (SessionFactory) context.getBean("sessionFactory"); 
    Session session = SessionFactoryUtils.getSession(sessionFactory, true); 
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); 

// Your code.... 

    TransactionSynchronizationManager.unbindResource(sessionFactory); 
} 

Trả lời

26

Tôi nghĩ bạn không nên sử dụng các phương pháp giao dịch phiên hibernate, nhưng chúng ta hãy mùa xuân làm cái đó.

Thêm phần này vào conf mùa xuân của bạn:

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="mySessionFactory" /> 
</bean> 

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 
    <property name="transactionManager" ref="txManager"/> 
</bean> 

và sau đó tôi sẽ sửa đổi phương pháp thử nghiệm của bạn để sử dụng mẫu giao dịch mùa xuân:

public static void main(String[] args) { 
    // init here (getting dao and transaction template) 

    transactionTemplate.execute(new TransactionCallback() { 
     @Override 
     public Object doInTransaction(TransactionStatus status) { 
      // do your hibernate stuff in here : call save, list method, etc 
     } 
    } 
} 

như một mặt lưu ý, các hiệp hội @OneToMany là lười biếng theo mặc định, do đó bạn không cần chú thích nó một cách lười biếng.(@ * ToMany là LAZY theo mặc định, @ * Toone đang háo hức theo mặc định)

EDIT: bây giờ đây là những gì đang xảy ra từ thời điểm hibernate của xem:

  • phiên mở (với sự khởi đầu giao dịch)
  • lưu người dùng và giữ nó trong phiên làm việc (xem bộ nhớ cache phiên làm đối tượng băm trong đó khóa là id tổ chức)
  • lưu sự kiện và giữ nó trong phiên
  • lưu sự kiện khác và giữ nó trong phiên
  • ... cùng với tất cả các hoạt động tiết kiệm ...

  • sau đó tải tất cả người dùng ("từ người dùng" query)

  • tại điểm đó ngủ đông thấy rằng nó có đã đối tượng trong phiên của nó, do đó, loại bỏ nó nhận được từ yêu cầu và trả lại một từ phiên.
  • người dùng của bạn trong phiên không có bộ sưu tập sự kiện được khởi tạo, vì vậy bạn sẽ bị vô hiệu.
  • ...

Dưới đây là một số điểm để tăng cường mã của bạn:

  • trong mô hình của bạn, khi bộ sưu tập đặt hàng là không cần thiết, sử dụng Set, không liệt kê cho các bộ sưu tập của bạn (Set tin sự kiện , không Danh sách sự kiện riêng tư)
  • trong mô hình của bạn, gõ các bộ sưu tập của bạn, nếu không ngủ đông sẽ không được tổ chức để lấy (tin Set <Event> sự kiện)
  • khi bạn thiết lập một mặt của một bidire quan hệ ctional, và bạn muốn sử dụng bên mappedBy của quan hệ trong cùng một giao dịch, đặt cả hai mặt. Hibernate sẽ không làm điều đó cho bạn trước tx tiếp theo (khi phiên là một khung nhìn mới từ trạng thái db).

Vì vậy, để giải quyết các điểm trên, hoặc thực hiện tiết kiệm trong một giao dịch, và tải trong nhau:

public static void main(String[] args) { 
    // init here (getting dao and transaction template) 
    transactionTemplate.execute(new TransactionCallback() { 
     @Override 
     public Object doInTransaction(TransactionStatus status) { 
      // save here 
     } 
    } 

    transactionTemplate.execute(new TransactionCallback() { 
     @Override 
     public Object doInTransaction(TransactionStatus status) { 
      // list here 
     } 
    } 
} 

hoặc đặt cả hai bên:

... 
event1.setUser(user); 
... 
event2.setUser(user); 
... 
user.setEvents(Arrays.asList(event1,event2)); 
... 

(Cũng làm đừng quên giải quyết các điểm nâng cao mã ở trên, Đặt không phải Danh sách, nhập bộ sưu tập)

+1

Tôi đã thử giải pháp của bạn và tôi đã loại bỏ vấn đề Lười biếng - không may, không tải bất kỳ Sự kiện nào: user.getEvents() Tạo con trỏ rỗng (độ cao tôi có thể thấy trong db và từ đầu tiên lặp lại mà người dùng có các sự kiện liên quan). Có thể hibernateTemplate.find doe snot giải quyết các phụ thuộc không? – Niko

+0

Tôi đã tải lên dự án thử nghiệm của mình với đề xuất của bạn đã có sẵn. có lẽ bạn có thể tìm hiểu những gì đang xảy ra. – Niko

3

Vấn đề là dao của bạn đang sử dụng một phiên ngủ đông nhưng l azy tải của user.getName (Tôi giả định đó là nơi nó ném) đang xảy ra bên ngoài phiên đó - hoặc không phải trong một phiên họp ở tất cả hoặc trong phiên khác. Thông thường, chúng tôi mở một phiên ngủ đông trước khi chúng tôi thực hiện cuộc gọi DAO và không đóng cuộc gọi cho đến khi chúng tôi hoàn thành tất cả các tải trọng lười biếng. Yêu cầu web thường được bao bọc trong một phiên lớn nên những vấn đề này không xảy ra.

Thông thường chúng tôi đã bao gồm các cuộc gọi dao và lười biếng của chúng tôi trong SessionWrapper. Một cái gì đó như sau:

public class SessionWrapper { 
    private SessionFactory sessionFactory; 
    public void setSessionFactory(SessionFactory sessionFactory) { 
     this.hibernateTemplate = new HibernateTemplate(sessionFactory); 
    } 
    public <T> T runLogic(Callable<T> logic) throws Exception { 
     Session session = null; 
     // if the session factory is already registered, don't do it again 
     if (TransactionSynchronizationManager.getResource(sessionFactory) == null) { 
      session = SessionFactoryUtils.getSession(sessionFactory, true); 
      TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); 
     } 

     try { 
      return logic.call(); 
     } finally { 
      // if we didn't create the session don't unregister/release it 
      if (session != null) { 
       TransactionSynchronizationManager.unbindResource(sessionFactory); 
       SessionFactoryUtils.releaseSession(session, sessionFactory); 
      } 
     } 
    } 
} 

Rõ ràng là SessionFactory cùng một SessionFactory được tiêm vào dao của bạn.


Trong trường hợp của bạn, bạn nên bọc toàn bộ danh sáchNgười dùngWithEvent body trong logic này. Một cái gì đó như:

public List listUserWithEvent() { 
    return sessionWrapper.runLogic(new Callable<List>() { 
     public List call() { 
      List users = hibernateTemplate.find("from User"); 
      for (User user : users) { 
       System.out.println("LIST : " + user.getName() + ":"); 
       user.getEvents().size(); 
      } 
     } 
    }); 
} 

Bạn sẽ cần phải tiêm phiên bản SessionWrapper vào daos của bạn.

+0

Thật không may là tôi không thực sự làm việc này. Bạn có nghĩa là bạn DAOImpl mở rộng SessionWrapper? Và ai (trong ví dụ của tôi) sẽ gọi runLogic và những gì sẽ là Callable? Có lẽ nó là cleaerer khi bạn mở rộng ví dụ và thích ứng nó với mã mẫu mà tôi đã cung cấp. Ngoài ra, câu hỏi của tôi là dành riêng cho không phải web, bởi vì tôi muốn sử dụng cùng một mô hình/daos tôi sử dụng trong web cũng cho các ứng dụng độc lập (Trình thu thập dữ liệu của chúng tôi). – Niko

+0

Xin lỗi, điều này thật khó hiểu. Tôi đã thêm một phần với một ví dụ runLogic. Bạn không cần phải thay đổi dao của bạn cả. Nó nên được tiêm với cùng một SessionFactory được tiêm vào SessionWrapper. SessionWrapper sau đó được tiêm vào các daos. – Gray

+0

Đó là những gì mẫu giao dịch mùa xuân đang làm. (nó chỉ thiếu Kiểu gõ: /) – Thierry

7

Tôi đã tìm kiếm gợi ý liên quan đến vấn đề tương tự. Tôi đã thử giải pháp được đề cập bởi Thierry và nó không hoạt động. Sau đó tôi đã thử những dòng này và nó đã hoạt động:

SessionFactory sessionFactory = (SessionFactory) context.getBean("sessionFactory"); 
Session session = SessionFactoryUtils.getSession(sessionFactory, true); 
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); 

Thực tế những gì tôi đang làm là một quá trình hàng loạt phải tận dụng các nhà quản lý/dịch vụ tồn tại của Spring. Sau khi tải ngữ cảnh và thực hiện một số lời gọi, tôi đã thành lập vấn đề nổi tiếng "thất bại trong việc lười biếng khởi tạo một bộ sưu tập". 3 dòng đó đã giải quyết nó cho tôi.

+0

Đã sửa lỗi! Mặc dù tập tin xml của tôi cho biết vì vậy tôi phải làm getBean ("wfSessionFactory") để thay thế. Ngoài ra nó có thể có thể sử dụng một "unbindResource" gọi trong đó ở cuối (xem câu trả lời ở phần cuối của câu hỏi) – rogerdpack

9

Trong trường hợp của ứng dụng Web, nó cũng có thể tuyên bố một bộ lọc đặc biệt trong web.xml, mà sẽ làm phiên mỗi yêu cầu:

<filter> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>openSessionInViewFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Sau đó bạn có thể lazyload dữ liệu của bạn bất cứ lúc nào trong suốt yêu cầu.

+0

trong ứng dụng của tôi Bộ lọc này cũng đã được tuyên bố, nhưng ngoại lệ là ném. –

2

Thú vị!

Tôi đã gặp sự cố tương tự trong phương thức xử lý @RequestMapping của @ Controller. Giải pháp đơn giản là để thêm một chú thích @Transactional với phương pháp xử lý do đó phiên được giữ mở cho toàn bộ thời gian thực hiện phương pháp cơ thể

1

giải pháp dễ nhất để thực hiện:

Trong phạm vi phiên [bên trong API chú thích với @Transactional], làm như sau:

nếu A có một danh sách <B> được lười biếng nạp, chỉ cần gọi một API mà làm cho chắc chắn Danh mục được nạp

API đó là gì?

size(); API của lớp List.

Vì vậy, tất cả những gì cần thiết là:

Logger.log (a.getBList.size());

Cuộc gọi đơn giản này để ghi nhật ký kích thước đảm bảo nó nhận được toàn bộ danh sách trước khi tính toán kích thước của danh sách. Bây giờ bạn sẽ không nhận được ngoại lệ!

+2

Điều này không hiệu quả đối với tôi. – abbas

0

Điều gì đã làm việc cho chúng tôi trong JBoss là giải pháp # 2 được lấy từ this site at Java Code Geeks.

web.xml:

<filter> 
     <filter-name>ConnectionFilter</filter-name> 
     <filter-class>web.ConnectionFilter</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>ConnectionFilter</filter-name> 
     <url-pattern>/faces/*</url-pattern> 
    </filter-mapping> 

ConnectionFilter:

import java.io.IOException; 
import javax.annotation.Resource; 
import javax.servlet.*; 
import javax.transaction.UserTransaction; 

public class ConnectionFilter implements Filter { 
    @Override 
    public void destroy() { } 

    @Resource 
    private UserTransaction utx; 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     try { 
      utx.begin(); 
      chain.doFilter(request, response); 
      utx.commit(); 
     } catch (Exception e) { } 
    } 

    @Override 
    public void init(FilterConfig arg0) throws ServletException { } 
} 

Có lẽ nó sẽ làm việc với mùa xuân quá.

Các vấn đề liên quan