Spring事务管理之几种方式实现事务(转)
一:事务认识
大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销。Spring事务管理基于底层数据库本身的事务处理机制。数据库事务的基础,是掌握Spring事务管理的基础。这篇总结下Spring事务。
事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。
(1)原子性(Atomicity)
事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性(Consistency)
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
(3)隔离性(Isolation)
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
(4)持久性(Durability)
指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
二:事务的传播机制
详情看这个: 事务的传播机制
三:数据库的4种隔离级别
详情看这个: 数据库的4种隔离级别
提示:
spring的事务传播行为是:REQUIRED
mysql的默认的事务处理级别是:REPEATABLE-READ, 也就是可重复读
Oracle的默认的事务处理级别是:READ COMMITTED, 也就是读已提交
可以通过更改数据库的默认事务处理级别
四:事务几种实现方式 (编程式事务管理、编程式事务管理)
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务
注:此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。
五:举例说明事务不同实现
/**
* 账户对象
*
*/
public class Account { private int accountid;
private String name;
private String balance; public int getAccountid() {
return accountid;
}
public void setAccountid(int accountid) {
this.accountid = accountid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
}
/**
* 股票对象
*
*/
public class Stock { private int stockid;
private String name;
private Integer count; public Stock() {
super();
} public Stock(int stockid, String name, Integer count) {
super();
this.stockid = stockid;
this.name = name;
this.count = count;
} public int getStockid() {
return stockid;
} public void setStockid(int stockid) {
this.stockid = stockid;
} public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
} }
DAO层
public interface AccountDao { void addAccount(String name,double money); void updateAccount(String name,double money,boolean isbuy); }
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override
public void addAccount(String name, double money) {
String sql = "insert account(name,balance) values(?,?);";
this.getJdbcTemplate().update(sql,name,money); } @Override
public void updateAccount(String name, double money, boolean isbuy) {
String sql = "update account set balance=balance+? where name=?";
if(isbuy)
sql = "update account set balance=balance-? where name=?";
this.getJdbcTemplate().update(sql, money,name);
} }
public interface StockDao { void addStock(String sname,int count); void updateStock(String sname,int count,boolean isbuy); }
public class StockDaoImpl extends JdbcDaoSupport implements StockDao { @Override
public void addStock(String sname, int count) {
String sql = "insert into stock(name,count) values(?,?)";
this.getJdbcTemplate().update(sql,sname,count);
} @Override
public void updateStock(String sname, int count, boolean isbuy) {
String sql = "update stock set count = count-? where name = ?";
if(isbuy)
sql = "update stock set count = count+? where name = ?";
this.getJdbcTemplate().update(sql, count,sname);
} }
Service层
public interface BuyStockService { public void addAccount(String accountname, double money); public void addStock(String stockname, int amount); public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException; }
public class BuyStockServiceImpl implements BuyStockService{ private AccountDao accountDao;
private StockDao stockDao; @Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money);
} @Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount);
} @Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy);
} public AccountDao getAccountDao() {
return accountDao;
} public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
} public StockDao getStockDao() {
return stockDao;
} public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
} }
自定义异常类
public class BuyStockException extends Exception { public BuyStockException() {
super();
} public BuyStockException(String message) {
super(message);
} }
(1)基于 TransactionProxyFactoryBean的声明式事务管理
<?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:mvc="http://www.springframework.org/schema/mvc"
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-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-aop-4.2.xsd
"> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean> <bean id="accountDao" class="transaction.test2.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="stockDao" class="transaction.test2.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="buyStockService" class="transaction.test2.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean> <!-- 事务管理器 --> <bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 事务代理工厂 -->
<!-- 生成事务代理对象 -->
<bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="myTracnsactionManager"></property>
<property name="target" ref="buyStockService"></property>
<property name="transactionAttributes">
<props>
<!-- 主要 key 是方法
ISOLATION_DEFAULT 事务的隔离级别
PROPAGATION_REQUIRED 传播行为
-->
<prop key="add*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
<!-- -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException</prop>
</props>
</property> </bean> </beans>
测试入口
public static void main(String[] args) {
String resouce = "transaction/test2/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
BuyStockService buyStockService = (BuyStockService) applicationContext.getBean("serviceProxy"); // buyStockService.openAccount("小郑", 5000); // buyStockService.openStock("知晓科技", 0); try {
buyStockService.buyStock("小郑", 1000, "知晓科技", 100);
} catch (BuyStockException e) {
e.printStackTrace();
} }
发生异常账户金额不能减,股票不能增加
(2)基于 @Transactional 的声明式事务管理
其他类不做改变,只改变购买股票接口实现类和配置文件
public class BuyStockServiceImpl implements BuyStockService{ private AccountDao accountDao;
private StockDao stockDao; @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money); } @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
@Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount); } public BuyStockServiceImpl() {
// TODO Auto-generated constructor stub
} @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=BuyStockException.class)
@Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy); } public AccountDao getAccountDao() {
return accountDao;
} public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
} public StockDao getStockDao() {
return stockDao;
} public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
} }
<context:property-placeholder location="classpath:jdbc.properties"/> <!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean> <bean id="accountDao" class="transaction.test3.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="stockDao" class="transaction.test3.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="buyStockService" class="transaction.test3.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean> <!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="myTracnsactionManager"/>
可以看出,使用@Transactional注解的方式配置文件要简单的多,将事务交给事务注解驱动。它有个缺陷是他会把所有的连接点都作为切点将事务织入进去,显然只需要在buyStock()方法织入事务即可。下面看看最后一种实现,它就可以精准的织入到指定的连接点
知识点:
事务超时:@Transactional(timeout = 60)
public boolean rollbackOn(Throwable ex) {
只有spring事务捕获到Exception异常后,@Transactional(rollbackFor=Exception.class),才会起到应有的作用;catch (Exception e) { e.printStackTrace(); }这句是捕获try中出现的Exception然后将异常信息打印出来,仅仅是打印出来,然后什么也没干。
2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
checked Unchecked exception是运行时错误。
(3)基于Aspectj AOP配置事务
public class BuyStockServiceImpl implements BuyStockService{ private AccountDao accountDao;
private StockDao stockDao; @Override
public void addAccount(String accountname, double money) {
accountDao.addAccount(accountname,money); } @Override
public void addStock(String stockname, int amount) {
stockDao.addStock(stockname,amount); } public BuyStockServiceImpl() {
// TODO Auto-generated constructor stub
} @Override
public void buyStock(String accountname, double money, String stockname, int amount) throws BuyStockException {
boolean isBuy = true;
accountDao.updateAccount(accountname, money, isBuy);
if(isBuy==true){
throw new BuyStockException("购买股票发生异常");
}
stockDao.updateStock(stockname, amount, isBuy); } public AccountDao getAccountDao() {
return accountDao;
} public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
} public StockDao getStockDao() {
return stockDao;
} public void setStockDao(StockDao stockDao) {
this.stockDao = stockDao;
} }
<context:property-placeholder location="classpath:jdbc.properties"/> <!-- 注册数据源 C3P0 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean> <bean id="accountDao" class="transaction.test4.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="stockDao" class="transaction.test4.dao.StockDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean> <bean id="buyStockService" class="transaction.test4.service.BuyStockServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="stockDao" ref="stockDao"></property>
</bean> <!-- 事务管理器 -->
<bean id="myTracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean> <tx:advice id="txAdvice" transaction-manager="myTracnsactionManager">
<tx:attributes>
<!-- 为连接点指定事务属性 -->
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/>
</tx:attributes>
</tx:advice> <aop:config>
<!-- 切入点配置 -->
<aop:pointcut expression="execution(* *..service.*.*(..))" id="point"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>
执行接口与其他方式一样。
转自:https://blog.csdn.net/chinacr07/article/details/78817449
Spring事务管理之几种方式实现事务(转)的更多相关文章
- Spring事务管理之几种方式实现事务
1.事务认识 大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销.Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring ...
- 事务管理(下) 配置spring事务管理的几种方式(声明式事务)
配置spring事务管理的几种方式(声明式事务) 概要: Spring对编程式事务的支持与EJB有很大的区别.不像EJB和Java事务API(Java Transaction API, JTA)耦合在 ...
- Spring事务管理的四种方式(以银行转账为例)
Spring事务管理的四种方式(以银行转账为例) 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不 ...
- Spring事务管理的三种方式
一 .第一种:全注解声明式事务 Xml代码 复制代码 收藏代码 .<?xml version="1.0" encoding="UTF-8"?> .& ...
- 配置spring事务管理的几种方式(声明式事务)
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSo ...
- Spring中事务管理的两种方式
spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager.对于编程式事务 ...
- Spring事务管理的两种方式
参考文档: http://www.iteye.com/topic/1123347 http://blog.csdn.net/lcj8/article/details/2835432 PS:好像还是tx ...
- 事务有哪些特性?spring的事务管理有几种方式实现,如何实现?
特性:1.原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做 2.一致性:数据不会因为事务的执行而遭到破坏 3.隔离性:一个事物的执行,不受其他事务的干扰,即并发执行的事 ...
- Spring加载applicationContext.xml实现spring容器管理的几种方式
package com.etc.test; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; i ...
随机推荐
- Flask【第5篇】:用Falsk实现的分页
用flask实现的分页 一.flask实现的分页组件 from urllib.parse import urlencode,quote,unquote class Pagination(object) ...
- vue单页面项目中解决安卓4.4版本不兼容的问题
1.cnpm安装 cnpm i babel-polyfill --save cnpm i es6-promise --save 2.main.js引入 import ‘babel-polyfill‘ ...
- 【python基础】集合方法汇总
一.定义 用于存储一组无序的不重复的数据 二.特点 1. 集合是无序的 2.集合中的元素是不重复的, 唯一的 3.集合中存储的数据必须是不可变的数据类型 4.集合是可变的数据类型 三.语法 set1 ...
- 0-4评价一个语言模型Evaluating Language Models:Perplexity
有了一个语言模型,就要判断这个模型的好坏. 现在假设: 我们有一些测试数据,test data.测试数据中有m个句子;s1,s2,s3-,sm 我们可以查看在某个模型下面的概率: 我们也知道,如果计算 ...
- linux运维、架构之路-Kubernetes本地镜像仓库+dashboard部署
一.部署docker registry 生产环境中我们一般通过搭建本地的私有镜像仓库(docker registry)来拉取镜像. 1.拉取registry镜像 [root@k8 ...
- ACM 求全排列(字典序、邻位对换、递增进位制数,递减进位制数)
字典序:(联合康托展开就也可以按照中介数求) 邻位对换.递增进位制数,递减进位制数:具体的实现和算法讲解如下: 代码..C++版的实现并不好..因为是挨个向后找的,如果K很大的时候会超时,不过...思 ...
- python3.0笔记
python文件头 #!/usr/bin/env python # -*- coding: utf- -*- ''' Created on 2017年5月9日 @author: Administrat ...
- [codeforces743C]:Vladik and fractions(数学)
题目传送门 题目描述 请找出一组合法解使得$\frac{1}{x}+\frac{1}{y}+\frac{1}{z}=\frac{2}{n}$成立. 其中$x,y,z$为正整数且互不相同. 输入格式 一 ...
- Model 层
package com.test.mvp.mvpdemo.mvp.v1.model; import com.test.mvp.mvpdemo.mvp.v1.MainContract; import o ...
- vue 通过绑定事件获取当前行的id
<div @click="router(items.productId)" style="float: left;" :key='items.produc ...