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块但 ...
随机推荐
- 第十章 OPENWRT安装nohup,因为不明原因nohup没有安装
Available pacaagess里找了coreutils-nohup包,安装好就行了 运行nohup自己的程序的时候可能会出现一下: root@OpenWrt:~# nohup: ignorin ...
- SPSS Clementine 数据挖掘入门3
转摘:http://www.cnblogs.com/dekevin/archive/2012/04/27/2473683.html 了解SPSS Clementine的基本应用后,再对比微软的SSAS ...
- 使用CadLib实现CAD(dxf、dwg格式)文件的读取和显示 【转】
参考文章:CadLib 3.5 documentationhttps://www.woutware.com/doc/cadlib3.5/Index.aspx 读取:定义DxfModel类型的变量mod ...
- 主题 Theme 小结
主题的使用 默认创建的Android工程中,在AndroidManifest.xml文件中有<application android:theme="@style/AppTheme&qu ...
- html表格内容自动换行
有时候表格会因为内容多少忽大忽小的很烦人,在网上搜了下解决方案,效果不错哦,给大家分享下!首先介绍两个利器:table-layout:fixed //固定表格大小word-break:break-al ...
- DevExpressComponents-14.2.5 破解过程,正在编写,未完
首先,批评一下cnblogs,在win10的环境下,需要加入到兼容视图列表方可正常编辑内容, 声明,本人在14.2.3 的源代码环境下,编译未通过,相关功能报错,索性选择破解,在此,只是学习测试使用, ...
- CKEditor与CKFinder学习--CKFinder源代码改动自己定义上传文件名称
CKFinder的系列文章到眼下应该说基本能够满足开发需求了,只是另一个小细节,CKFinder默认上传的文件名称和源文件名称一致,假设文件名称反复会自己主动加入编号"(1)"&q ...
- 阿里云服务器 centos7 ftp安装
昨天租了阿里云服务器一个月,想玩一下linux系统,结果想用ftp上传本地文件的时候,发现用不了,结果在安装配置的时候折腾了几个小时,在网上查了无数的资料,有的说要改配置文件,有的说要关防火墙,说啥的 ...
- webpack 编译图片文件 file-loader
1.安装插件 npm i file-loader --save-dev npm i url-loader --save-dev npm install image-webpack-loader - ...
- 数据库选型之MySQL(固态硬盘)
刘勇 Email: lyssym@sina.com 本博客记录作者在工作与研究中所经历的点滴,一方面给自己的工作与生活留下印记,另一方面若是能对大家有所帮助,则幸甚至哉矣! 简介 鉴于高频中心库 ...