'没有会话或会话关闭' 与JPA 2和EJB 3.1
我有这种方法无状态会话bean:'没有会话或会话关闭' 与JPA 2和EJB 3.1
@Override
public List<Character> getUserCharacters(int userId) {
User user = em.find(User.class, userId);
if(user != null)
return user.getCharacters();
else
return null;
}
其中,如果以这种方式定义User
类:
@Entity
@Table(name="Users")
public class User implements Serializable{
/** */
private static final long serialVersionUID = 8119486011976039947L;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private int id;
@ManyToMany(fetch=FetchType.EAGER)
private Set<Role> roles;
@OneToMany(mappedBy="owner",fetch=FetchType.LAZY)
private List<com.AandP.game.model.characters.Character> characters;
public User() {
creationDate = new Date();
roles = new HashSet<Role>();
}
}
但当我执行此方法(从我的@Named
豆)我收到异常:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.AandP.game.model.User.characters, no session or session was closed
根据t o JPA 2.0规范会话应该在整个事务中保持活跃状态。在这种情况下,交易(在我看来)持续整个方法调用(在类或方法上没有额外的事务属性)。
所以问题是:这段代码有什么问题,以及如何以懒惰的方式加载类属性。
您需要指定@TransactionAttribute
,以便您的方法是事务性的。否则,为每个实体管理器操作启动只读事务和新的底层会话。这与懒惰集合相结合意味着当您获取集合时,原始会话将被关闭。
According to the JPA 2.0 specification session should stay alive for a whole transaction. In this situation transaction (in my opinion) last for a whole method call (there is no additional transaction attributes on class or method).
这是真的,但它不包括返回对象的序列化。
我有同样的问题导出会话bean作为Web服务。详细了解问题here。
如果你有类似的用法会强烈建议你返回普通对象而不是实体。你可以像我们一样使用一些bean映射框架。我们使用Dozer。
pWoz:Bozho说的是正确的。我要添加的一个警告是,如果你没有通过接口(本地或远程)进入该方法,则该注释无关紧要。如果这是你的bean的样子:
@Stateless
public class MyUserBean implements UserBeanLocal {
...
public void doSomeStuffWithUserCharactersById(int id) {
List<Character>userCharacters = getUserCharacters(id);
}
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<Character> getUserCharacters(int userId) {
User user = em.find(User.class, userId);
if(user != null)
return user.getCharacters();
else
return null;
}
}
该属性的不会因为在同一会话bean的兑现,调用的第一个业务方法确定事务上下文和行为。现在,我无法确定在这种情况下发生了什么,因为我没有看到其他源代码,但这是一个非常常见的错误。
我正在通过一个接口进入这个方法。 'getUserCharacters(int userId)'是这个类中唯一的方法,这个类是无状态的会话bean。 – pWoz 2012-05-08 19:25:40
我还做了一些调查,并且在'return user.getCharacters()'之前添加'user.getCharacters()。size()'时,一切正常。所以,我认为,这个例子中的return语句不会初始化'User'类中的'characters'集合。我必须调用这个集合的任何方法来强制Hibernate初始化列表。但是这个例外很具误导性。 – pWoz 2012-05-08 19:33:32
2013年7月24日19:47:07387错误: - 未能懒洋洋地初始化角色的集合:com.xxxx.domain.DenialMaster.denialDetails,没有会话或会话关闭空
我的配置:
<tx:annotation-driven transaction-manager="transactionManagerDL" />
<bean id="transactionManagerDL" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfDL" />
</bean>
<bean id="emfDL" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceDL" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="mappingResources">
<value>META-INF/orm.xml</value>
</property>
<property name="packagesToScan" value="${dl.entity.packages}" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${catalog.org.hibernate.dialect}</prop>
<prop key="hibernate.max_fetch_depth">${catalog.org.hibernate.jdbc.max.fetchdepth}</prop>
<prop key="hibernate.jdbc.fetch_size">${catalog.org.hibernate.jdbc.fetchsize}</prop>
<prop key="hibernate.jdbc.batch_size">${catalog.org.hibernate.jdbc.batchsize}</prop>
<prop key="hibernate.show_sql">${catalog.org.hibernate.showsql}</prop>
<prop key="hibernate.connection.autocommit">${catalog.org.hibernate.connection.autocommit}
</prop>
</props>
</property>
</bean>
SOLUTION: 在类ServiceImpl添加@Transactional(readOnly的=真) 实施例:
@Override
@Transactional(readOnly = true)
public YourBean findById(long id) throws Exception {
return yourDAO.findOne(id);
}
和@LazyCollection(LazyCollectionOption.FALSE):
@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name = "idMaster")
@LazyCollection(LazyCollectionOption.FALSE)
public List<DenialDetail> getDenialDetails() {
return denialDetails;
}
我应该使用哪一种'TransactionAttributeType'?Javadocs说:_如果没有指定TransactionAttribute注解,并且bean使用容器管理的事务分界,则假定REQUIRED事务属性的语义。因此,我认为没有'TransactionAttribute'注释的注释方法是可以的。 – pWoz 2012-03-09 07:55:53
Bozho能解释吗? – pWoz 2012-03-15 15:03:17
否:)可能会有另一个子句提到只读事务。但是添加一个TransactionAttribute的工作? – Bozho 2012-03-15 16:05:52