交易“需要”春季繁殖

发布于 2025-01-04 23:50:45 字数 4233 浏览 1 评论 0原文

我是 Spring 新手,无法在“REQUIRED”模式下进行事务传播。

下面是一个示例:

@Controller
public class ExampleController
{
    @Autowired
    Foo foo;

    @Autowired
    Bar bar;

    @RequestMapping(value = "/example")
    public String submitForm(Model model) throws Exception
    {
        User user = new User("Joe", "Bloggs");
        user = foo.save(user);
        bar.simpleMethod(user);
        return "success";
    }
}

@Repository
public class Foo
{
    // A JPA repository
    private EntityManager em;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public User save(User user)
    {
        return this.em.merge(user);
    }

    @PersistenceContext
    void setEntityManager(EntityManager entityManager)
    {
        this.em = entityManager;
    }
}

public class Bar
{
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void simpleMethod(User user)
    {
        // Do something...
    }
}

applicationContext.xml(重要位):

<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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <context:property-placeholder location="/WEB-INF/jdbc.properties" />

    <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
        <constructor-arg>
            <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="${db.driverClassName}" />
                <property name="url" value="${db.url}" />
                <property name="username" value="${db.username}" />
                <property name="password" value="${db.password}" />
            </bean>
        </constructor-arg>
    </bean>

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
        <property name="showSql" value="${db.showSql}" />
        <property name="generateDdl" value="${db.generateDdl}" />
    </bean>

    <!-- enabling annotation driven configuration /-->
    <context:annotation-config />
    <context:component-scan base-package="my.package" />

    <!-- Instructs the container to look for beans with @Transactional and decorate them -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

    <!-- FactoryBean that creates the EntityManagerFactory  -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter" ref="jpaAdapter" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- A transaction manager for working with JPA EntityManagerFactories -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
</beans>

如果 bar.simpleMethod() 中发生异常,则不会滚动 foo.save(...)返回(或者也许是,但数据库肯定不是)。有谁知道为什么?

I'm new to Spring and I'm not able to make the transaction propagation in "REQUIRED" mode.

Here is an example:

@Controller
public class ExampleController
{
    @Autowired
    Foo foo;

    @Autowired
    Bar bar;

    @RequestMapping(value = "/example")
    public String submitForm(Model model) throws Exception
    {
        User user = new User("Joe", "Bloggs");
        user = foo.save(user);
        bar.simpleMethod(user);
        return "success";
    }
}

@Repository
public class Foo
{
    // A JPA repository
    private EntityManager em;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public User save(User user)
    {
        return this.em.merge(user);
    }

    @PersistenceContext
    void setEntityManager(EntityManager entityManager)
    {
        this.em = entityManager;
    }
}

public class Bar
{
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void simpleMethod(User user)
    {
        // Do something...
    }
}

The applicationContext.xml (important bits):

<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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <context:property-placeholder location="/WEB-INF/jdbc.properties" />

    <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
        <constructor-arg>
            <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="${db.driverClassName}" />
                <property name="url" value="${db.url}" />
                <property name="username" value="${db.username}" />
                <property name="password" value="${db.password}" />
            </bean>
        </constructor-arg>
    </bean>

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
        <property name="showSql" value="${db.showSql}" />
        <property name="generateDdl" value="${db.generateDdl}" />
    </bean>

    <!-- enabling annotation driven configuration /-->
    <context:annotation-config />
    <context:component-scan base-package="my.package" />

    <!-- Instructs the container to look for beans with @Transactional and decorate them -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

    <!-- FactoryBean that creates the EntityManagerFactory  -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter" ref="jpaAdapter" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- A transaction manager for working with JPA EntityManagerFactories -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
</beans>

If an exception occours in bar.simpleMethod(), foo.save(...) is not rolled back (or maybe it is, but the database is certainly not). Does anyone know why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

⒈起吃苦の倖褔 2025-01-11 23:50:45

如果bar.simpleMethod()中发生异常,foo.save(...)不会回滚

,也不应该回滚 - 您已经包装了事务注释分别围绕 Bar.simpleMethodFoo.save,因此它们将作为两个单独的事务执行。如果 Bar.simpleMethod 失败,它会回滚自己的事务,但 Foo.save 的事务已经提交。没有单一交易涵盖这两者。

您需要将这两个操作封装在一个方法中,该方法在单个事务中执行这两个操作。最好通过引入一个由控制器调用的额外组件来完成。该方法将使用@Transactional进行注释,并执行Bar.simpleMethodFoo.saveBar.simpleMethodFoo.save 上的 @Transactional 注释将成为同一整体事务的一部分。

If an exception occours in bar.simpleMethod(), foo.save(...) is not rolled back

And neither it should be - you've wrapped your transaction annotations individually around Bar.simpleMethod and Foo.save, and so these will be performed as two separate transactions. If Bar.simpleMethod fails, it rolls back its own transaction, but Foo.save's transaction has already been committed. There's no single transaction covering both.

You need to encapsulate the two operations within a method that performs both operations in a single transaction. This is best done by introducing an extra component, which is invoked by the controller. This method would be annotated with @Transactional, and performs Bar.simpleMethod and Foo.save. The @Transactional annotations on Bar.simpleMethod and Foo.save will be made part of the same overall transaction.

最好是你 2025-01-11 23:50:45

这里有两个独立的交易。第一个已提交,第二个在异常时回滚。这里真的没什么奇怪的。要使这两个调用参与同一事务,您应该将它们放在一个用 @Transactional 注释的方法中。

You've got two independent transactions here. The first one is committed, the second one is rolled back upon exception. Nothing surprising here really. To make those two calls participate in the same transaction, you should place them in a single method annotated with @Transactional.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文