Spring事务最全配置

Spring Transaction Management

Spring框架为事务管理提供了一致的抽象,具有跨不同事务API(例如Java事务API(JTA),JDBC,Hibernate和Java Persistence API(JPA))的一致编程模型,支持声明式事务管理,有比JTA更加简单的编程式API,能与Spring的数据访问抽象的出色集成。

什么是事务?

事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行; 事务是一组不可再分割的操作集合(工作逻辑单元);
在这里插入图片描述

事务的四大特性:

1.原子性: 事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做。

2.一致性:最终结果保持相同,比如A给B转账100,A账户-100,B账户 +100,A和B账户总和要和转账之前AB总和保持相同。

3.隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

4.持久性: 也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

事务的隔离级别:

隔离级别是指若干个并发的事务之间的隔离程度,Spring 在TransactionDefinition 这个接口 定义了五个隔离级别:

(1) ISOLATION_DEFAULT:默认的隔离级别,默认你接入的数据库默认隔离级别。一般默认的是READ_COMMITTED,幻读。其他的四个对应JDBC的隔离级别。

(2) ISOLATION_READ_UNCOMMITTED :指示可能发生脏读、不可重复读取和幻象读取。此级别允许一个事务更改的行,在提交该行中的任何更改之前,被另一个事务读取(“脏读”)。如果回滚了任何更改,则第二个事务将检索到无效行。这个隔离级别一般不会用。

(3) ISOLATION_READ_COMMITTED:可以阻止脏读取;但是可能发生不可重复读取和幻象读取。此级别仅禁止事务读取包含未提交更改的行。

(4) ISOLATION_REPEATABLE_READ:可以防止脏读和不可重复读取;可能会发生幻象读取。此级别禁止事务读取包含未提交更改的行,并且还禁止一个事务读取行,第二个事务更改行,第一个事务重新读取行,第二次获得不同值的情况(“不可重复读取”)。该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。幻读就是你读的过程中,别的事务对你读的内容进行修改,导致你多次查询的数据不一致。

(5)ISOLATION_SERIALIZABLE:可以防止脏读、不可重复读和幻象读。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

隔离级别越高,性能越差,所以大部分默认是幻读,READ_COMMITTED。

Spring 的事务传播特性:

(1) PROPAGATION_REQUIRED:支持当前事务,如果没有事务就创建新的事务。默认的传播特性。

(2)PROPAGATION_SUPPORTS:支持当前事务,如果没有事务,就以没有事务的方式执行。

(3)PROPAGATION_MANDATORY:支持当前事务,如果事务不存在就抛出异常。

(4)PROPAGATION_REQUIRES_NEW:创建新事务,如果有事务就暂停当前事务。

(5)PROPAGATION__NOT_SUPPORTS:不支持当前事务,总是以非事务方式执行。

(6)PROPAGATION_NEVER:不支持当前事务,如果事务存在就抛出异常。

(7)PROPAGATION_NESTED:如果存在当前事务,则在嵌套事务中执行。

Spring 的事务管理:

Spring 的事务管理是通过 PlatformTransactionManager这个接口来实现的。
Spring 的事务管理分为两种:声明式事务,编程式事务。

一、声明式事务:

<?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:aop="http://www.springframework.org/schema/aop"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
	
    <!-->配置JDBC数据源</!-->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"/>
		<property name="url" value="${jdbc.url}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
	</bean>

	<!-->将数据源注入到platformTransactionManager事务管理器中</!-->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<!-->设置事务通知</!-->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="say" read-only="true" isolation="READ_COMMITTED"/>
		</tx:attributes>
	</tx:advice>
	<!-->通过aop去配置事务通知</!-->
	<aop:config>
		<aop:pointcut id="addLogin" expression="execution(* test.Service.*.*(..))"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="addLogin"/>
	</aop:config>
</beans>
(1) 回滚声明式事务
一、声明配置那些异常抛出,事务会标记回滚
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
    <tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>
    <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
二、声明配置事务不回滚
<tx:advice id="txAdvice">
    <tx:attributes>
    <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
    <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
三、事务回滚根据配置的最大范围的匹配规则执行

这里会除了InstrumentNotFoundException异常外,其他的异常都会回滚

