内容源自:Spring中如何使用事务?

一、为什么要使用事务?

如果我们一个业务逻辑只执行一次sql,是不需要使用事务的。但如果要执行多条sql语句才能完成一个业务逻辑的话,这个时候就要使用事务了。 因为这几条sql可能有的执行成功,有的执行失败。 而事务就是对一组sql语句进行统一的提交或回滚操作,为了保证数据执行的一致性,这组sql不是全部成功就是全部失败。

举个例子吧: 
我们要实现转账的功能。首先要在账户a中扣100元,然后在账户b中加100元,这里涉及两次sql操作。大概像下面代码这样操作:

boolean flag1 = accountDao.minus(map)==1;
            if(flag1){
                // 减成功
                map.put("toAccount", toAccount);
                boolean flag2 = accountDao.plus(map)==1;
                if(flag2){
                    // 加成功
                    return true;
                }else{
                    /** 加失败 [减生效了] 回滚
                     *  为这个转账的过程添加事务控制
                    // 自定义异常
                    throw new PayException();
                }
            }else{
                // 减失败
                return false;
            }

如果账户a减钱成功,账户b加钱失败(比如账户输入错误,数据库中没有这个账户,sql执行失败), 这里显然要把a账户减的钱还回来。即回滚。所以在这里需要添加事务控制。

二.如何在spring中添加事务

  • spring中的事务 作为 局部事务 , 配置方式依赖于持久层使用的技术

spring整合jdbc 
spring整合hibernate

  • spring中即提供了编程式事务的管理方式,也提供了声明式事务的管理方式:

编程式事务 TransactionTemplate

模板类 将事务的管理过程封装模板类中】

声明式事务 AOP
提供根接口 PlatFormTransactionManager 事务管理器接口 
用于描述spring中事务如何管理[如何创建、如何提交、如何回滚] 】

  • 声明式事务

底层采用AOP技术实现,将事务管理过程(创建、提交、回滚)封装在一个事务通知bean[AfterAdvice ThrowsAdvice]中; 
通过在ioc容器中配置切入点的方式,将这个事务通知bean提供的事务管理功能引用给需要事务的核心业务逻辑方法(DAO)

在容器中添加配置如下:(这里orm用的mybatis) 
applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <context:component-scan base-package="com"/>

    <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/etoak"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="ds"></property>
        <property name="mapperLocations">
            <list>
                <value>classpath:com/etoak/dao/AccountDaoIf-mapper.xml</value>
            </list>
        </property>
    </bean>

    <bean id="accountDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="sqlSessionFactory" ref="ssf"></property>
        <property name="mapperInterface" value="com.etoak.dao.AccountDaoIf"></property>
    </bean>

    <!--
        配置声明式事务!
        1 aop命名空间、schema文件
          tx命名空间、schame文件(用于提供声明式事务的支持)
        2 配置事务通知bean [Advice]
        [before after around throws]
            管理事务的使用方式[创建、提交、回滚]
        transaction-manager: 设置事务管理器
        事务管理器 PlatFormTransactionManager
                - DataSourceTransactionManager
     -->
    <tx:advice id="tran" transaction-manager="tm">
        <tx:attributes>
            <!--
                tx:method 为不同类型的方法添加不同的事务属性
             -->
            <tx:method name="pay"
                isolation="DEFAULT"
                propagation="REQUIRED"
                read-only="false"
                timeout="-1"
                rollback-for="com.etoak.util.PayException"/>
            <tx:method name="add*"/>
            <tx:method name="del*"/>
            <tx:method name="sel*" read-only="true"/>
            <tx:method name="update*" timeout="10"/>
        </tx:attributes>
    </tx:advice>

    <!--
        配置事务管理器bean
     -->
    <bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="ds"></property>
    </bean>

    <!--
        3 配置切入点
            描述需要将通知[tran]提供的功能[事务管理功能]引用给哪个/哪些方法
     -->
    <aop:config>
        <aop:pointcut
            expression="execution(* com.etoak.service.*.*(..))"
            id="pc"/>
        <aop:advisor advice-ref="tran" pointcut-ref="pc"/>
    </aop:config>
</beans>

配置好了,还要写一个异常类,在需要事务管理的地方抛出自己定义的异常,从而启用事务。

public class PayException extends Exception{
    @Override
    public String getMessage() {
        return "减操作成功,加操作失败,失败原因:没有这个账户.转账失败,我要回滚";
    }
}

在web.xml中添加异常页面配置:

  <error-page>
    <exception-type>com.etoak.util.PayException</exception-type>
    <location>/error.jsp</location>
  </error-page>

方法里面添加事务管理:

public class PayService {

    @Autowired
    private AccountDaoIf accountDao;

    // 提供转账服务
    public boolean pay(String fromAccount , String toAccount , Double money)throws Exception{

        // 调用DAO
        double yue = accountDao.查询余额(fromAccount);
        if(yue>=money){
            Map map = new HashMap();
            map.put("fromAccount", fromAccount);
            map.put("money" , money);
            boolean flag1 = accountDao.minus(map)==1;
            if(flag1){
                // 减成功
                map.put("toAccount", toAccount);
                boolean flag2 = accountDao.plus(map)==1;
                if(flag2){
                    // 加成功
                    return true;
                }else{
                    /** 加失败 [减生效了] 回滚
                     *  为这个转账的过程添加事务控制
                     *  添加声明式事务
                     *  以AOP的方式进行添加
                     *  将事务的管理过程封装在一个事务通知bean
                     *  以配置、引用的方式将事务通知bean添加给需要事务的方法
                     *  切入点指向的是哪 : 服务层中Service对象提供的pay()
                     *
                     *  声明式事务回滚的方式:检测到异常时
                     */
                    // 自定义异常
                    throw new PayException();
                }
            }else{
                // 减失败
                return false;
            }
        }else{
            return false;
        }
    }
}

