Объекты не сохраняются-Spring + Hibernate + JPA
я использую Spring + Hibernate + JPA, и у меня есть ситуация, когда я не могу заставить мои сущности сохраняться в базе данных. Я настроил класс обслуживания, который аннотируется с помощью @Transactional. Он использует DAO, который содержит введенный EntityManager. Когда я вызываю функцию на объекте Службы, я вижу кучу выбора для чтения, которое делает DAO, но никаких обновлений/удалений в результате слияний и удалений, выданных моим DAO. Конечно, что-то не так с моей установкой, но я не вижу он.
настойчивость.в XML
<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>
конфиг.в 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>
AccountService.java
@Service("accountService")
@Transactional(propagation=Propagation.REQUIRED)
public class AccountService {
private static final Logger log = Logger.getLogger(AccountService.class);
@Autowired
private UserDAO userDAO;
public void activateUser(String username, String activationCode) {
PendingActivation pendingActivation = userDAO.getPendingActivation(
username, activationCode);
Client client = pendingActivation.getClient();
if (!userDAO.removePendingActivation(pendingActivation)) {
log.warn("Unable to remove pending activation");
}
if (!userDAO.enableUser(client)) {
log.error("Unable to enable client");
return;
}
return;
}
}
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);
}
}
2 ответов
хорошо, я понял проблему. Мне потребовалась вечность, чтобы понять это и не иметь ничего общего с моей конфигурацией базы данных, поэтому я хочу помочь людям, у которых есть подобные проблемы.
в документации Spring указано следующее:
<tx:annotation-driven/>
только ищет @Транзакционный на бобах в том же контекст приложения определяется в. Это значит что, если вы кладете<tx:annotation-driven/>
в WebApplicationContext для DispatcherServlet, он только проверяет @Транзакций бобов контроллеры, а не ваши услуги. См. Раздел 15.2," DispatcherServlet" для более информация.
что не опубликовано в моем исходном сообщении, это мое определение сервлета, которое имеет следующие строки кода конфигурации:
myServlet.в XML
<context:annotation-config />
<context:component-scan base-package="com.myDomain.*" />
это приводит все аннотированные компоненты, включая контроллеры, службы и репозитории, в контекст сервлета вместо контекста приложения. И там лежит проблема. Когда весна ищет бобы с аннотацией @Transactional (из-за существования <tx:annotation-driven/>
в моей конфигурации.xml-файл) он ищет их в контексте приложения. И, основываясь на моей конфигурации, которая была опубликована в моем предыдущем потоке, нет никаких бобов, загружаемых в контекст моего приложения... они все в контексте сервлетов. Поэтому, когда мой сервлет вызывал бобы, аннотированные @Service & @ Transactional, это было используя бобы, которые не были обернуты прокси транзакций. Таким образом, никаких транзакций. Трюк (скорее, правильный способ) состоял в том, чтобы изменить мои файлы конфигурации следующим образом:
myServlet.в XML
<context:annotation-config />
<context:component-scan base-package="com.myDomain.servlets" />
config.в XML
<context:annotation-config />
<context:component-scan base-package="com.myDomain.dao" />
<context:component-scan base-package="com.myDomain.services" />
эта конфигурация гарантирует, что все контроллеры существуют в контексте сервлета, а транзакционные службы и репозитории существуют в контексте приложения,которым они и принадлежат. И, наконец, после многих бессонных ночей, моя база данных пишет никак не прекращаются.
мы можем предоставить контроллер в сервлет-контексте.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>
это гарантирует, что только контроллер существует только в контексте сервлета. В корневом контексте.xml используйте следующее
<context:component-scan base-package="com.myDomain">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
Это гарантирует, что компоненты, отличные от контроллера, существуют в контексте приложения. Я много искал это решение, так как без этого JPA не обновляла базу данных, надеюсь, это поможет кому-то