java - Spring JPA 的@transactional 注释不起作用

标签 java spring hibernate jpa annotations

我遇到了交易问题。我使用 Spring Jpa(1.8.2)、Hibernate(4.3)、MariaDB、Jboss EAP 6.2。 我希望服务类中的方法 saveExample() 不会在表上写入任何内容,因为该方法会抛出异常并进行回滚。

这是我的代码: 持久性.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="fooPU">
    .........
        <class>ExampleCass</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

服务.java

import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Transactional
public class ExampleService {
    private TableExampleRepository exampleRepo;
    private JpaTransactionManager transactionManager;

    @Autowired
    public ExampleService(TableExampleRepository exampleRepo) {
        this.exampleRepo = exampleRepo;
    }



    @Transactional(rollbackFor={Exception.class})
    public void saveExample(ExampleClass example ){

        exampleRepo.save(example);
        throw new RuntimeException("foo");

    }


}

根上下文.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:context="http://www.springframework.org/schema/context"
    xmlns:ldap="http://www.springframework.org/schema/ldap"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.7.xsd
        http://www.springframework.org/schema/ldap http://www.springframework.org/schema/ldap/spring-ldap-2.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">


    <context:property-placeholder
        location="file:///${jboss.modules.dir}/system/layers/base/...../foo.properties" />

     <jpa:repositories base-package="it.foo.repository"
        entity-manager-factory-ref="entityManagerFactory"
        transaction-manager-ref="transactionManager"/> 

    <bean id="entityManagerFactory" name="foo"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="datasource" /> 
        <property name="persistenceUnitName" value="fooPU" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >             
                <property name="showSql" value="false" />
                <property name="generateDdl" value="false" />
                <property name="database" value="MYSQL"/>
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            </bean>
        </property>
             </bean>    

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!-- Data Source -->
    <jee:jndi-lookup jndi-name="java:jboss/datasources/fooDS"
        id="datasource" expected-type="javax.sql.DataSource" />




    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="message" />
    </bean>

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

    <context:component-scan base-package="foo" />

</beans>

Controller .java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.core.env.Environment;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;

@Controller
@SessionAttributes("att1")
public class ExampleController extends ReportController {
    private ExampleService exampleService;

    @Autowired
    public ExampleController(ExampleService exampleService) {
        this.exampleService = exampleService;
    }
    .......
    @RequestMapping(value = "/salvaExample", method = RequestMethod.GET)
    public String visualizzaProspetto(@RequestParam ExampleClass example,Model model) {
        exampleService.saveExample( example); 
        return "page1";
    }
    .......
}   

编辑 1 这是我的 servlet-context.xml

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

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="foo" />

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/webjars/**" location="classpath:/WEB-INF/resources/webjars/" />

</beans:beans>

怎么了?

最佳答案

您的两个配置文件都包含以下行:

<context:component-scan base-package="foo" />

这一行完全按照它被告知的去做,它将扫描组件并且它会为 ContextLoaderListener 执行此操作。和 DispatcherServlet .这会产生 2 个 bean 实例。 ContextLoaderListener捡到的那个将应用适当的事务,因为在相同的上下文中是 <tx:annotation-driven />然而,对于 DispatcherServlet 中的实例,情况并非如此。

您的 Controller 将使用在最近的应用程序上下文中注册的 bean 实例,即由 DispatcherServlet 加载的实例。所以没有交易。

简而言之,在进行组件扫描时,您应该注意不要扫描相同的组件两次。如果你有一个非常广泛的 base-package要扫描,您可以使用包含和排除过滤器。

在你的root-context.xml使用以下内容

<context:component-scan base-package="foo">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

在你的servlet-context.xml使用以下内容。

<context:component-scan base-package="foo" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

关于java - Spring JPA 的@transactional 注释不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32444007/

相关文章:

java - 使用spring框架我们在哪里实现松耦合呢?

java - 由 : org. hibernate.AnnotationException 引起:@OneToOne 或 @ManyToOne on

java - 导航栏点击事件 - Android 应用程序

java - AsyncTask 直到最后才完成下载

spring - 通过使用Spring Data Elasticsearch查询多个字段来更新?

java - Hibernate 的重复键问题

java - where 子句中的子查询与 CriteriaQuery

java - 在另一个方法中使用一个方法的变量

java - 在数据库中存储多行字符串并在网页中显示它们

java - 是否有另一种方法可以从 Spring MVC 中的 HttpServletRequest 对象获取用户的时区?