Đố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);
}
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
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