我遇到了交易问题。我使用Spring Jpa(1.8.2),Hibernate(4.3),MariaDB,Jboss EAP 6.2。 我希望服务类中的saveExample()方法不会在表上写任何内容,因为该方法会抛出异常并进行回滚。
这是我的代码: 的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";
}
.......
}
编辑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>
有什么问题?
答案 0 :(得分:3)
您的配置文件都包含以下行:
<context:component-scan base-package="foo" />
这一行完全按照它所要求的方式执行,它将扫描组件,它将为ContextLoaderListener
和DispatcherServlet
执行此操作。这导致2个bean实例。 ContextLoaderListener
选择的那个将应用正确的事务,因为在同一个上下文中是<tx:annotation-driven />
,但是`DispatcherServlet中的实例不是这种情况。
您的控制器将使用在最近的应用程序上下文中注册的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>