我们有一个使用Hibernate 5.1.0.Final和Java 8的Spring应用程序版本4.3.3.RELEASE 该应用程序有一个rmi接口,它将服务公开给Java胖客户端应用程序。该应用程序还公开了Spring Restful Webservices。 导致我们出现问题的服务被曝光为rmi服务和一个宁静的ws。将服务称为RMI非常有用,但调用restful ws会产生一个javax.persistence.TransactionRequiredException,如下所示。
我以为我在这里找到了这个问题的答案,但我似乎无法把事情弄清楚: Spring @Transactional not working
我们尝试过很多不同的事情,比如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
但我想这里的问题是我有两个spring-config文件但没有在springrest-config.xml中定义正确的东西。
有谁知道如何解决这个问题?
这是dao方法:
@Override
public void deleteFormReplyForInvitation(Long id) {
try {
entityManager.createQuery("DELETE FROM FormReply where id = " + id).executeUpdate();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
这是服务代码:
@Override
@Transactional
public String withdrawConsent(final String username, final Patient patient, final String method) {
try {
List<Invitation> invitations = invitationService.getInvitationsForPatient(patient);
for (Invitation invitation : invitations) {
if (invitation.getFormReply() != null) {
formReplyService.deleteFormReply(invitation.getFormReply().getId());
}
if (!invitation.getReminders().isEmpty()) {
reminderService.deleteReminders(invitation);
}
invitationService.deleteInvitation(invitation.getId());
}
eventlogService.deleteEventlog(patient);
EntryKind entryKind = entryKindService.getEntryKind(1);
eventlogService.addEventlog(patient, eventlogDataDeleted, entryKind, true, username);
addConsent(patient, method, username);
patient.setActive(false);
patientService.saveOrUpdatePatient(patient);
return "OK";
} catch (Exception e) {
logger.error("Feil oppstått i withdrawConsent.", e);
return "ERROR";
}
}
@Override
@Transactional
public String withdrawConsent(final String birthNumber, final String programCode) {
String encryptedPNR = encryptionService.encryptDBQ(birthNumber);
Cancertype cancertype = cancertypeService.getCancertypeByCode(programCode);
Patient aPatient = patientService.getPatient(encryptedPNR, cancertype);
return withdrawConsent("WebService", aPatient, "Webservice");
}
以下是其他控制器:
@RequestMapping(value = "/withdrawconsent", method = RequestMethod.GET)
@Transactional
String withdrawConsent(@RequestParam("programcode") final String programcode, @RequestParam("birthnumber") final String birthnumber) throws CancertypeException {
return consentService.withdrawConsent(birthnumber, programcode);
}
这是spring-config.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:tx="http://www.springframework.org/schema/tx" xmlns:util="http://camel.apache.org/schema/spring/v2.15"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"
default-autowire="byName">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="net.krg.proms" />
<context:annotation-config />
<!-- Define all property files here. Values will be available in all other spring config files. -->
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
<value>classpath:system.properties</value>
</list>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" name="EntityManagerFactory">
<property name="packagesToScan" value="net.krg.proms" />
<property name="persistenceUnitName" value="proms"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${db.show_sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="${db.dialect}" />
</bean>
</property>
</bean>
<!-- Values are defined in db.properties -->
<!--<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>net.krg.proms.domain.proms</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${db.dialect}</prop>
<prop key="hibernate.show_sql">${db.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${db.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" name="TransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
<property name="persistenceUnitName" value="proms"/>
</bean>
<bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" name="EntityManagerFactory2">
<property name="packagesToScan" value="net.krg.proms.domain.hdb" />
<property name="persistenceUnitName" value="hdb"></property>
<property name="dataSource" ref="dataSource2"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${db.hdb.show_sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="${db.hdb.dialect}" />
</bean>
</property>
</bean>
<!-- Values are defined in db.properties -->
<!--<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">-->
<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.hdb.driver}" />
<property name="url" value="${db.hdb.url}" />
<property name="username" value="${db.hdb.username}" />
<property name="password" value="${db.hdb.password}" />
</bean>
<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource2"/>
</bean>
<bean id="sessionFactory2" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
<property name="packagesToScan">
<list>
<value>net.krg.proms.domain.hdb</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${db.hdb.dialect}</prop>
<prop key="hibernate.show_sql">${db.hdb.show_sql}</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">${db.hdb.hbm2ddl.auto}</prop>-->
</props>
</property>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager" name="TransactionManager2">
<property name="entityManagerFactory" ref="entityManagerFactory2"></property>
<property name="persistenceUnitName" value="hdb"/>
</bean>
<tx:annotation-driven />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!--RMI starts Here-->
<!--this is the only bean that should be use expose all the needed RMI sercices which GUI will consume-->
<bean id="rmiServices" class="net.krg.proms.services.RMIServiceImpl"/>
<bean id="remoting_MessageSpecificationService_Proxy_Exporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="service" ref="rmiServices"/>
<property name="serviceInterface" value="net.krg.proms.rmiInterfaces.RMIServices"/>
<property name="serviceName" value="rmiServices"/>
<property name="registryPort" value="10998"/>
<property name="alwaysCreateRegistry" value="false"/>
</bean>
<!--RMI end here-->
<!--include camel configuraiton here -->
<!--load camel context-->
<import resource="camel-config.xml"/>
以下是spring-restful ws的配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="net.krg.proms.services" />
<context:annotation-config></context:annotation-config>
</beans>
这是web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/spring-config.xml</param-value>
</context-param>
<!---->
<!--ws-->
<servlet>
<servlet-name>springrest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springrest-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springrest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
我们用来调用网络服务i的网址 http://xxx-xxx-xxx:8080/proms-services-1.0-SNAPSHOT/withdrawconsent?birthnumber=01016512345&programcode=PR
调用rest-ws时的堆栈跟踪:
*36860 [http-nio-8080-exec-34] ERROR net.krg.proms.services.impl.ConsentServiceImpl - Feil oppst?tt i withdrawConsent.
java.lang.RuntimeException: javax.persistence.TransactionRequiredException: Executing an update/delete query
at net.krg.proms.dao.impl.FormReplyDaoImpl.deleteFormReplyForInvitation(FormReplyDaoImpl.java:61)
at net.krg.proms.services.impl.FormReplyServiceImpl.deleteFormReply(FormReplyServiceImpl.java:36)
at net.krg.proms.services.impl.ConsentServiceImpl.withdrawConsent(ConsentServiceImpl.java:72)
at net.krg.proms.services.impl.ConsentServiceImpl.withdrawConsent(ConsentServiceImpl.java:110)
at net.krg.proms.services.ws.krgcommon.PatientInfoController.withdrawConsent(PatientInfoController.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)*
答案 0 :(得分:0)
我不确定它会有所帮助,但据我所知,事务管理只属于服务层,也不属于持久性控制器。也许它会在通过rmi公开@Transaction方法时引起某种冲突。