2015-09-07 3 views
1

У меня проблема с транзакциями. Я использую Spring Jpa (1.8.2), Hibernate (4.3), MariaDB, Jboss EAP 6.2. Я ожидаю, что метод saveExample() в классе службы не будет ничего писать в таблице, потому что метод исключает и выполняет откат.@transactional аннотация Spring JPA не работает

Это мой код: persistence.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> 

Service.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"); 

    } 


} 

корня context.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"; 
    } 
    ....... 
} 

EDIT 1 это мой сервлет-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> 

Что не так?

+1

Как вы называете saveExample()? –

+0

Из контроллера Spring (@Controller) –

+0

Можем ли мы увидеть код? –

ответ

3

Обе ваши файлы конфигурации содержат следующую строку:

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

Эта линия делает именно то, что он сказал, чтобы сделать это будет сканировать компонентов, и он будет делать это как ContextLoaderListener и DispatcherServlet. Это приводит к 2 экземплярам bean. Тот, который был выбран ContextLoaderListener, будет иметь соответствующие транзакции, потому что в этом же контексте есть <tx:annotation-driven />, однако это не относится к экземпляру в `DispatcherServlet.

Ваши контроллеры будут использовать экземпляр компонента, зарегистрированный в ближайшем окружении приложения, тот, который загружается 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> 
Смежные вопросы