- 浏览: 244671 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
一EE:
确实可以解决问题,可是都不知道到底为什么会出现这个错误
jvm crash 的原因及解决办法 -
京华倦客:
太牛了
jvm crash 的原因及解决办法 -
ichenwenjin:
由OpenSessionInViewFilter报错引出的spring3.0事务配置问题及解决办法 -
BigBird2012:
我的配置是这样的,我是因为没有加<tx:anno ...
由OpenSessionInViewFilter报错引出的spring3.0事务配置问题及解决办法 -
luyuwww:
步骤如下: 1.多项目中公共的java包类分离出来啦,形 ...
eclipse多项目共享和同步java代码
开发环境
IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0
使用 OpenSessionInViewFilter的原因
在Service层执行插入,删除及数据更新操作时会包以下错误
报错原因:
看过OpenSessionInViewFilter以后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值
解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:通过spring的事务管理Hibernate的sessionFactory,对不同的数据操作作事务的隔离及限制
因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法
spring2.5以后就支持annotation配置了,到了3.0配置更加简化方便了,但对于新手来说,如果不懂具体的spring运作原理,很容易犯错误,并且在报错之后很难发现错误原因。
在此特将spring的配置方法写出来,并经过实例测试,是可以通过并正常运行的。希望对在这方面遇到问题的朋友有帮助,spring的基于annotation请不明白的朋友在网上查看相关文档。
主要配置文件有两个
app-config.xml 配置数据源,hibernate,事务等
mvc-config.xml 配置spring mvc的 controller,viewResolver,messageConvert等
本文主要涉及 app-config.xml的配置
首先通过以下配置,自动扫描com包内作了annotation注解的类,并实例化(至于里面为什么会有个exclude-filter请看文章的后面)
hibernate及数据源的配置
配置transactionManager管理事务
接下来是 自动化事务
如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册
因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下
app-config.xml
mvc-config.xml(注意里面的注释)
此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
更多事务注解的方式请参考spring3.0 reference
这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。
下面通过spring的aop对事务进行自动化管理,配置如下
注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >
app-config.xml的整个配置如下
我用的不是springMVC,而且所有的dao和service都是注解形式,所以不知道在哪里配置OpenSessionInViewInterceptor
和ajax应该没关系,如果你用了url重写,那么在web.xml中 OpenSessionInViewFilter(其它过滤器也是)要放在url重写那个过滤器的前面,过滤器的执行顺序是按你在web.xml里配置的顺序运行的
用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码
我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
我的意思是在control中如果使用了如下的情况,延迟加载是失败的 该如何解决?
control:
login 方法:
1、User user=userservice.findbyNameAndpassword();//此处用事务获取了实体
方法执行完后,事务管理会关闭session
2、紧接着如果再用user.getUserGroup().getRules()则报延迟加载错误的问题了。
所以想把事务加载在control层,该如何操作呢?
用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码
我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
这里是mvc-config.xml的全部配置
这是web.xml的基本配置
很抱歉,由于我的项目里还有很多其它的依赖,又没有用maven做管理,现在放出来可能也无法运行。你可以用svn把spring的的在线例子下载下来看。我的配置大部分是参考里面的 mvc-base 和 mvc-ajax这两个例子,在其基础上增加了spring security和事务管理等
这是spirng samples的 svn地址 https://src.springframework.org/svn/spring-samples/
谢谢提醒,已改正。
那句话的意思是指 如果简单的用<context:component-scan base-package="com">让spring自动扫描注册组件,在注册@Service或@Components时,事务配置还没起作用,这些组件就已经实例化了,最后导致spring的容器中的事务管理无效
IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0
使用 OpenSessionInViewFilter的原因
引用
Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter的主要功能是使每个请求过程绑定一个 Hibernate Session,即使最初的事务已经完成了,也可以在 Web 层进行延迟加载的操作。OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。
在Service层执行插入,删除及数据更新操作时会包以下错误
引用
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition
报错原因:
看过OpenSessionInViewFilter以后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值
解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:通过spring的事务管理Hibernate的sessionFactory,对不同的数据操作作事务的隔离及限制
因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法
spring2.5以后就支持annotation配置了,到了3.0配置更加简化方便了,但对于新手来说,如果不懂具体的spring运作原理,很容易犯错误,并且在报错之后很难发现错误原因。
在此特将spring的配置方法写出来,并经过实例测试,是可以通过并正常运行的。希望对在这方面遇到问题的朋友有帮助,spring的基于annotation请不明白的朋友在网上查看相关文档。
主要配置文件有两个
app-config.xml 配置数据源,hibernate,事务等
mvc-config.xml 配置spring mvc的 controller,viewResolver,messageConvert等
本文主要涉及 app-config.xml的配置
首先通过以下配置,自动扫描com包内作了annotation注解的类,并实例化(至于里面为什么会有个exclude-filter请看文章的后面)
<context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
hibernate及数据源的配置
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <!-- <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop> <prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--> </props> </property> </bean>
配置transactionManager管理事务
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/>
接下来是 自动化事务
<tx:annotation-driven/>
如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
<tx:annotation-driven transaction-manager="txManager"/>
这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
<context:component-scan base-package="com">
因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册
因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下
app-config.xml
<!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
mvc-config.xml(注意里面的注释)
<!-- 扫描com及子包,自动实例化带@controller注释的实例, 由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service --> <context:component-scan base-package="com"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
@Service("articleService") @Transactional public class ArticleService extends GenericService<Article, Long> { @Autowired private ArticleDao articleDao; @Transactional(readOnly=true) public List<Article> getArticles(){ /*...*/ } @Transactional(propagation=Propagation.REQUIRED) public void saveArticle(long id){ /*..*/ } }
更多事务注解的方式请参考spring3.0 reference
这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。
下面通过spring的aop对事务进行自动化管理,配置如下
<!-- 配置aop 切入点 和事务访问策略 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> <tx:advice id="txAdvice" > <tx:attributes> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="create*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >
app-config.xml的整个配置如下
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>/WEB-INF/prop/database.properties</value> </list> </property> </bean> <!-- JNDI DataSource for J2EE environments user c3p0--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"><value>${jdbc.driverClass}</value></property> <property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property> <property name="user"><value>${jdbc.user}</value></property> <property name="password"><value>${jdbc.password}</value></property> <property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property> <property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property> <property name="maxIdleTime"><value>${jdbc.maxIdleTime}</value></property> </bean> <!-- hibernate.hbm2ddl.auto参数说明 validate 加载hibernate时,验证创建数据库表结构 create 每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。 create-drop 加载hibernate时创建,退出是删除表结构 update 加载hibernate自动更新数据库结构 none 不更新数据库结构 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <!-- <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop> <prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--> </props> </property> </bean> <!-- 配置hibernate事务 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/> <!-- 配置aop 切入点 和事务访问策略 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> <tx:advice id="txAdvice" > <tx:attributes> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="create*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 --> <tx:annotation-driven/> <!-- Application Message Bundle --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/messages/messages" /> <property name="cacheSeconds" value="0" /> </bean> <!-- Configures Spring MVC <import resource="mvc-config.xml" /> --> </beans>
评论
22 楼
ichenwenjin
2015-11-07
21 楼
BigBird2012
2015-09-19
我的配置是这样的,我是因为没有加<tx:annotation-driven />抛出的这个异常:
<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byName"> <context:property-placeholder location="classpath*:jdbc.properties" /> <context:component-scan base-package="com.lavasoft.demo.dao" /> <context:component-scan base-package="com.lavasoft.demo.service" /> <context:component-scan base-package="com.lavasoft.demo.web.action" /> <!-- 配置系统的数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- access --> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- pool sizing --> <property name="initialPoolSize" value="3" /> <property name="minPoolSize" value="6" /> <property name="maxPoolSize" value="25" /> <property name="acquireIncrement" value="3" /> <property name="maxStatements" value="0" /> <!-- retries --> <property name="acquireRetryAttempts" value="30" /> <property name="acquireRetryDelay" value="1000" /> <!-- 1s --> <property name="breakAfterAcquireFailure" value="false" /> <!-- refreshing connections --> <property name="maxIdleTime" value="180" /> <!-- 3min --> <property name="maxConnectionAge" value="10" /> <!-- 1h --> <!-- timeouts and testing --> <property name="checkoutTimeout" value="5000" /> <!-- 5s --> <property name="idleConnectionTestPeriod" value="60" /> <!-- 60 --> <property name="testConnectionOnCheckout" value="true" /> <property name="preferredTestQuery" value="SELECT 1" /> <property name="testConnectionOnCheckin" value="true" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> <property name="packagesToScan" value="com.lavasoft.demo.entity" /> </bean> <!-- 设置HibernateDaoSupport抽象类 --> <bean id="hibernateDaoSupport" class="org.springframework.orm.hibernate3.support.HibernateDaoSupport" abstract="true"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 配置aop 切入点 和事务访问策略 --> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.lavasoft.demo.service.*Impl.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /> </aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="select*" read-only="true" /> <tx:method name="get*" read-only="true" /> <tx:method name="load*" read-only="true" /> <tx:method name="find*" read-only="true" /> <tx:method name="query*" read-only="true" /> <tx:method name="read*" read-only="true" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="sync*" /> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" /> </tx:attributes> </tx:advice> <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 --> <tx:annotation-driven /> </beans>
20 楼
snail530
2013-06-19
非常的感谢,通过这篇文章,我把问题解决了!
19 楼
bushkarl
2010-09-10
很棒 , 正在纳闷怎么在spring3mvc 加入opensessioninfilter。哈哈,看了你的文章,我成功了 !
18 楼
mayaprince
2010-09-02
aixinnature 写道
开发环境
IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0
使用 OpenSessionInViewFilter的原因
在Service层执行插入,删除及数据更新操作时会包以下错误
报错原因:
看过OpenSessionInViewFilter以后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值
解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:通过spring的事务管理Hibernate的sessionFactory,对不同的数据操作作事务的隔离及限制
因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法
spring2.5以后就支持annotation配置了,到了3.0配置更加简化方便了,但对于新手来说,如果不懂具体的spring运作原理,很容易犯错误,并且在报错之后很难发现错误原因。
在此特将spring的配置方法写出来,并经过实例测试,是可以通过并正常运行的。希望对在这方面遇到问题的朋友有帮助,spring的基于annotation请不明白的朋友在网上查看相关文档。
主要配置文件有两个
app-config.xml 配置数据源,hibernate,事务等
mvc-config.xml 配置spring mvc的 controller,viewResolver,messageConvert等
本文主要涉及 app-config.xml的配置
首先通过以下配置,自动扫描com包内作了annotation注解的类,并实例化(至于里面为什么会有个exclude-filter请看文章的后面)
hibernate及数据源的配置
配置transactionManager管理事务
接下来是 自动化事务
如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册
因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下
app-config.xml
mvc-config.xml(注意里面的注释)
此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
更多事务注解的方式请参考spring3.0 reference
这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。
下面通过spring的aop对事务进行自动化管理,配置如下
注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >
app-config.xml的整个配置如下
IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0
使用 OpenSessionInViewFilter的原因
引用
Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter的主要功能是使每个请求过程绑定一个 Hibernate Session,即使最初的事务已经完成了,也可以在 Web 层进行延迟加载的操作。OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。
在Service层执行插入,删除及数据更新操作时会包以下错误
引用
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition
报错原因:
看过OpenSessionInViewFilter以后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值
解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:通过spring的事务管理Hibernate的sessionFactory,对不同的数据操作作事务的隔离及限制
因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法
spring2.5以后就支持annotation配置了,到了3.0配置更加简化方便了,但对于新手来说,如果不懂具体的spring运作原理,很容易犯错误,并且在报错之后很难发现错误原因。
在此特将spring的配置方法写出来,并经过实例测试,是可以通过并正常运行的。希望对在这方面遇到问题的朋友有帮助,spring的基于annotation请不明白的朋友在网上查看相关文档。
主要配置文件有两个
app-config.xml 配置数据源,hibernate,事务等
mvc-config.xml 配置spring mvc的 controller,viewResolver,messageConvert等
本文主要涉及 app-config.xml的配置
首先通过以下配置,自动扫描com包内作了annotation注解的类,并实例化(至于里面为什么会有个exclude-filter请看文章的后面)
<context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
hibernate及数据源的配置
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <!-- <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop> <prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--> </props> </property> </bean>
配置transactionManager管理事务
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/>
接下来是 自动化事务
<tx:annotation-driven/>
如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
<tx:annotation-driven transaction-manager="txManager"/>
这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
<context:component-scan base-package="com">
因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册
因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下
app-config.xml
<!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
mvc-config.xml(注意里面的注释)
<!-- 扫描com及子包,自动实例化带@controller注释的实例, 由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service --> <context:component-scan base-package="com"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
@Service("articleService") @Transactional public class ArticleService extends GenericService<Article, Long> { @Autowired private ArticleDao articleDao; @Transactional(readOnly=true) public List<Article> getArticles(){ /*...*/ } @Transactional(propagation=Propagation.REQUIRED) public void saveArticle(long id){ /*..*/ } }
更多事务注解的方式请参考spring3.0 reference
这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。
下面通过spring的aop对事务进行自动化管理,配置如下
<!-- 配置aop 切入点 和事务访问策略 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> <tx:advice id="txAdvice" > <tx:attributes> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="create*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >
app-config.xml的整个配置如下
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 --> <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>/WEB-INF/prop/database.properties</value> </list> </property> </bean> <!-- JNDI DataSource for J2EE environments user c3p0--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"><value>${jdbc.driverClass}</value></property> <property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property> <property name="user"><value>${jdbc.user}</value></property> <property name="password"><value>${jdbc.password}</value></property> <property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property> <property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property> <property name="maxIdleTime"><value>${jdbc.maxIdleTime}</value></property> </bean> <!-- hibernate.hbm2ddl.auto参数说明 validate 加载hibernate时,验证创建数据库表结构 create 每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。 create-drop 加载hibernate时创建,退出是删除表结构 update 加载hibernate自动更新数据库结构 none 不更新数据库结构 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com"/> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--> <!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.use_sql_comments">true</prop> <!-- <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop> <prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--> </props> </property> </bean> <!-- 配置hibernate事务 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" autowire="byName"/> <!-- 配置aop 切入点 和事务访问策略 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> <tx:advice id="txAdvice" > <tx:attributes> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="create*" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 --> <tx:annotation-driven/> <!-- Application Message Bundle --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/messages/messages" /> <property name="cacheSeconds" value="0" /> </bean> <!-- Configures Spring MVC <import resource="mvc-config.xml" /> --> </beans>
17 楼
IcedCoffee
2010-08-17
qq528 写道
<mvc:interceptors>
<!-- 解决延迟加载问题 -->
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<!-- 解决增、删、改操作时提示没有权限的问题 -->
<property name="flushMode" value="1"/>
</bean>
</mvc:interceptors>
<!-- 解决延迟加载问题 -->
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<!-- 解决增、删、改操作时提示没有权限的问题 -->
<property name="flushMode" value="1"/>
</bean>
</mvc:interceptors>
我用的不是springMVC,而且所有的dao和service都是注解形式,所以不知道在哪里配置OpenSessionInViewInterceptor
16 楼
qq528
2010-08-17
<mvc:interceptors>
<!-- 解决延迟加载问题 -->
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<!-- 解决增、删、改操作时提示没有权限的问题 -->
<property name="flushMode" value="1"/>
</bean>
</mvc:interceptors>
<!-- 解决延迟加载问题 -->
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<!-- 解决增、删、改操作时提示没有权限的问题 -->
<property name="flushMode" value="1"/>
</bean>
</mvc:interceptors>
15 楼
IcedCoffee
2010-08-17
而且由于dao和service用的都是注解,openSessionInViewInterceptor也不会配置。。。
14 楼
IcedCoffee
2010-08-17
这个问题困扰我很久了..
目前我的项目里暂时用的是
this.getHibernateTemplate().initialize(role.getApplications());
这样写,但是总是用的很不舒服..
目前我的项目里暂时用的是
this.getHibernateTemplate().initialize(role.getApplications());
这样写,但是总是用的很不舒服..
13 楼
IcedCoffee
2010-08-17
<div class="quote_title">aixinnature 写道</div>
<div class="quote_div">
<div class="quote_title">IcedCoffee 写道</div>
<div class="quote_div">OpenSessionInViewFilter配置后不起作用是为什么? <br>我前台用的全部是ajax请求,是不是和这个有关系呢?</div>
<br><br>和ajax应该没关系,如果你用了url重写,那么在web.xml中 OpenSessionInViewFilter(其它过滤器也是)要放在url重写那个过滤器的前面,过滤器的执行顺序是按你在web.xml里配置的顺序运行的 <br>
</div>
<p><br>我的web.xml:</p>
<p> </p>
<pre name="code" class="xml"><?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>ceoms_v3</display-name>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<description>
Used to cleanup when a session is destroyed</description>
<display-name>ZK Session cleaner</display-name>
<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>
<servlet>
<description>
The ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<description>
The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.zul</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.zul</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.zul</location>
</error-page>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml;</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>proxool</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>proxool</servlet-name>
<url-pattern>/proxool</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app></pre>
<p> </p>
<p>我已经放在最前面了..还是不行...</p>
<div class="quote_div">
<div class="quote_title">IcedCoffee 写道</div>
<div class="quote_div">OpenSessionInViewFilter配置后不起作用是为什么? <br>我前台用的全部是ajax请求,是不是和这个有关系呢?</div>
<br><br>和ajax应该没关系,如果你用了url重写,那么在web.xml中 OpenSessionInViewFilter(其它过滤器也是)要放在url重写那个过滤器的前面,过滤器的执行顺序是按你在web.xml里配置的顺序运行的 <br>
</div>
<p><br>我的web.xml:</p>
<p> </p>
<pre name="code" class="xml"><?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>ceoms_v3</display-name>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<description>
Used to cleanup when a session is destroyed</description>
<display-name>ZK Session cleaner</display-name>
<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>
<servlet>
<description>
The ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<description>
The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.zul</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404.zul</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.zul</location>
</error-page>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml;</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>proxool</servlet-name>
<servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>proxool</servlet-name>
<url-pattern>/proxool</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app></pre>
<p> </p>
<p>我已经放在最前面了..还是不行...</p>
12 楼
aixinnature
2010-08-17
IcedCoffee 写道
OpenSessionInViewFilter配置后不起作用是为什么?
我前台用的全部是ajax请求,是不是和这个有关系呢?
我前台用的全部是ajax请求,是不是和这个有关系呢?
和ajax应该没关系,如果你用了url重写,那么在web.xml中 OpenSessionInViewFilter(其它过滤器也是)要放在url重写那个过滤器的前面,过滤器的执行顺序是按你在web.xml里配置的顺序运行的
11 楼
IcedCoffee
2010-08-17
OpenSessionInViewFilter配置后不起作用是为什么?
我前台用的全部是ajax请求,是不是和这个有关系呢?
我前台用的全部是ajax请求,是不是和这个有关系呢?
10 楼
qiren83
2010-08-16
挺不错的
周末也弄了一个 spring3+jpa2.0(hibernate3.3)+springmvc+lucene3 的demo
还没弄完 确实和s2.5 还有JPA1有区别
周末也弄了一个 spring3+jpa2.0(hibernate3.3)+springmvc+lucene3 的demo
还没弄完 确实和s2.5 还有JPA1有区别
9 楼
former
2010-08-16
<p>qq528 写道</p>
<div class="quote_div">事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?如果将事务边界在control层,这个配置该如何呢?</div>
<p> </p>
<p> </p>
<p>事务控制放在service层,是为了对我们的业务做完善的事务控制,前提是你的业务逻辑都在service中实现。如果这样的话,不需要在controller层配置事务。另外,为了解决延迟加载的问题,你将事务控制放在controller层中也不起作用,原因有2:</p>
<ol>
<li>延迟加载时在spring mvc渲染view的时候产生的,你的controller代码还没开始渲染。</li>
<li>延迟加载的目的主要是读,而一般需要控制事务的时候主要是保证业务的提交或回滚,所以为了延迟加载而将事务的控制放在controller层也不合适。</li>
</ol>
<p>另外,可以考虑用OpenSessionInViewInterceptor替换OpenSessionInViewFilter。性能应该好一些的。</p>
<div class="quote_div">事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?如果将事务边界在control层,这个配置该如何呢?</div>
<p> </p>
<p> </p>
<p>事务控制放在service层,是为了对我们的业务做完善的事务控制,前提是你的业务逻辑都在service中实现。如果这样的话,不需要在controller层配置事务。另外,为了解决延迟加载的问题,你将事务控制放在controller层中也不起作用,原因有2:</p>
<ol>
<li>延迟加载时在spring mvc渲染view的时候产生的,你的controller代码还没开始渲染。</li>
<li>延迟加载的目的主要是读,而一般需要控制事务的时候主要是保证业务的提交或回滚,所以为了延迟加载而将事务的控制放在controller层也不合适。</li>
</ol>
<p>另外,可以考虑用OpenSessionInViewInterceptor替换OpenSessionInViewFilter。性能应该好一些的。</p>
8 楼
qq528
2010-08-16
aixinnature 写道
qq528 写道
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?
如果将事务边界在control层,这个配置该如何呢?
用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码
<ul> <c:forEach var="article" items="${group.articles}"> <li>${article.title}</li> </c:forEach> </ul>
我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
我的意思是在control中如果使用了如下的情况,延迟加载是失败的 该如何解决?
control:
login 方法:
1、User user=userservice.findbyNameAndpassword();//此处用事务获取了实体
方法执行完后,事务管理会关闭session
2、紧接着如果再用user.getUserGroup().getRules()则报延迟加载错误的问题了。
所以想把事务加载在control层,该如何操作呢?
7 楼
aixinnature
2010-08-16
qq528 写道
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?
如果将事务边界在control层,这个配置该如何呢?
用OpenSessionInViewFilter就是为了解决延迟加载session不同步的问题,我测试了延迟加载,是可以顺利在jsp页面调用的
这是jsp页面里的测试代码
<ul> <c:forEach var="article" items="${group.articles}"> <li>${article.title}</li> </c:forEach> </ul>
我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
6 楼
aixinnature
2010-08-16
qq528 写道
楼主,能否把mvc-config.xml也完整发出来看看呢?或者有个完整的例子那是最好了 谢谢哈
这里是mvc-config.xml的全部配置
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="stringHttpMessageConverter"/> <ref bean="jacksonMessageConverter"/> </list> </property> <property name="webBindingInitializer"> <bean class="com.common.web.BaseBindingInitializer" /> </property> </bean> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/> <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/> <!-- Configures the @Controller programming model --> <mvc:annotation-driven/> <!-- 扫描com及子包,自动实例化带@controller注释的实例, 由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service --> <context:component-scan base-package="com"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- Forwards requests to the "/" resource to the "welcome" view --> <mvc:view-controller path="/" view-name="welcome"/> <!-- Configures Handler Interceptors --> <mvc:interceptors> <!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de --> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> </mvc:interceptors> <!-- Saves a locale change using a cookie --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" /> <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
这是web.xml的基本配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>spring-security-base</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/security.xml /WEB-INF/spring/app-config.xml </param-value> </context-param> <!-- spring security 过滤器链 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Reads request input using UTF-8 encoding --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- for restful style 注意要放在 characterEncodingFilter 否则可能引起不必要的乱码--> <filter> <filter-name>httpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>httpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--OpenSessionInViewFilter 作用,防止hibernate lazy-load 引起的不在同一session的报错 --> <filter> <filter-name>hibernateFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Enables clean URLs with JSP views e.g. /welcome instead of /app/welcome 注意: 过滤器执行顺序是按web.xml中的各过滤器的位置顺序执行的 将其它过滤器放在此过滤器的前面,否则由于url重写,会导致其它过滤器过滤的url失效 --> <filter> <filter-name>UrlRewriteFilter</filter-name> <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> <!-- <init-param> <param-name>logLevel</param-name> <param-value>DEBUG</param-value> </init-param> --> </filter> <filter-mapping> <filter-name>UrlRewriteFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Handles all requests into the application --> <servlet> <servlet-name>springMVCBase</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/mvc-config.xml </param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVCBase</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> </web-app>
很抱歉,由于我的项目里还有很多其它的依赖,又没有用maven做管理,现在放出来可能也无法运行。你可以用svn把spring的的在线例子下载下来看。我的配置大部分是参考里面的 mvc-base 和 mvc-ajax这两个例子,在其基础上增加了spring security和事务管理等
这是spirng samples的 svn地址 https://src.springframework.org/svn/spring-samples/
5 楼
qq528
2010-08-16
事务控制在service边界 即使用了hibernateinview,一对多的加载总是出现懒加载的问题 请问楼主是如何解决的?
如果将事务边界在control层,这个配置该如何呢?
如果将事务边界在control层,这个配置该如何呢?
4 楼
qq528
2010-08-16
楼主,能否把mvc-config.xml也完整发出来看看呢?或者有个完整的例子那是最好了 谢谢哈
3 楼
aixinnature
2010-08-16
daquan198163 写道
最关键的一段话存在语病和错别字:
看不懂。
引用
web 容器在扫描包含@Service或@Components的类并包含@Transaction是,此时@Transaction并为完成,导致事务未被注册。
因此需要把@Controller和其它的@Service,@components,@Reposity等标签分开实例化,controller放到最后实例化,app-config.xml和mvc-config.xml的配置分别入戏
因此需要把@Controller和其它的@Service,@components,@Reposity等标签分开实例化,controller放到最后实例化,app-config.xml和mvc-config.xml的配置分别入戏
看不懂。
谢谢提醒,已改正。
那句话的意思是指 如果简单的用<context:component-scan base-package="com">让spring自动扫描注册组件,在注册@Service或@Components时,事务配置还没起作用,这些组件就已经实例化了,最后导致spring的容器中的事务管理无效
相关推荐
### Struts2.1 + Spring3.0 + Hibernate3.3 整合实践 #### 一、项目背景与概述 在Java Web开发中,Struts2、Spring与Hibernate是三个非常重要的框架,它们分别用于处理MVC架构中的表示层、业务逻辑层与数据访问层...
OpenSessionInViewFilter是Spring框架中一个非常重要的组件,主要用于解决数据访问层(DAO)与视图层(View)之间的事务管理问题。在Web应用中,由于HTTP请求的无状态性,一次请求通常由多个Servlet过滤器、控制器和...
OpenSessionInViewFilter个人学习总结
Spring框架还提供了一系列的过滤器来处理Web应用中的请求,例如OpenSessionInViewFilter用于解决Hibernate懒加载问题。 - **OpenSessionInViewFilter**:此过滤器在请求处理开始时打开一个Hibernate会话,在请求...
我们可以通过配置XML文件和注解来实现整合,并使用opensessionInviewfilter来解决会话问题。 Spring JDBC面向接口编程 本节讲解了如何使用Spring JDBC来实现面向接口编程。我们可以通过配置XML文件和注解来实现DAO...
4. 解决OpenSessionInView问题,可以使用OpenSessionInViewFilter或OpenSessionInViewInterceptor,确保在一次HTTP请求中保持Hibernate Session的开放状态,以解决懒加载异常。 Spring的事务管理分为编程式和声明式...
通过在web.xml中配置`OpenSessionInViewFilter`,可以实现持久化层的事务与视图渲染的无缝结合,提高应用性能。 ##### 2. **Struts-config.xml与Spring集成** 当Spring与Struts框架集成时,可以通过`...
在处理Web应用时,Spring提供了一些关键特性,如`CharacterEncodingFilter`和`OpenSessionInViewFilter`,它们对于解决特定问题至关重要。 首先,让我们深入了解一下`CharacterEncodingFilter`。在Web应用中,字符...
当遇到OpenSessionInView问题时,可以使用OpenSessionInViewFilter或OpenSessionInViewInterceptor来解决。 Spring的事务管理提供了强大且灵活的机制,主要包括编程式和声明式两种方式: 1. 编程式事务管理:通过...
- 在`web.xml`中配置`OpenSessionInViewFilter`过滤器,自动管理事务。 #### 三、总结 通过以上步骤,我们不仅可以让Spring有效地管理Struts,实现更灵活的业务逻辑控制,还可以利用Spring的强大功能管理...
- 利用CharacterEncodingFilter和OpenSessionInViewFilter解决编码问题。 通过以上内容的学习,开发者可以深入理解Spring 2.5的核心概念,掌握其在实际开发中的应用,从而提高工作效率和代码质量。
该模式的核心在于通过Spring提供的`OpenSessionInViewFilter`过滤器,在视图渲染过程中保持Hibernate Session的打开状态,从而简化了事务管理,并避免了一些常见的懒加载异常。 #### 一、OpenSessionInViewFilter...
- 修改Struts配置:将Action的类型改为DelegatingActionProxy,这是Spring Struts集成的关键,使得Action实例由Spring管理。 - 配置web.xml:设置ContextLoaderListener监听器,加载Spring的bean工厂,并在web应用...
解决这个问题的方法有两种:一种是在 web.xml 中使用 Spring 提供的 OpenSessionInViewFilter,另一种是在 application.xml 中配置 OpenSessionInViewFilter。前者通用,后者只能用于 SpringMVC 结构中。 最后,...
涉及到了多个知识点,包括 Spring 配置、Hibernate 配置、Struts2 配置、ConnectionPool 配置、数据库配置、事务管理、OpenSessionInViewFilter 配置、web.xml 配置、依赖注入、Struts2 和 Spring 整合、Hibernate ...
本文将深入探讨Spring面试中常见的知识点,包括Spring的优点、DI(Dependency Injection)的实现方式、IOC(Inversion of Control)的理解、Spring对ORM框架如Hibernate的支持,以及Spring的事务管理。 首先,...
同时,需要在Spring的配置文件(如applicationContext.xml)中定义Action及DAO实例,并指定相应的依赖注入。 3. Hibernate的配置文件(hibernate.cfg.xml)中,配置数据库连接、实体类映射等信息。Spring的配置文件...