我正在使用 Spring 2.5.5。休眠3.2。和 MySQL。
我得到:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at beans.Country$$EnhancerByCGLIB$$e757f40e.getStringId(<generated>)
at beans.Address.getCountryStringId(Address.java:137)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:157)
at beans.Address$$EnhancerByCGLIB$$ef3e9848.getCountryStringId(<generated>)
at checkout.OrderService.ECSetExpressCheckoutCode(OrderService.java:274)
这部分我理解(Hibernate 为 Address 而不是真正的目标放置了一个代理,当我尝试从 checkout.OrderService.ECSetExpressCheckoutCode 方法中的持久用户对象获取地址时,我得到 LazyInitializationException)。
这就是我开始阅读有关 Spring 和 Hibernate 的事务管理的原因。我在 stackoverflow 上阅读了几个线程,但我没有遇到任何实现。我还阅读了:http:
//community.jboss.org/wiki/Sessionsandtransactions
http://community.jboss.org/wiki/OpenSessioninView
http://community.jboss.org/wiki/SessionhandlingwithAOP
Spring 参考 - 9.5。声明式事务管理
Spring 参考 - 12.2.7。声明式事务划分
等等。
我的事务管理配置(按照说明)如下所示:
<!-- =============================== TRANSACTION MANAGMENT ============================= -->
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="orderServiceOperation" expression="execution(* checkout.OrderService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="orderServiceOperation"/>
</aop:config>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<!-- ============================ END OF TRANSACTION MANAGMENT ========================= -->
我再次得到同样的错误!
我不确定此配置是否与我拥有的 Dao 层实现冲突(但不应该如此):
public class AccountDao implements AccountDaoInterface {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public User getUserForUserId(final long ruserId) throws DataAccessException {
return (User) this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
List objList = session.createQuery("from User where id=" + userId).list();
User user = null;
if (!objList.isEmpty()){
user = (User) objList.get(0);
}
return user;
}
});
}
//other methods
}
我知道地址代理要从数据库中获取“真实”目标,我需要提供一个 Hibernate 会话和事务。我读到了几种模式,但对我来说最方便的是声明性方法,使我的方法被划分(从事务逻辑“干净”)。那么我的配置中缺少什么?请记住,我不仅需要 DAO 层中的事务管理,还需要服务层(可能还有控制器)。我怎样才能使这项工作?
亲切的问候,
暴君
EDIT1:(由于请求更多信息)首先看AccountDao,方法getUserForUserId。这是我从应用程序的某一点调用的方法。所以你可以了解 User 是什么以及它是如何映射的,我为你提供了以下 POJO:
public class User implements Serializable{
private long id;
private Address shippingAddress;
private Address billingAddress;
private String otherData;
//default constructor, constructor using fields, getters, setters.
}
public class Address implements Serializable{
private long id;
private Country country;
private String otherData;
//default constructor, constructor using fields, getters, setters.
}
public class Country implements Serializable {
int id;
String stringId;
String name;
}
和映射文件:
<class name="User" table="User">
<id name="id" column="id" type="long" unsaved-value="-1">
<generator class="native" />
</id>
<many-to-one name="shippingAddress" class="beans.Address" column="shippingAddressId" not-null="true" cascade="persist,merge,save-update"/>
<many-to-one name="billingAddress" class="beans.Address" column="billingAddressId" not-null="true" cascade="persist,merge,save-update"/>
</class>
<class name="Address" table="Address">
<id name="id" column="id" type="long">
<generator class="native" />
</id>
<many-to-one name="country" class="Country" column="countryId" not-null="true" cascade="none" />
</class>
<class name="Country" table="Country">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<property name="stringId" type="string" not-null="true" length="4"/>
<property name="name" type="string" not-null="true" length="100"/>
</class>
在应用程序的某一点获取用户后,处理流程正常,因为我没有访问用户对象中的地址。所以想象一下几个请求和响应来回走动。然后出现某个请求(不是说它很重要,而是用户选择一个选项并单击提交按钮)并且处理导致 checkout.OrderService.ECSetExpressCheckoutCode 方法在 OrderService.java:274 行我有:
user.getShippingAddress().getCountryStringId().equals(AddressConst.COUNTRY_US_STRING_ID)
一旦我尝试输入这一行,我就会得到 LazYInitException,因为 Address 类是使用默认的 lazy="true" 属性映射的。
这是足够的解释吗?问题是正确的 Spring Hibernate 声明式事务管理配置是什么?