springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息
一、知识点及问题
后端框架:
Spring 、Spring mvc 、mybatis
业务需求:
client先从服务端获取用户大量信息到client,编辑完毕之后统一Post至服务端,对于数据的改动要么全成功,要么全失败,所以须要使用事务支持。
问题:
配置Spring声明式事务,运行中出现异常未回滚.从网上查询得到一開始是自己的配置出了问题,因为配置文件的载入顺序决定了容器的载入顺序导致Spring事务没有起作用。
详情例如以下:
因为採用的是SpringMVC、 MyBatis,故统一採用了标注来声明Service、Controller
因为server启动时的载入配置文件的顺序为web.xml—root-context.xml(Spring的配置文件)—servlet-context.xml(SpringMVC的配置文件)。因为root-context.xml配置文件里Controller会先进行扫描装配。可是此时service还没有进行事务增强处理,得到的将是原样的Service(没有经过事务加强处理,故而没有事务处理能力)。所以我们必须在root-context.xml中不扫描Controller
上面的问题解决后还是没有回滚,后来了解到,Spring 仅仅会在程序运行中出现unchecked(RuntimeException)的异常时才会触发回滚。因为是与client直接交互的Server所以要将每个处理结果以 errorcode 错误码和msg 错误信息的形式反馈给client所以显式捕捉了全部的异常,并将信息以Json数据格式发送给client这才导致了出现异常时事务没有回滚。
因为要给client最真实、准确的错误信息反馈又不得不捕捉可能发生的异常又陷入了沉思.当然,问题总是有解决的方式的,哪怕是绕着走。
之后从查询资料得到,捕捉能够,可是捕捉之后主动抛出还是会引发事务回滚的!(喜)然后就想到在主动 throw new RuntimeException(“反馈给client的信息”);将要反馈给client的详细错误信息包装到异常信息中,发生异常时在Controller层catch异常,将信息返回至client。
(mysql 表的engine为InnoDB–支持事务回滚,默觉得MyISAM–效率高)
到此,问题解决。
二、案例声明
岗位: Java服务端
工作内容: 接收来自client的请求(android,androidtv,ios,pc ..),对client请求数据做合法性校验,并与其它服务端交互获取client所需数据。
三、代码及配置
1.web.xml配置
<?xml version="1.0" encoding="UTF-8"?
>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
2. Spring-servlet.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/aop
http://www.springframework.org/schema/aop/spring-aop-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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 配置注解扫描,扫描 Controller层不扫描Service层 -->
<context:component-scan base-package="cn.com.XX">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Service" />
</context:component-scan>
</beans>
3. mybatis-config.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- changes from the defaults for testing -->
<setting name="cacheEnabled" value="true" />
<setting name="useGeneratedKeys" value="true" />
<setting name="defaultExecutorType" value="REUSE" />
<!-- <setting name="logImpl" value="LOG4J"/> -->
</settings>
<!-- mybatis分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql" />
</plugin>
</plugins>
</configuration>
4. applicationContext.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:p="http://www.springframework.org/schema/p"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<!--载入配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:system.properties" />
</bean>
<!--配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver">
</property>
<property name="jdbcUrl"
value="${数据库连接}">
</property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<!--连接池中保留的最大连接数。
Default: 15 -->
<property name="maxPoolSize" value="15"></property>
<!--连接池中保留的最小连接数。 -->
<property name="minPoolSize" value="3"></property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize" value="3"></property>
<!--最大空暇时间,20秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="20"></property>
<!--当连接池中的连接耗尽的时候c3p0一次同一时候获取的连接数。Default: 3 -->
<property name="acquireIncrement">
<value>5</value>
</property>
<!-- JDBC的标准參数,用以控制数据源内载入的PreparedStatements数量。
但因为预缓存的statements 属于单个connection而不是整个连接池。所以设置这个參数须要考虑到多方面的因素。
假设maxStatements与maxStatementsPerConnection均为0。则缓存被关闭。
Default: 0 -->
<property name="maxStatements">
<value>0</value>
</property>
<!--每60秒检查全部连接池中的空暇连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>60</value>
</property>
<!--定义在从数据库获取新连接失败后反复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!-- 获取连接失败将会引起全部等待连接池来获取连接的线程抛出异常。可是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。假设设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
<property name="breakAfterAcquireFailure">
<value>true</value>
</property>
<!-- 因性能消耗大请仅仅在须要的时候使用它。
假设设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接測试的性能。
Default: false -->
<property name="testConnectionOnCheckout">
<value>true</value>
</property>
</bean>
<!-- 注解扫描,不扫描Controller层 -->
<context:component-scan base-package="cn.com.xx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="mapperLocations" value="classpath:cn/com/xx/**/*.xml" />
</bean>
<!-- yxt add -->
<bean id="mapperScanneryxt" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.com.xx.mapper" />
</bean>
<!--配置事务管理器 -->
<!-- transaction manager, use DataSourceTransactionManager -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 切面 -->
<aop:config>
<aop:pointcut id="fooServiceMethods"
expression="execution(* cn.com.xx.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods" />
</aop:config>
<!--通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="select*" read-only="true" />
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
</beans>
5. 代码演示样例
Service业务逻辑处理层
try {
log.info("check phone is exist before ..");
int count = tMailingMapper.insert(record);
if (count > 0) {
log.info("加入 " + accountid + " 的好友"
+ account.getAccountid() + " "
+ phoneVo.getRemark() + " 成功");
} else {
log.info("加入 " + accountid + " 的好友"
+ account.getAccountid() + " "
+ phoneVo.getRemark() + " 失败");
}
} catch (Exception e) {
log.error("加入联系人出现了异常 " + e.getMessage());
resJson.put("errorcode", "20022");
resJson.put("msg", "同步信息异常,请稍后重试");
throw new RuntimeException(resJson.toString());
}
Controller 控制层
@RequestMapping("/update/userinfo")
public String updateUserInfo(HttpServletRequest request, HttpServletResponse response) {
log.info("update userInfo start ..");
String resText=null;
try {
resText = userService.updateUserInfo(request);
} catch (Exception e) {
log.error("更新信息失败,事务已回滚...",e);
resText=e.getMessage();
}
<-- 将操作结果返回给client-->
HttpsUtil.sendAppMessage(resText, response);
return null;
}
本人初入Java,小白一枚,有不到之处还请见谅。
欢迎大神指点!
2016-03-19 10:58:58
參考文章:1. http://sence-qi.iteye.com/blog/1328902/
2.http://blog.sina.com.cn/s/blog_89ca421401016bmg.html
springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息的更多相关文章
- springmvc的声明式事务管理类型讲解
以方法为单位,进行事务控制:抛出异常,事务回滚. 最小的执行单位为方法.决定执行成败是通过是否抛出异常来判断的,抛出异常即执行失败 中文名 声明式事务 外文名 declarative tran ...
- 零基础学习java------39---------json格式交互,Restful(不懂),静态资源映射,SSM整合(ssm整合思想,application.xml文件详解(声明式事务管理),)
一. json格式交互(知道) 1 . 回顾ajax基本语法 $.ajax({ url:"", // 请求的后台路径 data:{"":"" ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...
- spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)
1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...
- spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)
原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...
- 【Spring】Spring的事务管理 - 2、声明式事务管理(实现基于XML、Annotation的方式。)
声明式事务管理 文章目录 声明式事务管理 基于XML方式的声明式事务 基于Annotation方式的声明式事务 简单记录 - 简单记录-Java EE企业级应用开发教程(Spring+Spring M ...
- Spring声明式事务管理
一.Spring 的声明式事务管理概述 1.Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法 ...
- 全面分析 Spring 的编程式事务管理及声明式事务管理
开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...
- spring 声明式事务管理
简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...
随机推荐
- 总结学习 Python 的 14 张思维导图汇总
- python -m xxx.py和python xxx.py的区别
先看下python -m site作用是显示sys.path的值内容,也就是python搜索模块的目录,作用类似于linux下的PATH python -m SimpleHTTPServer 会在sy ...
- UVA 11107(Life Forms-后缀数组+二分)
Problem C: Life Forms You may have wondered why most extraterrestrial life forms resemble humans, di ...
- calibre,完成对各种格式的电子书籍的管理和格式转换及同步
Calibre是免费的电子书制作.阅读软件,源代码开放,拥有跨平台的设计,支持多个基于不同系统的便携式移动设备,包括苹果iPhone.Amazon电子书等设备.它是一个完整的电子图书馆,包括图书馆管理 ...
- 对于Ian的访谈,不少关于GAN的内容
文章链接如下: http://3g.163.com/dy/article/DD1GBSLF0511ABV6.html 里面提到胶囊网络,我找了这篇文章看了下: https://blog.csdn.ne ...
- go语言基础之闭包的特点
所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量.这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量.它不关心这些捕获了的变量和常量是否已经超出了作用域, ...
- 小议使用“完整”的CSS的缺点
1.浏览器支持的不一致性 浏览器的漏洞或缺乏支持的CSS功能,导致不同的浏览器显示出不同的CSS版面编排.例如在微软Internet Explorer6.0的旧版本 ,执行了许多自己的CSS2.0属性 ...
- css3动画属性系列之transform细讲旋转rotate
1.语法: transform: none | <transform-function> [<transform-function>]* 2.取值: none ...
- .net维护的一些心得
做了三个月的.net的开发,其实一直在做一个维护加二次开发的工作.现在这个项目告一段落,就此总结下我的所学所感吧.总的来说,.net和JAVA还是有许多地方是不同的,比如.net中的数据绑定问题,已经 ...
- echarts使用技巧(一)echarts的图表自适应resize问题、单选、缩放等
这些东西要是有精力和时间可以通读echarts文档,里面都有配置详细介绍.该博客只是把自己使用echarts遇到的问题记录下,并不全,加深印象,抛砖引玉而已,完整学习的请移步官方文档 1.legend ...