Spring 声明式事务@Transactional不起作用,为啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 声明式事务@Transactional不起作用,为啥相关的知识,希望对你有一定的参考价值。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<tx:annotation-driven transaction-manager="txManager" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="$c3p0.driverClass"></property>
<property name="jdbcUrl" value="$c3p0.url"></property>
<property name="user" value="$c3p0.user"></property>
<property name="password" value="$c3p0.password"></property>
<property name="acquireIncrement" value="$c3p0.acquireIncrement"></property>
<property name="initialPoolSize" value="$c3p0.initialPoolSize"></property>
<property name="maxIdleTime" value="$c3p0.maxIdleTime"></property>
<property name="maxPoolSize" value="$c3p0.maxPoolSize"></property>
<property name="minPoolSize" value="$c3p0.minPoolSize"></property>

<property name="acquireRetryDelay" value="1000"></property>
<property name="acquireRetryAttempts" value="60"></property>
<property name="breakAfterAcquireFailure" value="false"></property>
</bean>

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:c3p0.properties</value>
</list>
</property>
</bean>

<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>

参考技术A 1. spring 配置文件开启注解声明 2. java代码方法上打上标记 @Transactional(rollbackFor=Exception.class, RuntimeException.class) 方法抛出异常的时候事物回滚 参考技术B 1. spring 配置文件<context:annotation-config />开启注解声明
2. java代码方法上打上标记
@Transactional(rollbackFor=Exception.class, RuntimeException.class)
方法抛出异常的时候事物回滚追问

都加了。。还是不起作用。。

追答

最好是把log打成debug,看下log信息

参考技术C 我也遇到了同样的问题,到网上搜了一天,基本说法大同小异,也并没有解决问题。后来问了同事,据说是跑单元测试就不生效,真正的代码发布,然后去请求自己的服务,事物就生效了。一个建议,如果你也是用单元测试测的不生效,可以把代码跑起来再试试

spring学习笔记声明式事务

声明式事务

编程式事务:和声明式事务对应的是编程式事务,编程式事务在业务代码中添加事务控制代码,这样的事务控制机制就叫编程式事务。
声明式事务:通过xml或者注解配置的方式打到事务控制的目的,叫声明式事务。

事务

事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功,确保数据的准确和安全。

事务四大特性

原子性

事务是一个不可分割的工作单位,从操作的角度来描述,事务中的操作要么都发生,要么都不发生。

一致性

一致性是从数据的角度来描述的,例如转账之前,A有1000,B有1000。转账之后,A+B还要等于2000

隔离性

隔离性就是多个用户并发访问数据库时,数据库为没一个用户开启的事务,每个事务不能被其他事务的操作数据所干扰,多个并发事物之间要相互隔离。避免脏读。

持久性

持久性是指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来及时数据库发生故障也是不应该有任何影响。

事务的隔离级别

隔离级别解决事务并发问题,
脏读 :一个线程中的事务读到了另外一个线程中未提交的数据。
不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据(前后内容不一样)
虚读(幻读)一个线程中的事务读到了另外一个线程中已经提交的insert或者delete的数据(前后条数不一样)
事务隔离级别:
Serializable(串行化):可避免脏读、不可重复读、幻读的情况发生。级别最高。
Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。(幻读有可能发生) 级别第二。该机制下,会对要update的行进行加锁。
Read committed(读已提交):可避免脏读情况发生。不可重复读和幻读一定会发生。级别第三。
Read Uncommitted(读未提交):最低级别,以上情况均无法保证。级别最低。
随着隔离级别的升高,效率也一次降低。
mysql默认的事务隔离级别:Repeatable read(可重复读)
查询当前使用的隔离级别:select @@tx_isolation;

事务传播行为

事务旺旺在service层进行控制,如果出现service层方法A调用了另一个service层中的方法B,A和B本身都已经被添加了事务控制,那么A调用B的时候,就需要进行事务协商,这就叫做事务的传播。
A调用B,我们站在B的角度来观察来定义事务的传播行为一般情况下,我们使用以下两种方式来处理:
PROPAGATION_REQUIRED:如果当前事务没有事务,就新建一个事务,如果已经存在一个事务,那么加入到这个事务中。
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(非事务方式执行一般存在于select的时候)

基于springAOP的声明式事务

纯xml模式

    <!--spring 声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        定制事务细节,传播行为、隔离级别-->
        <tx:attributes>
<!--            一般性配置-->
            <tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT" timeout="-1"/>
<!--            针对查询的覆盖性-->
            <tx:method name="query*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT" timeout="-1"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <!--advice-ref指向增强=横切逻辑+方位-->
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.edu.service.impl.TransferServiceImpl(..))"/>
    </aop:config>

纯注解模式
在启动类上添加@EnableTransactionManagement

以上是关于Spring 声明式事务@Transactional不起作用,为啥的主要内容,如果未能解决你的问题,请参考以下文章

Spring的声明式事务处理怎么配置,可以在提交事务后关闭数据库连接?

Spring声明式事务

spring学习笔记声明式事务

spring中声明式事务 配置好后,在java代码中怎么使用

Spring AOP 应用:Spring 声明式事务的支持

spring 声明式事务原理解读