它不应该工作。因为您从该类的另一个方法调用 updateSomeProperty(obj1) 并尝试更改默认事务行为(从 REQUIRED 到 REQUIRED_NEW)。但它不会起作用。这就是为什么发生异常时所有更改都将回滚的原因。
默认情况下,Spring 为接口创建代理,@Transactional 注释应该只用于公共方法。并且应该从“外部”调用此方法。如果您将从类中的另一个方法调用它们,则 @Transactional 注释将不起作用。
您还可以更改 xml 中事务的默认设置(查看属性 proxy-target-class 和 mode)。但我从未改变过这一点,也不记得它应该如何工作。
<tx:annotation-driven transaction-manager="txManager" mode="..." proxy-target-class="..."/>
编辑:
顺便一提。这是一篇关于交易陷阱的非常好的文章。它对我帮助很大。还有一些关于交易的其他非常有趣的文章。
编辑2:
再次问好。我认为我找到了解决您问题的方法。至少我对此进行了测试,它对我很有效。我建议您将事务模式更改为“AspectJ”,并为项目使用 AspectJ 编译时间。这将使您有可能从一个类中的另一个方法调用私有事务方法,并更改事务行为(对于已启动的嵌套事务)。在这种情况下,您可以在嵌套事务中提交一些更改,而外部事务将被回滚。为此,您需要执行以下步骤:
1)在事务定义中更改事务模式: - 如果您使用 xml 配置,则:
<tx:annotation-driven transaction-manager="txManager" mode="aspectj"/>
2)在pom中添加aspectj依赖:
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>${aspectj.version}</version>
</dependency>
3)在pom中添加spring-aspects依赖:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>3.1.2.RELEASE</version>
    <scope>compile</scope>
</dependency>
4) 添加 maven 插件,启用编译时 wieving:
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <configuration>
                <showWeaveInfo>true</showWeaveInfo>
                <source>${compiler.version}</source>
                <target>${compiler.version}</target>
                <Xlint>ignore</Xlint>
                <complianceLevel>${compiler.version}</complianceLevel>
                <encoding>UTF-8</encoding>
                <verbose>false</verbose>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <!-- <goal>test-compile</goal> -->
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
5)我的 pom 中还有 maven 编译器插件,这就是为什么我认为你最好也添加它:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerVersion>${compiler.version}</compilerVersion>
        <fork>true</fork>
        <source>1.7</source>
        <target>1.7</target>
    </configuration>
</plugin>
*注意:我使用 jdk 1.7+ 版本。我的编译器和aspectj版本是sush:
<compiler.version>1.7</compiler.version>
<aspectj.version>1.6.12</aspectj.version>
我也有其他库的此类版本(但我认为这不是必需的):
<org.springframework.version>3.1.0.RELEASE</org.springframework.version>
<org.hibernate.version>4.1.0.Final</org.hibernate.version>
<org.springdata.version>1.0.2.RELEASE</org.springdata.version>
您也可以尝试在 spring 中使用加载时间,但它更难配置(这是我的观点),不建议在生产中使用(正如我在几篇文章中读到的)。但是如果你决定使用它,你可以在 web 和 spring 参考文档中找到很多信息。
如果你想在没有 maven 的情况下使用编译时间,那么我不知道如何配置它。(我只用 Maven 测试过)。您可以尝试在 web 中查找此类信息,但我不建议这样做,因为使用 maven 处理依赖项要容易得多(并且在此示例的情况下 - 添加必要的插件)。
这是我用于测试的示例:
- 一些界面: - 公共接口 TestClassInterface { - void testMethod();
 - } 
- 一些实现此接口的测试类: - @Transactional(propagation = Propagation.REQUIRED, rollbackFor=Exception.class) @Component public class TestClass implements TestClassInterface { - @Autowired
private SpringDataFooDAO fooDao;
public void testMethod() {
    try {
        Foo foo = fooDao.findOne(2L);
        System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
        System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
        foo.setName("should be rolled back");
        new ExceptionThrower().doSomething("default string");
    } catch(Exception e) {
        updateSomeProperty(1L, "Changed name");
        throw new RuntimeException(e);
    }
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
private void updateSomeProperty(long id, String newFooName) {
    System.out.println("   ---   ");
    System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
    System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
     // Update property of test object.
     Foo foo = fooDao.findOne(id);
     foo.setName(newFooName);    
}
 - } 
- 另一个具有引发异常的方法的类: - 公共类 ExceptionThrower { - public void doSomething(Object obj) throws Exception {
    throw new Exception();  
 }
 - } 
请注意,我从 catch 块中重新抛出异常(我将其作为运行时异常执行,因为我不需要在上层类中处理它)。这是正确的外部事务回滚所必需的。