[英]Spring application doesn't appear to be persisting data
我正在嘗試將一些內容寫入我的數據庫,但盡管報告“已成功完成請求”,但它仍無法正常工作。 成功之后,一切似乎都運行良好,我的控制器正確地重定向我。
調試
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;
}
似乎它甚至沒有開始交易。 希望有足夠的信息讓某人幫助我。 謝謝你的幫助。
UPDATE
獲取數據工作正常。 持久化(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>
確保在兩個xml配置中沒有完全重復的<context:component-scan .../>
元素。 如果你有這個,你基本上復制了所有的bean實例。 你最初擁有的是所有bean都被ContextLoaderListener
加載,並且由於<tx:annotation-driven />
的存在而被代理。
現在,如果您的payment-servlet.xml中有相同的<context:component-scan .../>
,那么將再次掃描所有創建另一個實例的bean,但是由於沒有<tx:annotation-driven />
它不會被代理,也不會應用任何交易。
現在發生的是,只要您需要一個@Service
注釋bean, DispatcherServlet
首先會在自己的ApplicationContext
中查看是否有bean來滿足其需求。 如果它將被使用(您當前的情況),如果沒有它將查詢父上下文(由ContextLoaderListener
加載的那個)。
您需要做的是配置ContextLoaderListener
以掃描所有內容但是 @Controller
注釋bean和DispatcherServlet
僅掃描@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問題 ,將其包含在參考指南中。 也是Spring社區論壇中的一個主題解釋了這一點。
再次查看您的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>
UPDATE
我只使用容器管理的實體配置了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>
使用注釋驅動的事務時,應該在使用數據庫的方法之前放置@Transactional
注釋。 它可以是您的DAO或服務方法。 我可以看到你已經將@Transactional
置於PaymentServiceImpl
之上,但這不是該注釋的正確位置。
看來你在DAO實現類的開頭就錯過了@Transactional注釋。 它可以解釋為什么你沒有打開任何交易。
如果它不足以解決您的問題,您能否給我們完整的DAO實施課程?
設法找到問題。 Spring Docu “@EnableTransactionManagement只在bean中查找它們所定義的相同應用程序上下文中的@Transactional。” 在我的payment-servlet.xml中我沒有<tx:annotation-driven />
這就是沒有活動事務的原因。
在創建transactionManager bean之后,你應該在Xml文件中啟用事務,
<tx:annotation-driven transaction-manager =“transactionManager”/>
要么
<tx:annotation-driven />
如果你寫了第二個,那么你必須在你的DAO類中使用@Transaction(),
如果任何方法在寫入之前需要事務
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
它告訴事務是require,readOnly = false意味着你可以讀寫數據。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.