[Spring+SpringMVC+Mybatis]框架学习笔记(六):事务
第7章 事务
7.1 事务的概念
事务是一系列作为一个逻辑单元来执行的操作集合。
它是数据库维护数据一致性的单位,它讲数据库从一个一致状态,转变为新的另外一个一致状态。说的简单一点就是:如果一组处理步骤要么全部成功,要么全部失败,这样就保证了数据始终一致的状态。
维护了数据的完整和可靠性。
7.2 jdbc处理事务的逻辑

7.3 事务的属性
事务的4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性。
- 原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的所有操作要么都做,要么都不做。
- 一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
- 隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,
并发执行的各个事务之间不能互相干扰。 - 持久性(durability):持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
7.4 事务的传播特性
事务的传播特性指处于不同事物的方法在相互调用时,执行期间事务的维护情况。
一般有两种方式:
- PROPAGATION_REQUIRED :如果存在一个事务,则支持当前事务,如果没有事务则开启
- PROPAGATION_REQUIRED_NEW :总是开启一个新事务
7.5 事务管理的类型
事务管理分为两种类型,分为编程式事务和声明式事务。
- 编程式事务
编程式事务管理可以清楚的定义事务的边界
可以实现细粒度的事务控制,开发者可以通过程序代码来控制你的事务何时开始,何时结束,类似于7.2节实例
但是事务的控制与业务代码耦合在一起,不能共用 ,而且开发效率低,不便于维护 - 声明式事务
声明式事务可以结合spring AOP的概念,只需要通过配置在指定的方法中加入事务控制.
如果需要修改或者删除事务,移除配置即可,解除了系统服务(事务)与业务代码的耦合,而且方便管理
在实际开发中,一般提倡用声明式事务管理
7.6 spring与事务的关系
1、事务原本是数据库中的概念,是在dao层。
但是一般情况下,我们会把事务管理提升到我们的业务层(service),这是为了更好的是用事务来管理我们的业务逻辑。
2、spring并不直接管理事务,而是提供了多种事务管理器。
根据不同的数据应用方式,(jdbc(自定义封装的jdbc,jdbctemplate,mybatis)/hibernate)提供了对应的事务管理器:
jdbc: DataSourceTransactionManagerhibenate: HibernateTranactionManager
所有的事务管理器实现了一个共同的接口:org.springframework.transaction.PlatformTransactionManager
它提供了三个方法:
commit/rollback/getTransaction(TransactionDefinition(用来定义事务的一系列属性))
7.7 Spring实现事务的三种方式
- 基于xml配置
- 注解
- aspectJ
7.8 实例:模拟转账
下面先建表、写Dao层、Service层;本例数据库连接采用c3p0的方式(使用jdbc.properties)。


1、Dao层接口
package com.steven.spring.sysmgr.dao;
public interface IAccountDao {
/**
* 往某个账户转入金额
* @param account 转入账户姓名
* @param money 转入金额
* @return
*/
public boolean addAccountMoney(String account, double money);
/**
* 在某个账户转出金额
* @param account 转出账户姓名
* @param money 转出金额
* @return
*/
public boolean subAccountMoney(String account, double money);
}
2、Dao接口实现类
package com.steven.spring.sysmgr.dao.impl;
import org.springframework.jdbc.core.JdbcTemplate;
import com.steven.spring.sysmgr.dao.IAccountDao;
public class AccountDao implements IAccountDao{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public boolean addAccountMoney(String account, double money) {
boolean updateFlag = false;
String sql = "UPDATE M_ACCOUNT SET AC_MONEY = AC_MONEY + ? WHERE AC_NAME = ?";
int rows = this.jdbcTemplate.update(sql, money, account);
if(rows > 0) updateFlag = true;
return updateFlag;
}
@Override
public boolean subAccountMoney(String account, double money) {
boolean updateFlag = false;
String sql = "UPDATE M_ACCOUNT SET AC_MONEY = AC_MONEY - ? WHERE AC_NAME = ?";
int rows = this.jdbcTemplate.update(sql, money, account);
if(rows > 0) updateFlag = true;
return updateFlag;
}
}
3、服务类接口
package com.steven.spring.sysmgr.service;
/**
* 对外提供转账服务的接口
* @author chenyang
*
*/
public interface IAccountService {
/**
* 从一个账户转账到另外一个账户
* @param fromAccount 转出账户
* @param toAccount 转入账户
* @param money 转账金额
* @return
*/
public boolean operateAccount(String fromAccount, String toAccount, double money);
}
4、服务类实现
package com.steven.spring.sysmgr.service.impl;
import com.steven.spring.sysmgr.dao.IAccountDao;
import com.steven.spring.sysmgr.service.IAccountService;
public class AccountService implements IAccountService{
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public boolean operateAccount(String fromAccount, String toAccount, double money) {
boolean operateFlag = false;
System.out.println("-------转账开始--------");
//转账一般是先减后加
boolean toFlag = accountDao.subAccountMoney(toAccount, money);
System.out.println("转账金额:" + money);
//模拟故障
int i = 1 / 0;
boolean fromFlag = accountDao.addAccountMoney(fromAccount, money);
if(toFlag && fromFlag) operateFlag = true;
System.out.println("-------转账结束--------");
return operateFlag;
}
}
7.8.1 spring基于xml配置实现事务
1、环境搭建:引入jar,引入aop约束
aopalliance-1.0.jar
spring-aop-4.2.1.RELEASE.jar
spring-tx.jar
2、配置事务
1)配置文件applicationContext-SpringXml.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册服务类,并描述依赖关系 -->
<bean id="accountService" class="com.steven.spring.sysmgr.service.impl.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 注册DAO类 -->
<bean id="accountDao" class="com.steven.spring.sysmgr.dao.impl.AccountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注册springJdbc查询模板,模板依赖于数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<!-- 注册spring自带的管理数据库连接的数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 注册事务管理器 -->
<bean id="txMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注册事务代理 -->
<bean id="transProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txMgr"/>
<property name="target" ref="accountService"/>
<property name="transactionAttributes">
<props>
<prop key="oper*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>

