Java/Spring和事务

前置阅读

https://blog.csdn.net/define_us/article/details/79738918
https://blog.csdn.net/define_us/article/details/80284576

java中的事务

因为现代架构由CS向BS架构演进,可信边界前移,所以,直接使用数据库锁机制的地方减少了。
当然,你仍然可以通过sql来使用数据库自己的锁机制

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

如果选择sesion参数,则本次会话所开启的事物全部使用该事务隔离级别。
如果使用global参数,则本次会话和所有新连接的会话都会使用该事务隔离级别
如果不使用任何参数,则只有本会话下一次开启的事物使用该隔离级别。

JAVA/Spring事务/ 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。

Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。
使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可以使用JTA来访问事务。JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据,这些数据可以分布在多个数据库上。JDBC驱动程序的JTA支持极大地增强了数据访问能力。
容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现。

Spring 同时支持编程式事务和声明式事务。编程式事务需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法。Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。事务增强也是AOP的一大用武之处。

JDBC则定义五种事物隔离级别:

  • RANSACTION_NONE JDBC: 驱动不支持事务
  • TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读,丢失更新。
  • TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读,丢失更新。
  • TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,但允许幻读,丢失更新。
  • TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读,丢失更新

Spring事务的传播属性

  • PROPAGATION_REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。
  • PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
  • PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
  • PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED 某一个事务存在,则运行在一个嵌套的事务中

下面解释一下事务挂起

方法A支持事务,方法B不支持事务。    即PROPAGATION_NOT_SUPPORTED
方法A调用方法B。
在方法A开始运行时,系统为它建立Transaction,方法A中对于数据库的处理操作,会在该Transaction的控制之下。
这时,方法A调用方法B,方法A打开的 Transaction将挂起,方法B中任何数据库操作,都不在该Transaction的管理之下。
当方法B返回,方法A继续运行,之前的Transaction回复,后面的数据库操作继续在该Transaction的控制之下提交或回滚。

Spring中的隔离级别

其实隔离级别是SQL标准规范中的语义

  • ISOLATION_DEFAULT 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。
  • ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
  • ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
  • ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
  • ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。

我们都知道,通过如下SQL可以确定数据库目前事务的隔离级别

show variables like 'tx_isolation'; # 查看隔离级别,MySQL8以前
show variables like 'transaction_isolation'; # 查看隔离级别,MySQL8
 
set global transaction_isolation='READ-COMMITTED'; // 设置隔离级别,阀域READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE

但是这个是数据层的。实际上,可以对不通session调整不同的级别

set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;

所以,spring中的隔离级别本质上要依赖数据源的支持。比如说目前据说很厉害的OceanBase只支持READ-COMMITTED的隔离借呗。。


基于声明的事务管理

SPRING是基于声明的事务管理。Spring事务可以操作hibernate,也可以直接操作JDBC。事实上,我们一般就是再操作数据时才使用事务的概念。

Spring有专门的的事务管理器类。

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。但是推荐只用在public方法上。
该注解可以配置如下属性:

  • value String 可选的限定描述符,指定使用的事务管理器
  • propagation enum: Propagation 可选的事务传播行为设置
  • isolation enum: Isolation 可选的事务隔离级别设置
  • readOnly boolean 读写或只读事务,默认读写
  • timeout int (in seconds granularity) 事务超时时间设置
  • rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
  • rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
  • noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
  • noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

第一步,配置容器

<?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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">   
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
     
    <bean id="accountDao" class="com.ys.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
     
    <bean id="accountService" class="com.ys.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
     
    <!-- 创建模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager"></property>
    </bean>
     
    <!-- 配置事务管理器 ,管理器需要事务,事务从Connection获得,连接从连接池DataSource获得 -->
    <!-- 如果要和mybaits整合,那么应该是一致的 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值