我使用此链接中的代码创建了自定义 Spring 范围,它允许使用view
类似于 JSF2 @ViewScoped 的范围 Spring 托管 bean。
当用户按下提交按钮时,会发生以下情况:
- Backbean AA (@Scope(value="view") calls injected @Service BB
- @Service BB calls DAO class CC
- CC is @Transactional(readOnly = true) and has sessionFactory injected
private SessionFactory sessionFactory;
//inject sessionGactory
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
- in CC i set the @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
for functions such as save/delete/saveOrUpdate
与此类有关的 Hibernate 映射是:
RegUser.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.testApp.hibernate.RegUser" table="reg_users" schema="dbo" catalog="devDB">
<id name="userPk" type="java.lang.Long">
<column name="userPK" />
<generator class="identity" />
</id>
<property name="firstname" type="java.lang.String">
<column name="firstname" length="25" not-null="true" />
</property>
<property name="lastname" type="java.lang.String">
<column name="lastname" length="50" not-null="true" />
</property>
<set name="UserVsOrderses" inverse="true">
<key>
<column name="userPK" not-null="true" />
</key>
<one-to-many class="com.testApp.hibernate.UserVsOrders" />
</set>
</class>
</hibernate-mapping>
UserVsOrders.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.testApp.hibernate.custOrders" table="custOrders" schema="dbo" catalog="devDB">
<composite-id name="id" class="com.testApp.hibernate.custOrdersId">
<key-property name="userPk" type="java.lang.Long">
<column name="userPK" />
</key-property>
<key-property name="OrderPk" type="java.lang.Long">
<column name="OrderPK" />
</key-property>
</composite-id>
<many-to-one name="RegUser" class="com.testApp.hibernate.RegUser" update="false" insert="false" fetch="select">
<column name="userPK" not-null="true" />
</many-to-one>
<many-to-one name="Order" class="com.testApp.hibernate.Order" update="false" insert="false" fetch="select">
<column name="OrderPK" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
应用程序上下文.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.testApp" />
<context:annotation-config />
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="view">
<bean class="com.testApp.util.ViewScope" />
</entry>
</map>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver">
</property>
<property name="url" value="jdbc:jtds:sqlserver://localhost:1433/devDB">
</property>
<property name="username" value="blabla"></property>
<property name="password" value="blabla"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">20</prop>
<prop key="hibernate.c3p0.idle_test_period">300</prop>
<prop key="hibernate.c3p0.timeout">1800</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="c3p0.acquire_increment">1</prop>
<props>
</property>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
...
<!-- some other beans declared below -->
...
<!-- all the Mapping Resource -->
</beans>
我的问题是第一个表单提交一切都很好,但是在下一个表单提交时我得到:
failed to lazily initialize a collection, no session or session was closed
viewId=/page/regNewCust.xhtml
location=C:\repo\dev\WebRoot\nz\regNewCust.xhtml
phaseId=PROCESS_VALIDATIONS(3)
Caused by:
org.hibernate.LazyInitializationException - failed to lazily initialize a collection, no session or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:394)
如果我将 bean 范围设置为@Scope(value='request')
我尝试添加以下内容,web.xml
但没有帮助:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我也尝试过添加<set name="UserVsOrderses" inverse="true" fetch="join">
也没有帮助。
谁能指出我做错了什么以及如何解决这个问题?