2)测试
package com.steven.spring.sysmgr.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.steven.spring.sysmgr.service.IAccountService;
public class AccountWithTransUsingSpringXml {
private ApplicationContext ac;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext-SpringXml.xml");
}
//模拟增加功能
@Test
public void testOperateAccount(){
//注意这里为代理对象的bean的id
IAccountService accountService = (IAccountService) ac.getBean("transProxy");
accountService.operateAccount("Mike", "Tom", 100);
}
}
3)测试结果
程序报错回滚,账目金额不变,达到目的。
7.8.2 spring注解方式实现事务
在第7.8.1基础上引入tx约束。
详见 applicationContext-annotation.xml和AccountWithTransAnnoTest.Java。
1)配置文件applicationContext-SpringAnnotation.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 注册服务类,并描述依赖关系 -->
<bean id="accountService" class="com.steven.spring.sysmgr.service.impl.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 注册DAO类 -->
<bean id="accountDao" class="com.steven.spring.sysmgr.dao.impl.AccountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注册springJdbc查询模板,模板依赖于数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<!-- 注册spring自带的管理数据库连接的数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 注册事务管理器 -->
<bean id="txMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务的注解驱动 -->
<tx:annotation-driven transaction-manager="txMgx"/>
</beans>
2)在目标类的目标方法上插入注解
package com.steven.spring.sysmgr.service.impl;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.steven.spring.sysmgr.dao.IAccountDao;
import com.steven.spring.sysmgr.service.IAccountService;
public class AccountService implements IAccountService{
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public boolean operateAccount(String fromAccount, String toAccount, double money) {
boolean operateFlag = false;
System.out.println("-------转账开始--------");
boolean toFlag = accountDao.subAccountMoney(toAccount, money);
System.out.println("转账金额:" + money);
//模拟故障
int i = 1 / 0;
boolean fromFlag = accountDao.addAccountMoney(fromAccount, money);
if(toFlag && fromFlag) operateFlag = true;
System.out.println("-------转账结束--------");
return operateFlag;
}
}
3)测试
package com.steven.spring.sysmgr.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.steven.spring.sysmgr.service.IAccountService;
public class AccountWithTransUsingSpringAnnotation {
private ApplicationContext ac;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext-SpringAnnotation.xml");
}
//模拟增加功能
@Test
public void testOperateAccount(){
//注意这里为目标对象的bean的id,与xml的方式不同
IAccountService accountService = (IAccountService) ac.getBean("accountService");
accountService.operateAccount("Mike", "Tom", 100);
}
}
7.8.3 spring AspectJ实现事务
在7.8.1的基础上引入AspectJ的相关jar包。
1)配置文件applicationContext-AspectJXml.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 注册服务类,并描述依赖关系 -->
<bean id="accountService" class="com.steven.spring.sysmgr.service.impl.AccountService">
<property name="accountDao" ref="accountDao"/>
</bean>
<!-- 注册DAO类 -->
<bean id="accountDao" class="com.steven.spring.sysmgr.dao.impl.AccountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注册springJdbc查询模板,模板依赖于数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<!-- 注册spring自带的管理数据库连接的数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 注册事务管理器 -->
<bean id="txMgr" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注册通知-->
<tx:advice id="txAdvice" transaction-manager="txMgr">
<tx:attributes>
<tx:method name="oper*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop:切入点表达式,加入通知 -->
<aop:config>
<aop:pointcut expression="execution(* *..AccountService.*(..))" id="accountPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="accountPointCut"/>
</aop:config>
</beans>
ps: 上面的切入点表达式可灵活处理。
2)测试
package com.steven.spring.sysmgr.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.steven.spring.sysmgr.service.IAccountService;
public class AccountWithTransUsingAspectJ {
private ApplicationContext ac;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext-AspectJXml.xml");
}
//模拟增加功能
@Test
public void testOperateAccount(){
IAccountService accountService = (IAccountService) ac.getBean("accountService");
accountService.operateAccount("Mike", "Tom", 100);
}
}
[Spring+SpringMVC+Mybatis]框架学习笔记(六):事务的更多相关文章
- Spring+SpringMVC+MyBatis集成学习笔记【一】
一,首先要清楚,SpringMVC其实就是Spring的一个组件 例如我们知道Spring中有类似于,AOP TX等等类似的组件,所以SpringMVC其实就是Spring的一个组件,是S ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...
- Spring+SpringMVC+MyBatis深入学习及搭建(六)——MyBatis关联查询
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6923464.html 前面有将到:Spring+SpringMVC+MyBatis深入学习及搭建(五)--动 ...
- Spring+SpringMVC+MyBatis深入学习及搭建(三)——MyBatis全局配置文件解析
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6874672.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(二)——My ...
- Spring+SpringMVC+MyBatis深入学习及搭建(八)——MyBatis查询缓存
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6956206.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(七)——My ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十七)——SpringMVC拦截器
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7098753.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十六)--S ...
- SSM(Spring+SpringMVC+Mybatis)框架环境搭建(整合步骤)(一)
1. 前言 最近在写毕设过程中,重新梳理了一遍SSM框架,特此记录一下. 附上源码:https://gitee.com/niceyoo/jeenotes-ssm 2. 概述 在写代码之前我们先了解一下 ...
- Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6869133.html 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)——My ...
- Spring+SpringMVC+MyBatis深入学习及搭建(七)——MyBatis延迟加载
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6953005.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(六)——My ...
随机推荐
- List.Sort() 小小技巧--- 从大到小排列
List.sort() 默认的情况下是从小到大的排列. 例如: List<int> list = new List<int>(); list.Add(- ...
- 什么是OTC?
OTC(Over The Counter)非处方药物,我国卫生部医政司是这样定义的:它是消费者可不经过医生处方,直接从药房或药店购买的药品,而且是不在医疗专业人员指导下就能安全使用的药品,即不需要凭借 ...
- 为什么360、百度、腾讯出的Mac端云盘客户端都只有同步盘?(用户量小,同步盘开发成本低,Linux下都没有客户端)
如题,顾名思义,同步盘是用来同步的,不具备增量的功能,像这三家在Windows端出的客户端都是即有同步也有增量的. 陆续出来的,可能大家更多的是跟随策略,不得不提dropbox是这样的形式.mac电脑 ...
- QQ邮箱打败163邮箱的过程(重视用户体验的结果)
引用 楼主 CKAOS 的回复: 目前负责一个项目,ASP.NET的,做一个网盘系统,别的都弄好了,只差一个下载文件夹的功能未实现,只能在服务器端打包成压缩文件,再发回浏览器.如何直接下载文件夹,不是 ...
- QT编译./configure参数的详细解释
可以随便的转载,只要按照规矩走带上咱论坛的链接就好. ======================================全文是按照./configure -help来翻译的========= ...
- 解决C/C++程序执行一闪而过的方法(使用getchar,或者cin.get,不推荐system(“pause”))
简述 在VS编写控制台程序的时候,包括使用其他IDE(Visual C++)编写C/C++程序,经常会看到程序的执行结果一闪而过,要解决这个问题,可以在代码的最后加上system(“pause”).g ...
- Win7和Vista的安全机制对于应用程序读取配置文件相关操作的影响(虚拟重定向技术)
今天构造了一个新版本的XXXX软件,并且在纯净的系统下进行了较为全面的测试.测试中也发现了一些问题.其中包括在Win7测试时程序竟然在另一个目录中创建了文件夹和配置文件,并且进行相关读取操作,却并没有 ...
- 基于QT的在线打字练习软件助手(C/S模型)good
简介 通过基于QT中QTcpServer和QTcpSocket以及UI编程,实现了基于TCP协议的C/S模型在线打字练习软件助手,服务端处理各客户端打字数据,以及显示在线打字客户列表即实时更新打字 ...
- shell多线程(2)之基于管道实现并发
在shell脚本里批量执行程序是比较常见的方式,如果程序很多,每个执行时间比较长,则顺序执行需要花费大量的时间. 此时并发就成为我们考虑的方向. 上篇<shell多线程>中我们已经简单实现 ...
- spring 5.x 系列第1篇 —— springmvc基础 (xml配置方式)
文章目录 一.搭建hello spring工程 1.1 项目搭建 1.2 相关配置讲解 二.配置自定义拦截器 三.全局异常处理 四.参数绑定 4.1 参数绑定 4.2 关于日期格式转换的三种方法 五. ...