Spring框架学习(10)Spring中如何使用事务?的更多相关文章

  1. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

  2. Spring框架学习02——Spring IOC 详解

    1.Spring IOC的基本概念 IOC(Inverse of Control)反转控制的概念,就是将原本在程序中手动创建对象的控制权,交由Spring框架管理.当某个Java对象(调用者)需要调用 ...

  3. Spring框架学习03——Spring Bean 的详解

    1.Bean 的配置 Spring可以看做一个大型工厂,用于生产和管理Spring容器中的Bean,Spring框架支持XML和Properties两种格式的配置文件,在实际开发中常用XML格式的配置 ...

  4. Spring 框架学习(1)--Spring、Spring MVC扫盲

    纸上得来终觉浅,绝知此事要躬行 文章大纲 什么是spring 传统Java web应用架构 更强的Java Web应用架构--MVC框架 Spring--粘合式框架 spring的内涵 spring核 ...

  5. Spring框架学习10——JDBC Template 实现数据库操作

    为了简化持久化操作,Spring在JDBC API之上提供了JDBC Template组件. 1.添加依赖 添加Spring核心依赖,MySQL驱动 <!--Spring核心基础依赖--> ...

  6. Spring框架学习1

    AnonymouL 兴之所至,心之所安;尽其在我,顺其自然 新随笔 管理   Spring框架学习(一)   阅读目录 一. spring概述 核心容器: Spring 上下文: Spring AOP ...

  7. Spring框架学习之IOC(二)

    Spring框架学习之IOC(二) 接着上一篇的内容,下面开始IOC基于注解装配相关的内容 在 classpath 中扫描组件 <context:component-scan> 特定组件包 ...

  8. Spring框架学习笔记(5)——Spring Boot创建与使用

    Spring Boot可以更为方便地搭建一个Web系统,之后服务器上部署也较为方便 创建Spring boot项目 1. 使用IDEA创建项目 2. 修改groupid和artifact 3. 一路n ...

  9. Spring框架学习一

    Spring框架学习,转自http://blog.csdn.net/lishuangzhe7047/article/details/20740209 Spring框架学习(一) 1.什么是Spring ...

  10. spring框架学习(三)junit单元测试

    spring框架学习(三)junit单元测试 单元测试不是头一次听说了,但只是听说从来没有用过.一个模块怎么测试呢,是不是得专门为一单元写一个测试程序,然后将测试单元代码拿过来测试? 我是这么想的.学 ...

随机推荐

  1. 关于k8s里的service互访,有说法

    昨天,测试了一个项目的接入.明白了以下几个坑: 1,traefik有可能有性能问题,如果daemonset安装,可重建.也需要通过8580端口查看性能. 2,集群中的service访问自己时,好像性能 ...

  2. Android点击图标重新启动问题

    原文:http://blog.csdn.net/jianiuqi/article/details/54091181 项目中的小问题:发现应用打包安装后按home键切换到后台后,点击应用图标又重新打开了 ...

  3. EL表达式无法显示Model中的数据

    后台程序通过Debug都能正常返回数据并封装到Model中.而在前台通过EL表达式取值时却是原样输出,如${cart.num}... ///展现我的购物车 @RequestMapping(" ...

  4. Linux NFS服务器的简明配置6.8

    Linux NFS服务器的简明配置6.8   Linux NFS服务器的简明配置 一.NFS服务简介 NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的 ...

  5. Project interpreter not specified(eclipse+pydev) (转)

    [小记] 最近因为想配置Android的开发环境,把原来的MyEclipse5.5删了,下载了最新的Eclipse3.7版本,因为之前在进行Python开 发,就下载了最新的Pydev2.4版本,安装 ...

  6. shell脚本报错退出

    在shell脚本中,比如有以下的代码: cd /root/test88 rm -rf  backup 如果目录/root/test88不存在,脚本不会停止,依然会执行rm -rf backup这个命令 ...

  7. 初见Python<3>:字符串

    1.格式化字符串 %s代表的是格式化字符串,或者说为字符串进行占位操作. 如果一个变量本身不是字符串,则会自动被转化为字符串. 使用%f格式化浮点数.同时也可以提供需要的精度,如%.3f,即保留3位小 ...

  8. noip 2016 day2 t1组合数问题

    题目描述 组合数表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们可以给出计算 ...

  9. JZYZOJ1527 [haoi2012]高速公路 线段树 期望

    http://172.20.6.3/Problem_Show.asp?id=1527 日常线段树的pushdown写挂,果然每次写都想得不全面,以后要注意啊……求期望部分也不熟练,和平均数搞混也是or ...

  10. STL的常用用法、函数汇总(不定时更新)

    隶书文字为原创. 1.vector 在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结. 1 基本操作 (1)头文件#include<vector>. (2)创建vec ...