spring注解事务及事务回滚失败的原因

【spring】Spring事务失效分析,事务回滚失败原因,事务的传播机制 1.第一种情况 :调用方加上@Transactional 注解,被调用方未加上注解 (同一个service类) Exp: @Transactional void methodA(){ // insert table1 methodB(Object obj); } void methodB(){ // insert table2 } 结论:methodB()出现异常,抛给methodA,A中捕获到异常,进行回滚处理,table1,table2都未插入 2.第二种情况:调用方未加上注解,被调用方加上注解(同 阅读详情

背景

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

自动提交(AutoCommit)与连接关闭时的是否自动提交

自动提交

默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果
执行失败则隐式的回滚事务。

spring注解事务的实现

maven创建一个普通项目,当然web项目也可以,我这里是一个web项目
pom.xm如下,本身是用不到这么多jar,直接从项目中拷贝的,懒得删。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bamboo</groupId>
  <artifactId>anoTest</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>anoTest Maven Webapp</name>
  <url>http://maven.apache.org</url>

    <repositories>
        <repository>
            <id>nexus_public</id>
            <name>nexus_public</name>
            <url>http://repo.maven.apache.org/maven2/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>nexus_public</id>
            <name>nexus_public</name>
            <!-- <url>http://repository.jboss.org/nexus/content/repositories/root_repository/maven2/</url> -->
            <url>http://repo.maven.apache.org/maven2/</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <updatePolicy>never</updatePolicy>
            </releases>
        </pluginRepository>
    </pluginRepositories>



    <!-- 项目属性 -->
    <properties>
        <!-- jar 版本设置 -->
        <spring.version>4.1.0.RELEASE</spring.version>
        <shiro.version>1.2.3</shiro.version>
        <mybatis.version>3.2.8</mybatis.version>
        <mybatis-spring.version>1.2.2</mybatis-spring.version>
        <mysql.version>5.1.26</mysql.version>
        <druid.version>1.0.9</druid.version>
        <junit.version>3.8.1</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j.version>1.7.5</slf4j.version>
        <poi.version>3.10-FINAL</poi.version>
        <commons-lang3.version>3.1</commons-lang3.version>
        <commons-io.version>2.4</commons-io.version>
        <commons-codec.version>1.8</commons-codec.version>
        <commons-fileupload.version>1.3.1</commons-fileupload.version>
        <commons-beanutils.version>1.8.3</commons-beanutils.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.7</jdk.version>
    </properties>


<dependencies>
    <!-- spring相关包 -->
    <!-- Spring -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>servlet-api</artifactId>
            <version>6.0.37</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- 切面jar -->
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>

        <!-- javax提供的annotation,注入的注解jar -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

        <!-- 日志架包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!--springMVC 依赖json解析jar  -->
            <dependency>  
                <groupId>com.fasterxml.jackson.core</groupId>  
                <artifactId>jackson-core</artifactId>  
                <version>2.1.0</version>  
            </dependency>  
            <dependency>  
                <groupId>com.fasterxml.jackson.core</groupId>  
                <artifactId>jackson-databind</artifactId>  
                <version>2.1.0</version>  
            </dependency>  
            <dependency>  
                <groupId>com.fasterxml.jackson.core</groupId>  
                <artifactId>jackson-annotations</artifactId>  
                <version>2.1.0</version>  
            </dependency>   
        <!--Apache Shiro所需的jar包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency> -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${shiro.version}</version>
        </dependency> -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <!-- 数据库连接dbcp -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId> 
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- fileupload的jar -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>${commons-fileupload.version}</version>
        </dependency>
    <!-- apache 常用包 -->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.3</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <!-- 页面装饰 -->
        <dependency>
            <groupId>opensymphony</groupId>
            <artifactId>sitemesh</artifactId>
            <version>2.4.2</version>
        </dependency>
        <!-- jstl -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- 缓存ehcache -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.8.3</version>
        </dependency>
        <!-- ehcache缓存jar -->
        <!-- <dependency>  
            <groupId>com.googlecode.ehcache-spring-annotations</groupId>  
            <artifactId>ehcache-spring-annotations</artifactId>  
            <version>1.2.0</version>  
            <type>jar</type>  
            <scope>compile</scope>
        </dependency> -->






  </dependencies>
  <build>
    <finalName>onedollar</finalName>
  </build>
</project>

spring.xml

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
     xmlns:cache="http://www.springframework.org/schema/cache"
     xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/cache  http://www.springframework.org/schema/cache/spring-cache.xsd
    http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">

     <!-- 自动扫描 -->  
    <context:component-scan base-package="anotest" />  

    <!-- 定义一个数据源 -->  
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://127.0.0.1/shiro" />
        <property name="username" value="root" />
        <property name="password" value="root" />
        <property name="initialSize" value="3" /><!-- initial connections -->
        <property name="maxActive" value="10" /><!-- MAX connections -->
        <property name="maxIdle" value="5" /><!-- MAX idle connections -->
        <property name="minIdle" value="2" /><!-- MIN idle connections -->
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="validationQuery" value="select 1" />
        <property name="timeBetweenEvictionRunsMillis" value="20000" />
        <property name="numTestsPerEvictionRun" value="100" />
    </bean>

      <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <!-- 自动扫描mapping.xml文件 -->  
        <property name="mapperLocations" value="classpath:anotest/mapper/*.xml"></property>  
        <property name="typeAliasesPackage" value="anotest" />
    </bean>  

      <!-- DAO接口所在包名,Spring会自动查找其下的类 -->  
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="anotest.dao" />  
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
    </bean>  





    <!-- 配置事务管理器 -->  
    <bean id="txManager"  
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager"  
            p:dataSource-ref="dataSource">  
    </bean>  

    <!-- enables scanning for @Transactional annotations -->  
    <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" /> 

    <!-- 配置事物的拦截方式 -->
    <!-- <tx:advice id="transAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="modify*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />

            <tx:method name="find*" propagation="SUPPORTS" />
            <tx:method name="get*" propagation="SUPPORTS" />
            <tx:method name="select*" propagation="SUPPORTS" />
            <tx:method name="query*" propagation="SUPPORTS" />

            <tx:method name="*" propagation="SUPPORTS" />
        </tx:attributes>
    </tx:advice> -->

    <!-- 事物配置扫描包 -->
    <!--  <aop:config  proxy-target-class="true">
        <aop:pointcut expression="execution(* anotest.*impl.*(..))" id="transcationPointcut" />
        <aop:advisor advice-ref="transAdvice" pointcut-ref="transcationPointcut" />
    </aop:config> -->


</beans>

代码片段

创建包名
anotest.dao
anotest.mapper
anotest.service.impl

LogDao.java

package anotest.dao;

import anotest.Log;


/**
 * log页面表 数据库处理类
 */
public interface LogDao {

    void add(Log log);
}

LogMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="anotest.dao.LogDao">

<resultMap type="Log" id="Log">
    <id column="LOG_ID" property="logId" javaType="java.lang.Long" jdbcType="BIGINT"/>
    <result column="IMEI_CODE" property="imeiCode" javaType="java.lang.String" jdbcType="VARCHAR"/>
    <result column="DAY_TIME" property="dayTime" javaType="java.lang.String" jdbcType="VARCHAR"/>
</resultMap>


<!-- 全部字段,一般用于明细查询 -->
<sql id="AllColumnlist">
LOG_ID,IMEI_CODE,DAY_TIME
</sql>

<!-- 常见字段,一般用于列表查询,可能不包含备注之类的字段 -->
<sql id="CommonColumnlist">
LOG_ID,IMEI_CODE,DAY_TIME
</sql>

<insert id="add" parameterType="Log" useGeneratedKeys="true" keyProperty="LogId">
    insert into T_LOG (
        <if test="logId!=null">
        LOG_ID,
        </if>
        IMEI_CODE,
        DAY_TIME
    ) values (
        <if test="logId!=null">
        #{logId,jdbcType = BIGINT},
        </if>
        #{imeiCode,jdbcType = VARCHAR},
        #{dayTime,jdbcType = VARCHAR}
    )
</insert>


<delete id="delete">
    delete from T_LOG 
    <where>
        Log_ID=#{0}
    </where>
</delete>

<select id="get" resultMap="Log">
    select <include refid="AllColumnlist"/> from T_LOG
    <where>
        LOG_ID=#{0}
    </where>
</select>


<select id="getLogByCode" parameterType="java.lang.String" resultMap="Log">
    select * from T_LOG
    <where>
        IMEI_CODE=#{0}
    </where>
</select>


</mapper>

Log.java

package anotest;


public class Log {

    private static final long serialVersionUID = 1l;

    /*Auto generated properties start*/

    //log-id
    private Long logId;
    //IMEI编号
    private String imeiCode;
    //年月日
    private String dayTime;

    /*Auto generated methods start*/


    public Log() {
    }



    /**
     * @param imeiCode
     * @param dayTime
     */
    public Log(String imeiCode, String dayTime) {
        super();
        this.imeiCode = imeiCode;
        this.dayTime = dayTime;
    }








    /*Auto generated methods end*/



    /*Customized methods start*/

    /*Customized methods end*/

    public Long getLogId() {
        return logId;
    }






    public void setLogId(Long logId) {
        this.logId = logId;
    }






    public String getImeiCode() {
        return imeiCode;
    }






    public void setImeiCode(String imeiCode) {
        this.imeiCode = imeiCode;
    }






    public String getDayTime() {
        return dayTime;
    }






    public void setDayTime(String dayTime) {
        this.dayTime = dayTime;
    }






    @Override
    public String toString() {
        return "Log [logId=" + logId + ", imeiCode=" + imeiCode + ", dayTime="
                + dayTime + "]";
    }





}

TestService.java

package anotest.service;

import anotest.Log;


/** 
 * @ClassName: TestService 
 * @Description: TODO(这里用一句话描述这个类的作用) 
 * @author  bamboo   <a href="mailto:zjcjava@163.com?subject=hello,bamboo&body=Dear Bamboo:%0d%0a描述你的问题:">Bamboo</a>
 * @date 2017年3月7日 上午10:17:06 
 * @since
 */

public interface TestService {

    public void addCatch() throws Exception;

    public void addTest();
}

TestServiceImpl.java

package anotest.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import anotest.Log;
import anotest.dao.LogDao;
import anotest.service.TestService;

/** 
 * @ClassName: TestServiceImpl 
 * @Description: TODO(这里用一句话描述这个类的作用) 
 * @author  bamboo   <a href="mailto:zjcjava@163.com?subject=hello,bamboo&body=Dear Bamboo:%0d%0a描述你的问题:">Bamboo</a>
 * @date 2017年3月7日 上午10:38:42 
 * @since
 */
@Service
//默认将类中的所有函数纳入事务管理.    
@Transactional
public class TestServiceImpl implements TestService{

    @Resource
    private LogDao logDao;



    /***
     * 捕获异常后但是不抛出去是无法执行回滚事务的
     * 建议:用本方式写,使上层方法能够检测到数据插入失败,因此必须抛出异常,然后在调用它的方法中捕获异常并提示用户数据提交失败
     * @throws Exception 
     */
    @Transactional
    public void addCatch() throws Exception {
        // TODO Auto-generated method stub

         try {
             SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            String dayTime=format.format(new Date());
            Log log =new Log("ABCD", dayTime);
             log.setLogId(System.currentTimeMillis());
             System.out.println(log.toString());
            // 调用Dao执行插入操作
            logDao.add(log);//正常常数据
            log.setDayTime(dayTime+"yyyyyyyyyyyyyyyyyyy");
            // 调用Dao执行插入操作
            logDao.add(log);//异常数据
        } catch (Exception e) {
            // TODO Auto-generated catch block

            System.out.println("插入失败");
            //throw new Exception(e);//注意:正常环境中必须去掉本行注释,当把这行去掉注释事务回滚就会起作用
        }

    }

    /******
     * 运行时异常不作捕获则则能够正常执行回滚事务
     */
    @Transactional
    public void addTest() {
        // TODO Auto-generated method stub
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String dayTime=format.format(new Date());
        Log log =new Log("ABCD", dayTime);
         log.setLogId(System.currentTimeMillis());
         System.out.println(log.toString());
        // 调用Dao执行插入操作
        logDao.add(log);
        log.setDayTime(dayTime+"yyyyyyyyyyyyyyyyyyy");
        // 调用Dao执行插入操作
        logDao.add(log);//异常数据
    }


}

测试类

ContextConfig.java

import org.junit.runner.RunWith;  
import org.springframework.test.context.ContextConfiguration;  
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;  
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  

//指定bean注入的配置文件  
@ContextConfiguration(locations = { "classpath:spring.xml" })  
//使用标准的JUnit @RunWith注释来告诉JUnit使用Spring TestRunner  
@RunWith(SpringJUnit4ClassRunner.class) 
public class ContextConfig extends AbstractJUnit4SpringContextTests {

}

TestCase.java

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import anotest.service.TestService;


public class TestCase extends ContextConfig {

    @Autowired  
    private TestService testService;

    @Test
    public void getTimestampTest() throws Exception{  
        testService.addCatch();//1捕获异常的方法,注释掉异常抛出则不会回滚
        testService.addTest();//2没有任何捕获,能够正常回滚
    } 
}

测试结果

当注释掉注释//2所在的行只执行addCatch()方法时

log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Log [logId=1488871162669, imeiCode=ABCD, dayTime=20170307]
插入失败

插入失败,但是我们看数据库,依然会有数据被插入了

mysql> select * from t_log;
+---------------+-----------+------------+
| LOG_ID        | IMEI_CODE | DAY_TIME   |
+---------------+-----------+------------+
| 1488871162669 | ABCD      | 2017-03-07 |
+---------------+-----------+------------+
1 row in set (0.00 sec)

当注释掉注释//1所在的行只执行addTest()方法时
OUTPUT:

log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Log [logId=1488871460315, imeiCode=ABCD, dayTime=20170307]

看数据库,显然数据没有被插入,而是发生了回滚

mysql> select * from t_log;
+---------------+-----------+------------+
| LOG_ID        | IMEI_CODE | DAY_TIME   |
+---------------+-----------+------------+
| 1488871162669 | ABCD      | 2017-03-07 |
+---------------+-----------+------------+
1 row in set (0.00 sec)

我们在回到addCatch()方法,把下面这行的注释去掉

//throw new Exception(e);//注意:正常环境中必须去掉本行注释,当把这行去掉注释事务回滚就会起作用

运行测试

OUTPUT:

log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Log [logId=1488871709355, imeiCode=ABCD, dayTime=20170307]
插入失败

查看表数,可以看到这次数据并没有被插入

mysql> select * from t_log;
+---------------+-----------+------------+
| LOG_ID        | IMEI_CODE | DAY_TIME   |
+---------------+-----------+------------+
| 1488871162669 | ABCD      | 2017-03-07 |
+---------------+-----------+------------+
1 row in set (0.00 sec)

结论

spring的事务只有在触发运行时异常时才会发生回滚,并且这个异常是在切面中是可以被事务管理器捕获到的,如果我们自己在方法体中捕获而不把这个异常抛出(不通知事务管理器)它就不会除非事务回滚。因此在dao层基本不处理数据库插入异常。

其他原因

mysql数据库引擎的问题
mysql数据库引擎分为两种
innodb:支持事务和索引
myisam:不支持事务和索引,因此这种类型的引擎即使你的代码写的是正确的但是依然不会触发事务回滚。

配置文件扫描的问题
因为spring的容器(applicationContext)和springMVC的(applicationContext)是不同的。

spring容器加载得时候,优先加载ServletContextListener(对应spring.xml)产生的父容器,而springMVC(对应springMVC.xml)产生的是子容器。子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,

即没有事务处理能力的Service。而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service除去掉,此时得到的将是原样的无事务处理能力的Service。

所以,我们应把扫描Service的工作放在spring.xml中。让Service和事务注解存在于同一个容器中,这样配置的事务注解就能起作用了。也就是说把这个配置从

springMVC.xml中移到spring.xml的配置中。事务不回滚的问题就能解决了。

本demo下载

http://download.youkuaiyun.com/detail/zjcjava/9773010

Spring事务自调用陷阱:为什么你的@Transactional注解不生效? 本文深入剖析了Spring框架中@Transactional注解在自调用(self-invocation)场景下失效的根本原因,即Spring AOP代理机制的限制。文章详细解释了代理机制的工作原理,并提供了重构代码结构、自身注入、使用AspectJ、编程式事务管理等多种实战解决方案,帮助开发者有效规避这一常见陷阱,确保事务管理代码的可靠性。 阅读详情

相关推荐

OMNET++ INET框架学习教程(一)

在自组网学习的道路上摸石头过河,帮你快速入门OIMNET++平台下的INET框架。

NLDwangzhe的博客 6556

Spring的Transactional注解不回滚问题

为了解决这个问题, 网上找了很多资料。 但是你懂得, 百度搜出来的都是同一个问题拷贝来拷贝去。 什么public方法,unchecked异常都试过了还是不行。 后来在谷歌上找到一个blog https://ameblo.jp/kochablo/entry-11578714824.html 大致意思是, @Transactional必须是利用通过DI注入完后的对象调用@Transactio...

kimsung的专栏 764

Verilog数字钟

使用Verilog语言进行的数字钟的编写,FPGA开发板亲测正常 大学生一个,第一次自己做的东西,写出来分享在这里插入代码片一下,有不对的地方请大家批评指正。 这次的做的题是:设计一个数字钟,该数字钟能进行正常的时,分计时功能,且能对数字钟的时间进行调整。 该数字钟有3个按键,按键1为功能键,用于数字钟在“正常计时”,“时调整”,“分调整”这三个功能之间切换;按键2,3用于调整时间,仅当数字钟处于...

bin_bin_bun的博客 6149

Transaction 事务回滚无效,常见原因!!!

http://www.cnblogs.com/culushitai/p/9205036.html

无术不学的博客 3487

GEE影像重采样实战:从10米到500米,如何用.reduceResolution和.reproject统一尺度?

本文详细介绍了在Google Earth Engine (GEE)平台中,如何利用`.reduceResolution()`和`.reproject()`方法解决多源遥感影像的尺度统一难题。通过实战案例,从哨兵2号10米分辨率影像聚合至MODIS 500米尺度,阐述了聚合规则选择、参数配置及效果验证的全流程,为环境监测、农业分析等领域的跨尺度数据融合提供了关键方法。

weixin_29223603的博客 84

Megatron-LM深度解析:万亿参数大模型的3D并行训练之道

训练框架,采用创新的"层内模型并行"设计,通过将Transformer层的计算拆分到多个GPU上并行执行,显著提升训练效率。该系统支持3D并行策略(数据并行、张量并行、流水线并行)和序列并行等新技术,成功应用于训练5300亿参数的MT-NLG模型。相比DeepSpeed、TPU GSPMD等框架,Megatron-LM在NVIDIA GPU上展现出卓越性能,并与TensorRT等工具深度集成,形成从训练到部署的完整解决方案。该项目持续演进,已成为大模型训练的重要基准。

数据与算法架构提升之路专栏 2084

Spring的事务管理

Spring的事务管理 什么是事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。 事务的特性 原子性:事务不可分割 一致性:事务执行前后数据完整性保持一致 隔离性:一个事务的执行不应该受到其他事务的干扰 持久性:一旦事务结束,数据就持久化到数据库 如果不考虑隔离性引发安全性问题 读问题        脏读 :一个事务读到另一个事务未提交的数据 ...

bright_light12345的博客 337

python实现MACD策略背离点的判断 (附完整源码)

python实现MACD策略背离点的判断 (附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 665

完美解决Spring声明式事务不回滚的问题

编程式的事务管理 实际应用中很少使用 通过使用TransactionTemplate 手动管理事务 声明式的事务管理 开发中推荐使用(代码侵入最少) Spring的声明式事务是通过AOP实现的 主要掌握声明式的事务管理。 spring事务不回滚的两个原因 总结一下导致事务不回滚的两个原因,一是Service类内部方法调用,二是try...catch异常。 1. Service类内...

xjk201的博客 1047

Microsemi Libero使用技巧11——CoreUARTAPB RX管脚分配时不显示

调用串口IP核CoreUARTAPB,并例化到顶层设计,发现UART_RX管脚在进行管脚分配时没有显示出来,最后发现是CoreAPB3总线IP核配置不对导致,改为如下配置后正常。

whik1194的博客 756

YOLOv11在STM32H7上的MCU部署实战:基于CMSIS-NN的高效推理实现

嵌入式AI与MCU部署技术解析 本文系统介绍了基于STM32H7微控制器的YOLOv11模型部署方案。主要内容包括: 边缘计算背景下MCU的AI部署优势与挑战,重点分析了STM32H7平台特性 YOLOv11模型的结构优化,包括E-ELAN骨干网络和Meta-ACON激活函数等改进 CMSIS-NN加速库的架构原理,在STM32H743上可实现5.4倍卷积加速 完整的开发环境搭建流程,涵盖硬件选型、工具链配置和模型转换 模型优化关键技术,包括int8量化、剪枝和内存占用优化等 实验表明,该方案在保持模型精度

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 853

事务回滚失败的场景和原因

Java开发中遇到事务回滚失败,可以考虑从以下列表中寻找原因: 数据库引擎是否支持事务(Mysql的MyIsam引擎就不支持事务) 注解所在的类是否注入spring容器中 注解所在方法是否为public修饰或者final(方法实现了接口是否为public,方法没有实现接口是否为final) 分析:这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。 @Transa

m0_46120463的博客 1915

基于加速科技ST2500的SN74HC00N芯片测试计划

实际上随着工艺的进步,器件内部和引脚间的绝缘氧化膜越来越薄,导致漏电流发生的概率更大,另外制造过程中的工艺缺陷导致的桥接,异物或封装过程中造成的芯片划伤、引裂,都会造成IC的漏电流偏大,有部分产品可能会表现出漏电流偏大,但功能正常,此类产品具有潜在的可靠性问题,漏电流测试的目的就是把具有此类缺陷的产品筛选出来,避免其流到最终产品造成更大的损失。漏电流的测试方法相对简单,就是根据产品手册或测试规范对被测引脚施加额定的电压,然后测量其输入或流出的电流是否符合相应的设计规范。74HC00引脚功能如表所示。

weixin_68288412的博客 1431

SprinBoot回滚事务

一.Controller要回滚事务,当然不推荐,一般在service使用事务 @Transactional(rollbackFor = Exception.class) @PostMapping("/add") public AjaxResult addSave(CourseOrder courseOrder) throws SchedulerException, TaskException 使用上图所示来回滚事务,会发现事务并没有回滚 解决: 默认spring事务只在发生未被捕

老王的博客 210

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

一句话回答“Spring的事务什么情况下会失效?”

在上面的例子中,如果doSomethingRisky方法抛出了RuntimeException,并且它在performTransaction方法中没有被捕获或者处理,Spring会自动回滚事务。如果一个方法是@Transactional注解的,但它内部调用了另一个没有@Transactional注解的方法,事务就会失效。作为Java开发者,深入理解这些可能导致事务失效的场景,不仅能助你在开发中有效规避问题,还能在面试中彰显你对Spring事务管理的深刻认识。事务传播属性,这意味着它会启动一个全新的事务。

x1ao_fe1的博客 596

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spring Boot 事务失效的常见坑,我一次性给你讲清楚

私有方法上放注解— 代理不了,事务无效同一类中自调用— 不经过代理,事务无效异常被 catch 吞掉— Spring 感知不到,不会回滚传播行为配错了— 内部调用导致传播行为失效事务生效的关键是 AOP 代理,只要记住这一点,所有事务失效的问题都能找到根源。建议大家写完带的方法后,一定一定要测试一下异常情况下能不能回滚,别像我一样踩坑踩三次才长记性。有任何问题评论区见!

聚焦学生开发者需求,分享课设毕设项目实战经验、系统开发技巧、数据库设计规范及文档排版实用方法。 704

为什么你的@Transactional事务没有回滚?从内部调用失效到掌握事务之道

我不是加了@Transactional注解吗,怎么数据又没回滚。要是有一个仁厚、正直、诚信、谦和、忠恕、清廉、高洁、温润、儒雅、端方、恭谨、庄重、内敛、沉稳、睿智、豁达、淡泊、温良、恭俭、谦让、坦荡、中和、包容、自律、慎独的Java高手帮我排查就好了

2402_89042144的博客 1357

Spring事务管理:从配置到实践(附事务配置代码)

Spring事务管理通过声明式和编程式两种方式确保数据库操作的一致性。声明式事务基于AOP,使用@Transactional注解实现自动事务控制;编程式事务则通过TransactionTemplate手动管理。配置事务管理器后,结合注解属性设置传播行为和隔离级别,并通过测试验证事务功能。示例代码展示了从依赖配置到测试的完整实现流程。

fykam的博客 1234

解决seata和mybatis-plus事物不回滚问题

seata整合mybatis-plus,事物不回滚,解决方案

dxcll的博客 3366

Seata事务突然不生效了?别慌,手把手教你排查@GlobalTransactional失效的N种原因(附配置清单)

本文深入解析Seata分布式事务框架中@GlobalTransactional注解失效的七大常见原因,并提供从日志分析到配置优化的完整解决方案。涵盖注解扫描问题、客户端配置错误、动态配置覆盖等高频故障场景,附赠经过百万级交易验证的配置清单和性能调优建议,帮助开发者快速定位并解决事务失效问题。

weixin_30847939的博客 609

【springboot 多数据源下,开启事务后,数据源切换失败】

当我们配置了事物管理器和拦截Service中的方法后,每次执行Service中方法前会开启一个事务,并且同时会缓存一些东西:DataSource、SqlSessionFactory、Connection等,所以,我们在外面再怎么设置要求切换数据源也没用,因为Conneciton都是从缓存中拿的,所以我们要想能够顺利的切换数据源,实际就是能够动态的根据DatabaseType获取不同的Connection,并且要求不能影响整个事物的特性。

m0_46459413的博客 2545

SpringBoot2异常处理回滚事务详解(自动回滚/手动回滚/部分回滚)

1 问题背景 有时候,我们总是需要再SpringBoot2中对一个Service方法做一个完整的事务,发现异常时,进行回滚,然后又能返回错误信息。 事务定义 事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多...

zzhongcy的专栏 5万+

Spring Boot 各种事务操作实战(自动回滚、手动回滚、部分回滚)

事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。

LoveSummer 2万+

详解spring事务失效和回滚失败的场景

详解spring事务失效的12种场景详解spring事务失效的12种场景前言一 事务不生效1.访问权限问题2. 方法用final修饰3.方法内部调用3.1 新加一个Service方法3.2 在该Service类中注入自己3.3 通过AopContent类4.未被spring管理5.多线程调用6.表不支持事务7.未开启事务二 事务不回滚1.错误的传播特性2.自己吞了异常3.手动抛了别的异常4.自定义了回滚异常5.嵌套事务回滚多了三 大事务与编程式事务1 大事务问题2 编程式事务 详解spring事务失效的12

意田天的博客 1万+

spring手动开启事务,手动提交事务,手动回滚事务

1.未加事务注解(或者事务配置), 所以需要手动开启事务和手动提交事务和手动回滚事务 @Autowired private PlatformTransactionManager txManager; @Autowired private ShopGroupBuyDao shopGroupBuyDao; @GetMapping(value = "/transactionDemo") public void ceshi() { // 手动开启事务 start De

小林子的博客 2万+

Spring中事务回滚失败的解决方案

Spring中事务回滚失败解决方案 前言        事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transac...

东哥_Jeffery的博客 4203
上一篇: FastDFS单机配置
下一篇: mysql explain执行计划
牧竹子
博客等级 码龄17年 572粉丝 233原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值