Hibernate 实体不持久-Spring+;冬眠+;JPA
我使用的是Spring+Hibernate+JPA,我遇到了无法让实体持久化到数据库的情况。我已经设置了一个用@Transactional注释的服务类。它使用包含注入的EntityManager的DAO。当我调用服务对象上的函数时,我看到DAO正在执行一系列的读取选择,但是没有由于DAO发出的合并和删除而进行更新/删除。我的设置肯定有问题,但我看不出来 persistence.xmlHibernate 实体不持久-Spring+;冬眠+;JPA,hibernate,spring,transactions,entitymanager,transactional,Hibernate,Spring,Transactions,Entitymanager,Transactional,我使用的是Spring+Hibernate+JPA,我遇到了无法让实体持久化到数据库的情况。我已经设置了一个用@Transactional注释的服务类。它使用包含注入的EntityManager的DAO。当我调用服务对象上的函数时,我看到DAO正在执行一系列的读取选择,但是没有由于DAO发出的合并和删除而进行更新/删除。我的设置肯定有问题,但我看不出来 persistence.xml <persistence xmlns="http://java.sun.com/xml/ns/persis
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="pu">
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.InformixDialect" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider" />
<property name="hibernate.showsql" value="true" />
<property name="hibernate.cache.use_second_level_cache"
value="false" />
</properties>
</persistence-unit>
UserDAOImpl.java
@Repository("userDAO")
public class UserDAOImpl implements UserDAO, Serializable {
private static final long serialVersionUID = 1L;
private static Logger log = Logger.getLogger(UserDAOImpl.class);
@PersistenceContext
EntityManager em;
@Override
public PendingActivation getPendingActivation(String username, String activationCode) {
Query q = em.createNamedQuery("getActivationCode")
.setParameter("activationCode", activationCode);
PendingActivation pendingActivation = null;
try {
pendingActivation = (PendingActivation)q.getSingleResult();
return pendingActivation;
}
catch (Exception e) {
log.warn("Could not retrieve activation code " + activationCode + " for user " + username, e);
return null;
}
}
@Override
public boolean enableUser(Client client) {
try {
client.setEnabled(true);
client = em.merge(client); // this never generates an update
}
catch(Exception e) {
log.error("Unable to enable client: " + client.getUsername(), e);
return false;
}
return true;
}
@Override
public boolean removePendingActivation(PendingActivation pendingActivation) {
try {
pendingActivation = (PendingActivation)em.getReference(PendingActivation.class, pendingActivation.getPendingActivationId());
em.remove(pendingActivation); // this never generates a delete
}
catch(Exception e) {
log.warn("Unable to remove activation: " + pendingActivation.getActivationCode(), e);
return false;
}
return true;
}
}
AccountActivationController.java
@Controller
public class AccountActivationController {
@Autowired
@Qualifier("accountService")
AccountService accountService;
@RequestMapping("activate.do")
public String doActivate(
@RequestParam("activationCode") String activationCode,
@RequestParam("username") String username,
ModelMap model) {
UnitCriteria unitCriteria = accountService.activateUser(username, activationCode);
if (unitCriteria == null) {
return "account/activationError";
}
model.addAttribute("fromActivation", true);
return "forward:search.do?" + unitCriteria.toUrlParams(true);
}
}
好的,我解决了问题。我花了很长时间才弄明白,与我的数据库配置无关,所以我想帮助有类似问题的人 Spring文档说明了以下内容:
只查找
@同一环境中bean上的事务
它是在应用程序上下文中定义的。
这意味着,如果你把
在
应用程序的WebApplicationContext
DispatcherServlet,它只检查
@您的应用程序中的事务bean
控制器,而不是您的服务。
见第15.2节“本文件”
DispatcherServlet“了解更多信息
信息
我的原始帖子中没有发布的是我的servlet定义,它有以下几行配置代码:
myServlet.xml
<context:annotation-config />
<context:component-scan base-package="com.myDomain.*" />
<context:annotation-config />
<context:component-scan base-package="com.myDomain.servlets" />
这会将所有带注释的bean(包括控制器、服务和存储库)带入servlet上下文,而不是应用程序上下文。这就是问题所在。当Spring查找带有@Transactional注释的bean时(由于我的config.xml文件中存在
),它是在应用程序上下文中查找它们。而且,根据我在前一个线程中发布的配置,没有bean加载到我的应用程序上下文中。。。它们都在servlet上下文中。因此,当我的servlet调用带有@Service&@Transactional注释的bean时,它使用的是未被事务代理包装的bean。因此,没有交易。诀窍(更确切地说,是正确的方法)是以以下方式更改我的配置文件:
myServlet.xml
<context:annotation-config />
<context:component-scan base-package="com.myDomain.*" />
<context:annotation-config />
<context:component-scan base-package="com.myDomain.servlets" />
config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/testdb" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="pu" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<context:annotation-config/>
</beans>
<context:annotation-config />
<context:component-scan base-package="com.myDomain.dao" />
<context:component-scan base-package="com.myDomain.services" />
此配置确保所有控制器都存在于servlet上下文中,事务服务和存储库存在于应用程序上下文中,而应用程序上下文正是它们所属的位置。最后,在经历了许多不眠之夜之后,我的数据库写操作仍在继续。我们可以在servlet-context.xml中提供如下控制器
<context:component-scan base-package="com.myDomain" use-default-filters="false" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
这将确保只有控制器存在于servlet上下文中。
在root-context.xml中,使用以下命令
<context:component-scan base-package="com.myDomain">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
这将确保应用程序上下文中存在控制器以外的组件。我搜索了很多这个解决方案,因为没有这个JPA就不能更新数据库,希望这能帮助别人你从哪里调用activateUser?我从servlet调用它。我已将代码添加到原始帖子中。谢谢谢谢-我已经为这个问题挣扎了一段时间,这让我保持了一些理智。