我正在尝试将某些内容写入我的数据库,但尽管它报告了“已成功完成的请求”,但它无法正常工作。成功之后,一切似乎都运行良好,我的控制器正确地重定向我。
调试
DEBUG a.d.p.payment.PaymentServiceImpl - Requesting to persist new user'max_test@test.com'.
DEBUG a.d.p.payment.model.PaymentDAOImpl - Persisting com.app.payment.model.PaymentUser@86ceb985.
DEBUG o.s.o.j.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13771737739
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'redirectForm'
DEBUG o.s.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'redirectForm'; URL [/WEB-INF/jsp/redirectForm.jsp]] in DispatcherServlet with name 'payment'
DEBUG o.s.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/jsp/redirectForm.jsp] in InternalResourceView 'redirectForm'
DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
appContext.xml(根上下文)
<context:annotation-config />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="username" value="test" />
<property name="password" value="test" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!--payment_test is the name of the schema -->
<property name="url" value="jdbc:mysql://test1.com:3306/payment_test" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="payment" />
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<context:component-scan base-package="com.app.payment" />
<context:annotation-config />
<!-- Auto scan the components -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
<tx:annotation-driven />
PaymentUser
@Entity
@Table(name="PaymentUser")
public class PaymentUser {
@Id
@GeneratedValue
private int id;
...
}
PaymentService
@Transactional("transactionManager")
@Service()
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentDAO paymentDAO;
// ... service methods
}
付款DAO
@Repository()
public class PaymentDAOImpl implements PaymentDAO {
//@PersistenceContext(unitName="payment")
@PersistenceContext()
EntityManager em;
}
似乎它甚至没有开始交易。希望有足够的信息让某人帮助我。谢谢你的帮助。
更新
获取数据工作正常。持久化(EntityManager em.persist()
)和删除(em.remove
)不起作用。可能有正确的问题。意思是只读权限而没有写权限,但在这种情况下我应该有一个错误。
更新2
将<aop:scoped-proxy />
添加到我的dataSource bean,但没有更改。就像我的调试消息说的那样
DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
没有交易,但我的交易应该从哪里开始?
我还检查了问题Spring: Annotation-driven Transaction Manager 但我不知道该怎么做。
新的appContext
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config />
<tx:annotation-driven />
<!-- Auto scan the components
<bean id="paymentDao" class="com.app.payment.model.PaymentDAOImpl" />
<bean id="paymentService" class="com.app.payment.PaymentServiceImpl" />
should do the same
-->
<context:component-scan base-package="com.appn.payment" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" lazy-init="false" destroy-method="close">
<aop:scoped-proxy />
<property name="username" value="user" />
<property name="password" value="pw" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://test1.com:3306/test" />
<!-- <property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />-->
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="payment" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
<property name="packagesToScan" value="com.app.payment" />
</bean>
<tx:annotation-driven />
</beans>
更新3
尝试刷新我的PaymentDAO em.flush()
,这会导致我收到错误消息。
javax.persistence.TransactionRequiredException: no transaction is in progress at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:792)
是:
public void flush() {
if ( !isTransactionInProgress() ) {
throw new TransactionRequiredException( "no transaction is in progress" );
}
try {
getSession().flush();
}
catch ( RuntimeException e ) {
throw convert( e );
}
}
我需要某种特殊会话吗? 还记录在我的控制器中
log.info("Is transaction active " + TransactionSynchronizationManager.isActualTransactionActive());
导致错误......不确定为什么没有活动交易...
更新4
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Repository
public class PaymentDAOImpl implements PaymentDAO {
private final Logger log = LoggerFactory.getLogger(getClass());
//@PersistenceContext()
@PersistenceContext(unitName="payment")
EntityManager em;
@Override
public void persist(PaymentUser user) {
log.debug("Persisting {}.", user);
em.persist(user);
//em.flush();
}
@Override
public void remove(PaymentUser user) {
log.debug("Removing {}.", user);
em.remove(user);
}
@Override
public List<PaymentUser> getPaymentUsers() {
log.debug("Fetching payment users.");
return em.createQuery("FROM PaymentUser", PaymentUser.class).getResultList();
}
@Override
public PaymentUser getPaymentUserById(String userId) {
log.debug("Fetching payment users with id '{}'.",userId);
return em.createQuery(
"FROM PaymentUser WHERE userId = :userId", PaymentUser.class)
.setParameter("userId", userId).getSingleResult();
}
@Override
public void removePaymentUserById(String userId) {
log.debug("Removing payment users with id '{}'.",userId);
em.createQuery("DELETE FROM PaymentUser WHERE userId = :userId ", PaymentUser.class).
setParameter("userId", userId).executeUpdate();
}
@Override
public void mergePaymentUser(PaymentUser user) {
log.debug("Merging payment user '{}'.",user);
em.merge(user);
}
}
更新5
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- springapp servlet -->
<servlet>
<servlet-name>payment</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>payment</servlet-name>
<url-pattern>/payment/*</url-pattern>
<url-pattern>/paymentExternalData</url-pattern>
<url-pattern>/paymentInternalData</url-pattern>
</servlet-mapping>
<!-- Welcome files -->
<welcome-file-list>
<welcome-file>payment.jsp</welcome-file>
<welcome-file>payment.html</welcome-file>
</welcome-file-list>
<!-- S P R I N G -->
<!-- Add Support for Spring -->
<!-- Default applicationContext location: /WEB-INF/applicationContext.xml -->
<!-- UTF-8 filter -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
更新6
付款servlet.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config />
<tx:annotation-driven />
<!-- Auto scan the components -->
<context:component-scan base-package="com.app.payment" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
appContext.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" lazy-init="false" destroy-method="close">
<aop:scoped-proxy />
<property name="username" value="test" />
<property name="password" value="test" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://test1.com/test" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="payment" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitManager">
<bean class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
</beans>
答案 0 :(得分:3)
确保两个xml配置中没有完全重复的<context:component-scan .../>
元素。如果你有这个,你基本上复制了所有的bean实例。您最初拥有的是ContextLoaderListener
加载的所有bean,并且由于<tx:annotation-driven />
的存在而被代理。
现在,如果您的payment-servlet.xml中有相同的<context:component-scan .../>
,那么将再次扫描所有创建另一个实例的bean,但是由于没有<tx:annotation-driven />
它将会不被代理,也没有应用任何交易。
现在发生的是,只要您需要一个@Service
带注释的bean,DispatcherServlet
首先会查找自己的ApplicationContext
,看看是否有bean来满足其需求。如果它将被使用(您当前的情况),如果没有它将查询父上下文(由ContextLoaderListener
加载的那个)。
您需要做的是配置ContextLoaderListener
以扫描所有但是 @Controller
带注释的bean以及DispatcherServlet
来扫描 ONLY for @Controller
带注释的bean。这可以通过正确配置<context:component-scan .../>
来完成。
的applicationContext.xml
<context:component-scan base-package="com.appn.payment">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
付款servlet.xml中
<context:component-scan base-package="com.appn.payment" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
这将为您提供事务,并且只为您的bean提供单个实例。您应该从payment-servlet.xml文件中删除<tx:annotation-driven />
。
参考指南中还有一个开放的JIRA issue。也是Spring Community Forums中解释此问题的一个主题。
答案 1 :(得分:2)
再次查看您的applicationContext.xml,我注意到您没有使用您的transactionManager声明分配entityManager。我不确定Spring是否会隐式设置它,但如果它不能解释为什么你的坚持不起作用。
例如,更改:
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager" />
to
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<强>更新强>
我只使用容器管理的实体配置了Spring + JPA(看起来也是你的意图) - 从来没有真正的应用程序管理。据我所知,在使用Spring进行Container管理时,您并不需要配置持久单元。我不是100%确定这是否有帮助,但尝试更改在applicationContext.xml中声明entityManagerFactory的方式。
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.app.payment" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hiberate.show_sql">true</prop>
... //additional props
</props>
</property>
</bean>
答案 2 :(得分:1)
使用注释驱动的事务时,应该在使用数据库的方法之前放置@Transactional
注释。它可以是您的DAO或服务方法。我可以看到您已将@Transactional
置于PaymentServiceImpl
之上,但这不是该注释的正确位置。
答案 3 :(得分:0)
您似乎在DAO实现类的开头错过了@Transactional注释。这可以解释为什么你没有打开任何交易。
如果还不足以解决您的问题,您能否给我们完整的DAO实施课程?
答案 4 :(得分:0)
设法找到问题所在。 Spring Docu“@EnableTransactionManagement只在与bean定义的相同应用程序上下文中查找@Transactional。”在我的payment-servlet.xml中我没有<tx:annotation-driven />
这就是为什么没有活动的交易。
答案 5 :(得分:0)
创建transactionManager bean后,您应该在Xml文件中启用该事务,
&LT; tx:annotation-driven transaction-manager =“transactionManager”/&gt;
或
&LT; tx:注释驱动/&gt;
如果你写了第二个,那么你必须在DAO类中使用@Transaction(),
如果任何方法在写入之前需要事务
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
它告诉事务是require,readOnly = false意味着你可以读写数据。