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块但 ...
随机推荐
- SourceInsight中文字体
转载自: http://blog.chinaunix.net/uid-29094179-id-3889999.html 1.正确显示中文注释 1)Options->Style Propertie ...
- Photoshop的版本体系
Photoshop CS6 和Photoshop CC的区别 没有什么玄乎的,仅仅是版本不一样. 版本的命名 Photoshop CS6 是CS系列的最后一版本, Adobe Photoshop CS ...
- 未能加载文件或程序集“file:///D:/Program Files (x86)/ArcGIS/DeveloperKit10.0/DotNet/ESRI.ArcGIS.3DAnalyst.dll”或它的某一个依赖项。试图加载格式不正确的程序。 行 129,位置 5。
能加载文件或程序集“file:///C:/Program Files (x86)/ArcGIS/DeveloperKit10.0/DotNet/ESRI.ArcGIS.ADF.Local.dll”或它 ...
- UIView独占响应事件
exclusiveTouch A Boolean value that indicates whether the receiver handles touch events exclusively. ...
- 集成SVN源码管理和Mantis缺陷跟踪
集成SVN源码管理和Mantis缺陷跟踪 (windows) 要集成Mantis和SVN,需要几个工具:SVN客户端,TortoiseSVN,下载地址: http://tortoisesvn.net/ ...
- Android API 中文(14) —— ViewStub
前言 关键字: android.view.ViewStub,版本为Android 2.2 r1 本章翻译来自唐明 ,这里本博负责整理和发布,欢迎其他译者一起参与Android API 的中文翻译行动, ...
- 如何修改容器内的/etc/resolv.conf
源由不表,暂且略过. 直接说workaround. 因为openshift的模式,/etc/resolv.conf是在pod生成的时候插入的,写入的是宿主机的ip作为dns的寻址,如果需要修改的化,需 ...
- django cookie and session
cookie和session 1.cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生. cookie的工作 ...
- TensorFlow目标检测(object_detection)api使用
https://github.com/tensorflow/models/tree/master/research/object_detection 深度学习目标检测模型全面综述:Faster R-C ...
- Echarts动画效果:实现数据左右移动
1.业务背景 图形实时从后台获取数据,让图形从最右边出现,每隔一秒向左移一位,当最左边的数据移到Y轴时,最左边的数据移出屏幕,最右边增加一个数.实现一个从右往左动画的效果 2.先看下项目中的demo解 ...