<tx:advice id="txAdvice">
  <tx:attributes>
  <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
  </tx:attributes>
</tx:advice>
四、编程式事务回滚

代码侵入性强,耦合紧,不建议使用。

public void resolvePosition() {
    try {
        // some business logic...
    } catch (NoProductInStockException ex) {
        // trigger rollback programmatically
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}
(2) 为不同的bean 设置不同的事务
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:config>

        <aop:pointcut id="defaultServiceOperation"
                expression="execution(* x.y.service.*Service.*(..))"/>

        <aop:pointcut id="noTxServiceOperation"
                expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>

        <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>

        <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

    </aop:config>

    <!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->
    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- this bean will also be transactional, but with totally different transactional settings -->
    <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>

    <tx:advice id="defaultTxAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <tx:advice id="noTxAdvice">
        <tx:attributes>
            <tx:method name="*" propagation="NEVER"/>
        </tx:attributes>
    </tx:advice>

    <!-- other transaction infrastructure beans such as a TransactionManager omitted... -->

</beans>
(3) tx:method/ 设置
属性必须的?默认描述
nameYes与事务属性关联的方法名。通配符()可以用于将相同的事务属性设置与许多方法(例如get、handle*、on*Event等)关联起来。
propagationNOREQUIRED事务传播行为。
isolationNODEFAULT事务隔离级别,仅适用于设置事务传播时的REQUIRED或者REQUIRED_NEW。
timeoutNO-1事务超时,仅适用于设置事务传播时的REQUIRED或者REQUIRED_NEW。
read-onlyNOfalse读写与只读事务。仅适用于设置事务传播时的REQUIRED或者REQUIRED_NEW。
rollback-forNO触发事务回滚的异常实例设置。
no-rollback-forNo不触发事务回滚的实例设置。
(4)使用@Transational注解
一、在类上加@Transactionnal代表类中所有的方法都具有事务
@Transactional
public class DefaultFooService implements FooService {

    Publisher<Foo> getFoo(String fooName) {
        // ...
    }

    Mono<Foo> getFoo(String fooName, String barName) {
        // ...
    }

    Mono<Void> insertFoo(Foo foo) {
        // ...
    }

    Mono<Void> updateFoo(Foo foo) {
        // ...
    }
}
二、在方法上加@Transactionnal代表该方法具有事务
public class DefaultFooService implements FooService {

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
    }
}

二、编程式事务:

(1) TransactionTemplate使用

TransactionTemplate类的实例是线程安全的,因为实例不维护任何会话状态。不过,TransactionTemplate实例确实保持配置状态。因此,虽然许多类可能共享TransactionTemplate的一个实例,但如果一个类需要使用具有不同设置(例如,不同的隔离级别)的TransactionTemplate,则需要创建两个不同的TransactionTemplate实例。

public class SimpleService implements Service {

    // single TransactionTemplate shared amongst all methods in this instance
    private final TransactionTemplate transactionTemplate;

    // use constructor-injection to supply the PlatformTransactionManager
    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }

    public Object someServiceMethod() {
        //有返回值时
        return transactionTemplate.execute(new TransactionCallback() {
            // the code in this method runs in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }
}
public void someServiceMethod1(){
//没有返回值时使用TransactionCallbackWithoutResult匿名类
transactionTemplate.execute(new TransactionCallbackWithoutResult匿名类() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        updateOperation1();
        updateOperation2();
     }
 });
}
//setRollbackOnly()回滚事务
transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
            updateOperation1();
            updateOperation2();
        } catch (SomeBusinessException ex) {
            status.setRollbackOnly();
        }
    }
});

事务设置

public class SimpleService implements Service {

    private final TransactionTemplate transactionTemplate;

    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired
        this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
        this.transactionTemplate.setTimeout(30); // 30 seconds
        // and so forth...
    }
}
<bean id="sharedTransactionTemplate"
        class="org.springframework.transaction.support.TransactionTemplate">
    <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
    <property name="timeout" value="30"/>
</bean>
(2) TransactionManager直接的实现

通过引用PlatformTransactionManager实例和

通过使用TransactionDefinitionTransactionStatus对象,您可以启动事务,回滚和提交

PlatformTransactionManager txManager = new DataSourceTransactionManager();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can be done only programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    // put your business logic here
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值