- 浏览: 3514193 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (1491)
- Hibernate (28)
- spring (37)
- struts2 (19)
- jsp (12)
- servlet (2)
- mysql (24)
- tomcat (3)
- weblogic (1)
- ajax (36)
- jquery (47)
- html (43)
- JS (32)
- ibatis (0)
- DWR (3)
- EXTJS (43)
- Linux (15)
- Maven (3)
- python (8)
- 其他 (8)
- JAVASE (6)
- java javase string (0)
- JAVA 语法 (3)
- juddiv3 (15)
- Mule (1)
- jquery easyui (2)
- mule esb (1)
- java (644)
- log4j (4)
- weka (12)
- android (257)
- web services (4)
- PHP (1)
- 算法 (18)
- 数据结构 算法 (7)
- 数据挖掘 (4)
- 期刊 (6)
- 面试 (5)
- C++ (1)
- 论文 (10)
- 工作 (1)
- 数据结构 (6)
- JAVA配置 (1)
- JAVA垃圾回收 (2)
- SVM (13)
- web st (1)
- jvm (7)
- weka libsvm (1)
- weka屈伟 (1)
- job (2)
- 排序 算法 面试 (3)
- spss (2)
- 搜索引擎 (6)
- java 爬虫 (6)
- 分布式 (1)
- data ming (1)
- eclipse (6)
- 正则表达式 (1)
- 分词器 (2)
- 张孝祥 (1)
- solr (3)
- nutch (1)
- 爬虫 (4)
- lucene (3)
- 狗日的腾讯 (1)
- 我的收藏网址 (13)
- 网络 (1)
- java 数据结构 (22)
- ACM (7)
- jboss (0)
- 大纸 (10)
- maven2 (0)
- elipse (0)
- SVN使用 (2)
- office (1)
- .net (14)
- extjs4 (2)
- zhaopin (0)
- C (2)
- spring mvc (5)
- JPA (9)
- iphone (3)
- css (3)
- 前端框架 (2)
- jui (1)
- dwz (1)
- joomla (1)
- im (1)
- web (2)
- 1 (0)
- 移动UI (1)
- java (1)
- jsoup (1)
- 管理模板 (2)
- javajava (1)
- kali (7)
- 单片机 (1)
- 嵌入式 (1)
- mybatis (2)
- layui (7)
- asp (12)
- asp.net (1)
- sql (1)
- c# (4)
- andorid (1)
- 地价 (1)
- yihuo (1)
- oracle (1)
最新评论
-
endual:
https://blog.csdn.net/chenxbxh2 ...
IE6 bug -
ice86rain:
你好,ES跑起来了吗?我的在tomcat启动时卡在这里Hibe ...
ES架构技术介绍 -
TopLongMan:
...
java public ,protect,friendly,private的方法权限(转) -
贝塔ZQ:
java实现操作word中的表格内容,用插件实现的话,可以试试 ...
java 读取 doc poi读取word中的表格(转) -
ysj570440569:
Maven多模块spring + springMVC + JP ...
Spring+SpringMVC+JPA
如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信息,这些操作通过调用一个服务类的方法来执行,这个方法也在spring事务管理拦截器的管理之下,那么这个记录方法需要在另一个事务中进行,而不是与被拦截方法在同一个事务中,不然如果被拦截方法抛出异常需要回滚时,所作的记录也会被回滚,当然有时候确实需要同时回滚,那就要放在同一个事务中。
这和自己的拦截器和事务管理的拦截器的执行顺序有一定关系,spring事务管理拦截器是一个环绕通知,在被拦截方法执行前启动事务,执行后完成事务,如果自己的拦截器被spring事务管理拦截器包围在里面,那么在自己的拦截器运行时,spring已经启动了一个事务,如果你的记录信息方法需要与被拦截方法同在一个事务中,将你的记录信息方法的事务传播属性设为默认的REQUIRED就可以了;
如果你记录信息的方法需要单独的一个事务环境,那就要把事务传播属性设为REQUIRES_NEW了,这样spring事务管理器会新建一个事务,并且新建一个session连接,因为一个数据库连接不可能同时有两个事务,记录信息完了提交事务并且把新建的session连接关闭,自己的拦截器退出后继续执行被拦截的方法或它的事务处理。
相反如果自己的拦截器在spring事务管理拦截器的外面,那么记录信息的方法会在一个单独的事务中执行,并提交,不管它的事务传播属性是 REQUIRES_NEW还是REQUIRED,因为与被拦截方法的事务处理没有交叉,并且可以使用同一个session连接如果是 OpenSessionInViewFilter。
所以如果记录信息和被拦截方法要在不同事务中执行,分别提交,那么最好将自己的拦截器
设在spring事务管理器拦截器的外面;如果需要将记录信息和被拦截方法在同一个事务中处理,必须将自己的拦截器被包围在spring事务管理拦截器中,并且记录信息方法的事务传播属性为默认的 REQUIRED。
设置拦截器的执行顺序可以让拦截器处理类实现org.springframework.core.Ordered接口,在spring配置文件的 AOP设置中设定自己的拦截器和spring事务管理拦截器的执行顺序,将自己的拦截的序号排在spring事务管理的前面,就可以将该拦截器放到事务管理拦截器的外面执行了,对于before通知方式会先于事务管理拦截器执行,对于after returning和after和after throwing通知方式会后于事务管理拦截器的执行,对于arount通知方式会包围事务管理拦截器执行。
下面是一个异常拦截器的例子。
有位朋友提到在spring异常拦截器中更新数据不能够提交,做了一下测试,测试环境基本是这样:一个用户登录的功能,spring对 service中的每个方法进行事务管理,在用户检测的service方法上同时加上一个异常拦截器,当用户不存在或密码不正确时用户检测方法会抛出异常,异常拦截器捕获到该异常,同时记录一些日志。
spring配置文件相关:
Java代码 收藏代码
1. <span style="font-size: medium;"> <!-- 事务管理 -->
2. <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
3. <property name="sessionFactory" ref="sessionFactory"></property>
4. </bean>
5.
6. <!-- 事务通知 -->
7. <tx:advice id="txAdvice" transaction-manager="transactionManager">
8. <tx:attributes>
9. <tx:method name="get*" read-only="true"/>
10. <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/>
11. </tx:attributes>
12. </tx:advice>
13.
14. <!-- aop代理设置 -->
15. <aop:config proxy-target-class="true">
16. <aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/>
17. <aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/>
18. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/>
19. <aop:aspect id="logAspect" ref="logInterceptor" order="2" >
20. <aop:after-throwing
21. pointcut-ref="logPointcut"
22. method="serviceIntercept" />
23. </aop:aspect>
24. </aop:config>
25.
26. <!-- log拦截器类 -->
27. <bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor">
28. <property name="service" ref="logService"></property>
29. </bean> </span>
<!-- 事务管理 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!-- aop代理设置 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/>
<aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/>
<aop:aspect id="logAspect" ref="logInterceptor" order="2" >
<aop:after-throwing
pointcut-ref="logPointcut"
method="serviceIntercept" />
</aop:aspect>
</aop:config>
<!-- log拦截器类 -->
<bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor">
<property name="service" ref="logService"></property>
</bean>
拦截器类:
Java代码 收藏代码
1. <span style="font-size: medium;">public class EventLogInterceptor implements Ordered {
2.
3. private int order = 1;
4.
5. private EventLogService service;
6.
7. public Object serviceIntercept(ProceedingJoinPoint point) throws Throwable{
8. if(point instanceof MethodInvocationProceedingJoinPoint){
9. MethodInvocationProceedingJoinPoint mpoint = (MethodInvocationProceedingJoinPoint)point;
10. //
11. }
12. try {
13. System.out.println("记录日志开始");
14. service.eventLog();
15. System.out.println("记录日志结束");
16. }catch(Exception ex) {
17. ex.printStackTrace();
18. }
19. return null;
20. }
21.
22. public void setOrder(int order){
23. this.order = order;
24. }
25. public int getOrder() {
26. return order;
27. }
28. public EventLogService getService() {
29. return service;
30. }
31. public void setService(EventLogService service) {
32. this.service = service;
33. }
34. }
35. </span>
public class EventLogInterceptor implements Ordered {
private int order = 1;
private EventLogService service;
public Object serviceIntercept(ProceedingJoinPoint point) throws Throwable{
if(point instanceof MethodInvocationProceedingJoinPoint){
MethodInvocationProceedingJoinPoint mpoint = (MethodInvocationProceedingJoinPoint)point;
//
}
try {
System.out.println("记录日志开始");
service.eventLog();
System.out.println("记录日志结束");
}catch(Exception ex) {
ex.printStackTrace();
}
return null;
}
public void setOrder(int order){
this.order = order;
}
public int getOrder() {
return order;
}
public EventLogService getService() {
return service;
}
public void setService(EventLogService service) {
this.service = service;
}
}
service方法中的事务传播属性都设为要求新建事务,spring事务管理切面拦截器的order设为1,而log拦截器的order设为2,这意味着这两个要同时执行时,先执行事务拦截器,后执行log拦截器,由于事务管理是一个环绕通知(around),实际上是log拦截器被包围在事务管理拦截器中。
从中可以看出,log异常拦截器在用户登录的事务回滚之前截获异常,在记录日志时,日志记录的service方法也在spring的事务管理之下,用户登录的事务还没有结束,根据REQUIRES_NEW特性,spring会新开一个事务,这时原来的数据库连接已经在一个事务中,一个连接不可能同时有两个事务,所以同时新创建一个session连接(虽然我使用了OpenSessionInViewFilter,并且session是单例的),日志记录就在新建的事务和session中进行,完了提交,并且会把新建的session连接关闭。
然后继续进行被中断的用户登录的事务管理操作,由于抛异常spring将用户登录的事务回滚。
这样能够实现预想的功能,但是如果我去掉指定的REQUIRES_NEW,那么log记录的操作会继续在用户登录的事务中进行,最后会被一起回滚。
如果把事务管理的order设为2,log拦截器的order设为1,也就是log拦截器在事务管理拦截器的外面,会在事务管理拦截器前后执行完了再执行log的异常拦截器。
可以看出,用户登录的事务和日志记录的事务是前后两个不相关的事务,并且在日志记录事务中并不需要新建session连接,而是直接用在 OpenSessionInViewFilter中创建的session。实际上这时也并不需要将propagation设为REQUIRES_NEW,使用默认的REQUIRES也照样能够正常工作。
所以应该将该异常拦截器设在事务管理拦截器的外面,即使用Order接口排在前面。
(本文章转载来自http://endual.iteye.com/admin/blogs/new)。博客作者改编了题目
发表评论
-
spring mvc 文件上传
2015-12-16 15:56 1003http://cmao.iteye.com/blog/2264 ... -
spring mvc 控制文件大小
2015-03-08 23:49 1159http://19950603.blog.51cto.com/ ... -
spring data jpa 分页
2014-08-28 23:27 13446public Page<Task> getUser ... -
spring mvc maven 视频
2013-10-17 03:24 1236http://www.verycd.com/topics/29 ... -
pom 创库
2013-09-20 01:13 12771, spring 和hibernate要哪些包,这个要LZ ... -
服务器推送技术可以看看
2013-09-17 16:38 742activeMq或者comet4j试试 -
spring mvc jpa 引入包中的实体类
2013-09-16 16:22 2996http://www.iteye.com/topic ... -
spring mvc 定时器
2013-09-11 15:44 1170http://fhqllt.iteye.com/blog/43 ... -
spring mvc 作业调度
2013-09-11 15:42 1077http://tonyaction.blog.51cto.co ... -
spring mvc 发生邮件
2013-09-11 15:38 1144http://blog.csdn.net/geloin/art ... -
spring mvc 文件的上传和下载
2013-09-11 15:32 1391http://blog.csdn.net/yiyuhanmen ... -
Spring JPA 无法扫描多JAR包中@Entity类的有关问题
2013-08-26 23:20 2530Spring JPA 无法扫描多JAR包中@Entity ... -
Spring+SpringMVC+JPA
2013-08-21 16:17 27736SpringMVC是越来越火,自己也弄一个Spring+ ... -
spring mvc 权限管理项目 shiro
2013-08-20 23:37 1413https://github.com/ketayao -
spring mvc 整合shiro
2013-08-20 23:13 1256http://www.th7.cn/Program/java/ ... -
spring data jpa 和spring mvc
2013-08-20 22:10 1362http://www.cnblogs.com/luxh/arc ... -
spring mvc 乱码
2013-08-20 12:19 1268因为使用spring mvc的时候,已经在web.xml中设 ... -
Spring3.2.2_自动装配
2013-08-16 08:57 1865Spring3.2.2_自动装配 ... -
Spring 3 MVC: Tiles Plugin Tutorial With Example In Eclipse By Viral Patel on Ju
2013-08-14 17:24 2532Spring 3 MVC: Tiles Plugin T ... -
spring data jpa 采用内存数据库
2013-08-13 15:43 2948# The default database is H2 me ...
相关推荐
spring aop切面拦截指定类和方法实现流程日志跟踪 一般情况下,在不侵入业务代码的情况下,需要做流程日志跟踪是比较合理的 采用springaop切面思想
Spring Mvc AOP通过注解方式拦截controller等实现日志管理
内含有mybatis 拦截器实现的分页代码,spring 的事务和aop 测试、和反射工具类
springaop拦截controller日志
Spring AOP配置事务方法,描述了spring的事务配置,方便开发应用和数据库的连接管理。
死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序
项目中含有一整个springboot实现aop的功能,在拦截的方法形式上有两种一种是通过切点设置为拦截某个包路径下面的类中的所有方法;还有一种是基于某个自定义注解的.
SpringAOP的日志拦截示例, 包含配置和代码
spring aop 拦截 实例spring aop 拦截 实例spring aop 拦截 实例
spring aop做的日志管理,网上看的,没测试过。
spring aop 拦截实例,下载下来直接就可以用了,很好很方便。
Spring AOP 拦截器 Advisor Spring AOP 拦截器 Advisor
spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop
Spring AOP 日志管理 实例LoggingThrowsAdvice.java
SpringAOP原理及拦截器.pdf
SpringAOP原理及拦截器.docx
SpringAOP原理及拦截器.doc
spring aop jar 包
springboot spring aop 拦截器 注解方式实现脱敏(涉及到:pom.xml -->application.properties --->启动类-->拦截器)
演示了spring基于AOP代理TransactionProxyFactoryBean实现事务