1、事务认识

大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销。Spring事务管理基于底层数据库本身的事务处理机制。数据库事务的基础,是掌握Spring事务管理的基础。这篇总结下Spring事务。
事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。
(1)原子性(Atomicity)
事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性(Consistency)
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
(3)隔离性(Isolation)
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
(4)持久性(Durability)
指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。

2、事务的传播特性

事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring定义了7中传播行为:
(1)propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。
(2)propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
(3)propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
(4)propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
(5)propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
(6)propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
(7)propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。

3、事务的隔离级别

(1)read uncommited:是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。
(2)read commited:保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。
(3)repeatable read:这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。
(4)serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读
(5)脏读、不可重复读、幻象读概念说明:
a.脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
b.不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
c.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中)

4、事务几种实现方式

(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务

5、举例说明事务不同实现

编程式事务基本已经OUT了,在上上家公司的老工程还能找到,所有就省略了,主要回顾 下声明式事务。
以用户购买股票为例
新建用户对象、股票对象、以及dao、service层
/*** 账户对象**/
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 {@Overridepublic void addAccount(String name, double money) {String sql = "insert account(name,balance) values(?,?);";this.getJdbcTemplate().update(sql,name,money);}@Overridepublic 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 {@Overridepublic void addStock(String sname, int count) {String sql = "insert into stock(name,count) values(?,?)";this.getJdbcTemplate().update(sql,sname,count);}@Overridepublic 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;@Overridepublic void addAccount(String accountname, double money) {accountDao.addAccount(accountname,money);}@Overridepublic void addStock(String stockname, int amount) {stockDao.addStock(stockname,amount);}@Overridepublic 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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsdhttp://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)@Overridepublic void addAccount(String accountname, double money) {accountDao.addAccount(accountname,money);}@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)@Overridepublic 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)@Overridepublic 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()方法织入事务即可。下面看看最后一种实现,它就可以精准的织入到指定的连接点

(3)基于Aspectj AOP配置事务

public class BuyStockServiceImpl implements BuyStockService{private AccountDao accountDao;private StockDao stockDao;@Overridepublic void addAccount(String accountname, double money) {accountDao.addAccount(accountname,money);}@Overridepublic void addStock(String stockname, int amount) {stockDao.addStock(stockname,amount);}public BuyStockServiceImpl() {// TODO Auto-generated constructor stub}@Overridepublic 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>

执行接口与其他方式一样。

好了今天的博客写到这里,明天继续加油!

Spring事务管理之几种方式实现事务相关推荐

  1. Spring的4种事务管理(1种编程式事务+三种声明事务)

    2019独角兽企业重金招聘Python工程师标准>>> Spring的4种事务管理(1种编程式事务+三种声明事务) 一.Spring事务的介绍 二.编程式事务xml的配置 注入后直接 ...

  2. 配置spring事务管理的几种方式(声明式事务)

    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSo ...

  3. Spring中进行事务管理的两种方式

    1.Spring中事务管理的API 事务是指逻辑上要么全部成功.要么全部失败的一组操作.例如用户A给用户B转账,则用户A账户余额减少.用户B账户增加这两个操作就是一组事务,必须全部成功或失败撤回操作, ...

  4. spring事务管理的两种方式

    一.注解式事务 1.注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo. 2.事务配置实例 (1).spring+mybatis 事务配置 &l ...

  5. spring支持事务管理的两种方式

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

  6. Spring中把一个bean对象交给Spring容器管理的三种方式

    一.使用@Component,把bean对象依赖交给Spring容器 注意,该注解不能使用,则说明未添加依赖,需要去该项目pom.xml文件内引入依赖,若该项目只是作为一个存放工具类的子模块项目,没有 ...

  7. spring中自定义对象交给spring容器管理的4种方式

    1.自定义一个 BeanDefinition @Component public class BeanPro implements BeanDefinitionRegistryPostProcesso ...

  8. Spring事务管理详解_基本原理_事务管理方式

    Spring事务管理详解_基本原理_事务管理方式 1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象 ...

  9. spring 的4种事务管理(1种编程式+3种声明式)

    见:http://blog.csdn.net/sinat_25926481/article/details/48208619 Spring的4种事务管理(1种编程式事务+三种声明事务) 一.Sprin ...

最新文章

  1. 微信小程序-封装http请求(ajax)
  2. windows下部署redis
  3. (仿头条App项目)9.视频列表页面实现
  4. java magic number_Magic Number
  5. IntellIJ IDEA 配置 Maven 以及 修改 默认 Repository
  6. 你还在 new 对象吗?Java8 通用 Builder 了解一下?
  7. 一个类的两个接口有同名函数,JAVA如何调用
  8. Centos下安装Scrapy
  9. axis调用webservice服务
  10. (超详细笔记整理)动力节点_老杜 | JavaSE进阶 【P486之后】
  11. 双组百分比堆积柱形图的制作
  12. html5 canvas实现桌面效果,基于html5 canvas实现漫天飞雪效果实例
  13. 初步认识C语言中的选择和循环语句
  14. 几种矩阵分解算法: LU分解,Cholesky分解,QR分解,SVD分解,Jordan分解
  15. 【EM算法】期望最大化算法
  16. android 外接扫码枪_Android手机(设备)连接扫描枪扫码遇到的问题
  17. windows bitlocker加密 分区
  18. ubuntu加入widdows启动
  19. 大数据新闻推送你怎么看_大数据分析表明:新闻越“假”转发越多!你知道为什么吗?...
  20. HTML五子棋游戏论文,五子棋毕业论文-HTML开发五子棋的原型设计.doc

热门文章

  1. applewatch2 android,Apple Watch 2最新消息 更专注配置以及材质
  2. 图片压缩到200k以内怎么操作?图片压缩指定大小工具推荐
  3. 惠普笔记本刷linux系统教程,【高手 你会用吗?HP Linux系统笔记本】- 中关村在线...
  4. QQ空间运营 怎么做一个QQ人气号?
  5. mysql数据库连接数
  6. impl java_究竟是什么毁了我的impl实现
  7. Android聊天软件的开发(三)--网络连接
  8. android 误触屏幕失灵,华为手机触摸屏没反应怎么办?解决手机触摸屏时灵时不灵的办法...
  9. JVM-动态年龄判断你真的理解了吗
  10. 手机上怎么记录恋爱天数?用便签记录情侣相恋天数