Spring框架(Spring事务管理初识)

    技术2022-07-11  111

    目录,更新ing,学习Java的点滴记录

      目录放在这里太长了,附目录链接大家可以自由选择查看--------Java学习目录

    Spring知识

      一丶SpringIOC初步认识↓↓↓ 第一篇---->初识Spring   二丶SpringIOC深入↓↓↓ 第二篇---->深入SpringIoC容器(一) 第三篇---->深入SpringIoC容器(二)   三丶装配SpringBean↓↓↓ 第四篇---->依赖注入的方式 第五篇---->基于xml装配Bean 第六篇---->基于注解装配Bean 第七篇---->Spring Bean之间的关系 第八篇---->SpringBean的作用域 第九篇---->Spring 加载属性(properties)文件 第十篇---->Spring表达式(SpEL) 第十一篇---->Spring在xml中配置组件扫描   四丶面向切面编程↓↓↓ 第十二篇—>认识SpringAOP及底层原理 第十三篇—>使用@AspectJ注解开发AOP 第十四篇—>使用xml配置开发AOP   五丶Spring中数据库编程↓↓↓ 第十五篇—>数据库编程JdbcTemplate   六丶Spring事务管理↓↓↓ 第十六篇—>Spring事务管理初识 第十七篇—>编程式事务和声明式事务 第十八篇—>事务ACID特性 第十九篇—>事务传播行为 第二十篇—>事务隔离级别

    六丶深入Spring数据库事务管理

    1 互联网应用中面临的数据库事务相关问题

    互联网系统时时面对着高并发,在互联网应用上同时跑着成百上千条线程都非常刹那间,尤其是比如想京东,淘宝等一些购物网站举办双十一这样的活动或者将一些廉价商品放在线上销售时,在同一秒内,各种用户通过手机,电脑,平板等设备疯狂抢购,这样就会出现多线程访问网站,进而导致数据库在一个多事务访问环境中,从而引发数据库丢失更新和数据一致性问题,同时也会给服务器带来很大的压力,甚至发生数据库系统死锁和瘫痪进行导致系统宕机.为了解决这些问题,我们非常有必要了解数据库的一些特定,进行主动规避一些存在的问题,避免数据的不一致,提高系统性能在大部分情况下,我们认为数据库事务要么同时成功,要么同时失败,但是不可否认也会存在其他需求.比如银行的信用卡还款,有个批量还款的事务,其中包含了多张信用卡还款的业务处理,我们显然不能因为一张卡的还款失败而将其他卡的还款操作都回滚,这样就会导致因为一个客户出现异常,造成多个客户还款失败,即正常还款用户也会被当成不正常的.Spring事务的传播行为带来了很好的解决方案.后面这一部分的内容也非常重要,毕竟没有人觉得事务不重要吧?hh.里面涉及到一个著名的注解—@Transactional,但是理解他却不容易,它涉及到数据库的很多概念,这里会一一说明,数据库的隔离级别和传播行为可能也是需要反复理解的地方.

    2 事务简介

    事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用暴露的问题,以下面这段JDBC连接数据库的代码为例   在使用JDBC对数据库操作时,必须为不同的方法重写类似的样板代码,此外这段代码是特定于 JDBC 的, 一旦选择类其它数据库存取技术, 代码需要作出相应的修改

    3 Spring数据库事务管理器

    作为企业级应用程序框架, Spring 在不同的事务管理 API 之上定义了一个抽象层. 而应用程序开发人员不必了解底层的事务管理 API, 就可以使用 Spring 的事务管理机制.

    3.1 Spring底层事务管理器的设计

    Spring中数据库事务是通过PlatformTransactionalManager进行管理的,它为事务管理封装了一组独立于技术的方法. 无论使用 Spring 的哪种事务管理策略(编程式或声明式), 事务管理器都是必须的.在上面目录中第十五篇SpringJdbcTemplate中,我们谈到过它是不能支持事务的,而能够支持事务的是org.springframework.transaction.support.TransactionTemplate模板,它是Spring所提供的事务管理器的模板.下面看一下TransactionTemplate的源码(已经做了注释) @SuppressWarnings("serial") public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean { // 打印日志相关类 protected final Log logger = LogFactory.getLog(getClass()); // 事务管理器 private PlatformTransactionManager transactionManager; // 创建一个TransactionTemplate的构造器,为创建Bean实例提供条件 public TransactionTemplate() { } //使用已有的事务管理器初始化一个TransactionTemplate对象 public TransactionTemplate(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } // 使用传入的事务管理器来初始化一个TransactionTemplate对象,并且采用所给的事务的默认配置 public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) { super(transactionDefinition); this.transactionManager = transactionManager; } //设置要使用的事务管理器 public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } //返回使用的事务管理器 public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } //如果没有设置事务管理的话,将抛出异常-->类的属性(事务管理器)是必须的 @Override public void afterPropertiesSet() { if (this.transactionManager == null) { throw new IllegalArgumentException("Property 'transactionManager' is required"); } } // 事务处理的核心方法 @Override public <T> T execute(TransactionCallback<T> action) throws TransactionException { // 使用自定义的事务管理器 if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else {//使用系统默认管理器 //获取事务的状态 TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { //回调接口方法 result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback //回滚异常方法 rollbackOnException(status, ex); //抛出异常 throw ex; } catch (Error err) { // Transactional code threw error -> rollback //回滚异常方法 rollbackOnException(status, err); //抛出错误 throw err; } catch (Exception ex) { // Transactional code threw unexpected exception -> rollback //回滚异常方法 rollbackOnException(status, ex); //抛出无法捕获异常 throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } //提交事务 this.transactionManager.commit(status); //返回结果 return result; } } //执行回滚,正确处理异常的方法,status代表事务的对象,ex代表抛出的异常或者错误 private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException { logger.debug("Initiating transaction rollback on application exception", ex); try { this.transactionManager.rollback(status); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } } } 从上面源码中可以看到   1) 事务的创建,提交和回滚都是通过PlatformTransactionManager接口来完成的   2) 当事务产生异常时会回滚事务,在默认的实现中所有的异常都会回滚(catch语句用用了Throwable,是所有异常和错误的父类).我们可以通过配置去修改在某些异常发生时回滚或者不回滚事务   3) 当没有异常,就会提交这样的话,我们明白了Spring事务管理的源头在于事务管理器的设计,那么关注点自然转移到事务管理器(TransactionManager)的实现上了.Spring中有多种事务管理器的实现,如下图   上图中我们最常用的就是DataSourceTransactionManager,它继承抽象事务管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又实现了PlatformTransactionManager.这样Spring就可以像源码中一样使用PlatformTransactionManager接口中的方法,创建,提交或回滚事务了.下面在看一下PlatformTransactionManager的源码   方法作用一目了然

    3.2 配置事务管理器

    由于目前SSM框架居于主流地位,所以用的最多的事务管理器是DataSourceTransactionManager(org.springframeworkd.jdbc.datasource.DataSourceTransactionManager).而恰好该事务管理器与MyBatis框架关系也比较密切如果你使用Hibernate框架,那么就需要用到Spring-orm的jar包了(org.springframework.orm.hibernate4.HibernateTransactionManager)了.下面基于MyBatis的使用管理,我选择使用DataSourceTransactionManager,先创建一个项目,导入jar包:链接:链接:https://pan.baidu.com/s/17ZRcowiQ6qX8mawQxmuWPQ 提取码:qao1   修改Spring配置文件,引入命名空间和xsd文件,配置数据库连接池和事务管理器   这里数据库连接池使用阿里巴巴的Druid,具体内容可以看上面的第十五篇—JdbcTemplate中内容   命名空间如果输入时没有提示的话可以复制这里的---->命名空间   配置文件中先引入了jdbc和tx的命名空间及其xsd文件,然后定义了Druid数据库连接池和jdbcTemplate,最后使用DataSourceTransactionManager来定义数据库事务管理器,将数据库连接池注入.通过上述配置后,Spring就明白了你已经将数据库事务委托给事务管理器transactionManager管理了.如果你看过上面第十五篇末尾,谈到过单独使用JdbcTemplate的话,数据库资源的获取和释放都没有委托给数据库管理器,有JdbcTemplate自己管理,也不支持事务,但是经过上述配置,已经将工作给了事务管理器,所以以后JdbcTemplate的数据库资源和事务已经交给事务管理器处理了.Spring 既支持编程式事务管理, 也支持声明式的事务管理.但是编程式事务管理几乎已经不用了,所以仅做简单介绍.   编程式事务管理: 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚. 在编程式管理事务时, 必须在每个事务操作中包含额外的事务管理代码.,但是产生冗余,代码可读性很差   声明式事务管理: 大多数情况下比编程式事务管理更好用. 它将事务管理代码从业务方法中分离出来, 以声明的方式来实现事务管理. 事务管理作为一种横切关注点, 可以通过 AOP 方法模块化. Spring 通过 Spring AOP 框架支持声明式事务管理.声明式事务又可以分为XML配置和注解事务,xml配置方式也已经不常用了,也只做简要介绍,目前主流的方式就是使用注解@Transactional.

    3.3 配置实现Spring数据库事务

    上面是使用xml的方式来配置数据库事务,如果你想在代码中怎么配置呢?实现Spring数据库事务的话,需要在配置类中实现接口TransactionManagementConfigurer的annotationDrivenTransactionManager方法.Spring会把annotationDrivenTransactionManager方法返回的事务管理器作为程序中的事务管理器,如下   说明:该配置类中实现了TransactionManagementConfigurer接口定义的方法annotationDrivenTransactionManager,并且我们采用了DataSourceTransactionManager作为数据库事务的实例,并传递数据源给它.这里使用了一个很关键的注解@EnableTransactionManagement,当我们在Spring上下文中使用@Transactional注解,Spring就会明白使用这个数据库事务管理器来管理事务
    Processed: 0.012, SQL: 9