一、知识点及问题

后端框架:

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回滚)捕捉异常,传输错误信息的更多相关文章

  1. springmvc的声明式事务管理类型讲解

    以方法为单位,进行事务控制:抛出异常,事务回滚.   最小的执行单位为方法.决定执行成败是通过是否抛出异常来判断的,抛出异常即执行失败   中文名 声明式事务 外文名 declarative tran ...

  2. 零基础学习java------39---------json格式交互,Restful(不懂),静态资源映射,SSM整合(ssm整合思想,application.xml文件详解(声明式事务管理),)

    一. json格式交互(知道) 1 . 回顾ajax基本语法 $.ajax({ url:"", // 请求的后台路径 data:{"":"" ...

  3. spring事物配置,声明式事务管理和基于@Transactional注解的使用

    http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...

  4. spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)

    1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...

  5. spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)

    原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...

  6. 【Spring】Spring的事务管理 - 2、声明式事务管理(实现基于XML、Annotation的方式。)

    声明式事务管理 文章目录 声明式事务管理 基于XML方式的声明式事务 基于Annotation方式的声明式事务 简单记录 - 简单记录-Java EE企业级应用开发教程(Spring+Spring M ...

  7. Spring声明式事务管理

    一.Spring 的声明式事务管理概述 1.Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法 ...

  8. 全面分析 Spring 的编程式事务管理及声明式事务管理

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  9. spring 声明式事务管理

    简单理解事务: 比如你去ATM机取5000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉5000元钱:然后ATM出5000元钱.这两个步骤必须是要么都执行要么都不执行.如果银行卡扣除了5000块但 ...

随机推荐

  1. SourceInsight中文字体

    转载自: http://blog.chinaunix.net/uid-29094179-id-3889999.html 1.正确显示中文注释 1)Options->Style Propertie ...

  2. Photoshop的版本体系

    Photoshop CS6 和Photoshop CC的区别 没有什么玄乎的,仅仅是版本不一样. 版本的命名 Photoshop CS6 是CS系列的最后一版本, Adobe Photoshop CS ...

  3. 未能加载文件或程序集“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”或它 ...

  4. UIView独占响应事件

    exclusiveTouch A Boolean value that indicates whether the receiver handles touch events exclusively. ...

  5. 集成SVN源码管理和Mantis缺陷跟踪

    集成SVN源码管理和Mantis缺陷跟踪 (windows) 要集成Mantis和SVN,需要几个工具:SVN客户端,TortoiseSVN,下载地址: http://tortoisesvn.net/ ...

  6. Android API 中文(14) —— ViewStub

    前言 关键字: android.view.ViewStub,版本为Android 2.2 r1 本章翻译来自唐明 ,这里本博负责整理和发布,欢迎其他译者一起参与Android API 的中文翻译行动, ...

  7. 如何修改容器内的/etc/resolv.conf

    源由不表,暂且略过. 直接说workaround. 因为openshift的模式,/etc/resolv.conf是在pod生成的时候插入的,写入的是宿主机的ip作为dns的寻址,如果需要修改的化,需 ...

  8. django cookie and session

    cookie和session 1.cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生. cookie的工作 ...

  9. TensorFlow目标检测(object_detection)api使用

    https://github.com/tensorflow/models/tree/master/research/object_detection 深度学习目标检测模型全面综述:Faster R-C ...

  10. Echarts动画效果:实现数据左右移动

    1.业务背景 图形实时从后台获取数据,让图形从最右边出现,每隔一秒向左移一位,当最左边的数据移到Y轴时,最左边的数据移出屏幕,最右边增加一个数.实现一个从右往左动画的效果 2.先看下项目中的demo解 ...