Я обучаю себя Spring 3.0, реализуя веб-приложение JavaEE, используя:
- Tomcat 7
- Spring 3.0, Безопасность 3.1
- JPA : EclipseLink 2.3.1
- MySQL 5.5, Connector / J 5.1
Моя проблема :
- Я настроил декларативное управление транзакциями на своем уровне обслуживания с помощью Spring AOP.
- (У меня также есть перехватчик ведения журнала Spring AOP, объявленный в том же месте.)
- Создание новых сущностей не является проблемой.
- Обновление существующие сущности - это!
Согласно журналу, сервисный метод возвращается до того, как транзакция начинается!
[org.springframework.orm.jpa.JpaTransactionManager] - <Using transaction object [org.springframework.orm.jpa.JpaTransactionManager$JpaTransactionObject@335f5e3a]>
[org.springframework.orm.jpa.JpaTransactionManager] - <Creating new transaction with name [org.snowjak.livesavegive.data.service.TagService.rename]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT>
[org.springframework.orm.jpa.JpaTransactionManager] - <Opened new EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@3a234c2f] for JPA transaction>
[org.springframework.orm.jpa.JpaTransactionManager] - <Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.JDBC4Connection@49116f61]>
[myproject.data.service.MyEntityService] - <Beginning method: rename>
[myproject.data.dao.MyEntityDao] - <Beginning method: get>
[myproject.data.dao.MyEntityDao] - <After method: get>
[myproject.data.dao.AbstractDao] - <Beginning method: update>
[myproject.data.dao.AbstractDao] - <After method: update>
[myproject.data.service.MyEntityService] - <After method: rename>
[org.springframework.orm.jpa.JpaTransactionManager] - <Triggering beforeCommit synchronization>
[org.springframework.orm.jpa.JpaTransactionManager] - <Triggering beforeCompletion synchronization>
[org.springframework.orm.jpa.JpaTransactionManager] - <Initiating transaction commit>
[org.springframework.orm.jpa.JpaTransactionManager] - <Committing JPA transaction on EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@3a234c2f]>
[org.springframework.orm.jpa.JpaTransactionManager] - <Triggering afterCommit synchronization>
[org.springframework.orm.jpa.JpaTransactionManager] - <Triggering afterCompletion synchronization>
[org.springframework.orm.jpa.JpaTransactionManager] - <Closing JPA EntityManager [org.eclipse.persistence.internal.jpa.EntityManagerImpl@3a234c2f] after transaction>
Эта неспособность к обновлению исчезает, если я делаю свои DAO транзакционными, а не сервисным уровнем.
- Но Власти говорят, что это плохой стиль.
Может кто-нибудь предложить любойуказатели / советы / хитрости / секреты гильдии?
Редактировать:
Я включил DEBUG
деталь для org.springframework в моем логгере;и я вижу, что, насколько я могу судить, транзакции в конце концов обрабатываются правильно, т. е. начинаются до и заканчиваются после рассматриваемого метода обслуживания.
У меня все еще есть проблема с обновлением, а именно.мои обновления не появляются ни в ПУ, ни в БД;теперь, почему это будет?...
Редактировать:
Я также заглянул в общий журнал MySQL во время попытки обновления.JPA, похоже, просто не выдает UPDATE
s в базу данных!
=================================================================================
Объекты:
Под myproject.data.entity
.Ничего особенного.Общие JPA.
@Entity
public class MyEntity implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
int id;
@Column(nullable=false, unique=true)
String name;
...
}
DAO:
Интерфейсы в myproject.data.dao
.
interface AbstractDao
@Repository
interface AbstractDao<T,K> extends Serializable {
public T get(K key);
public Collection<T> getAll();
public T save(T entity);
public T update(T entity);
}
interface MyEntityDao
@Repository
interface MyEntityDao extends AbstractDao<MyEntity, Integer> {
public MyEntity get(String name);
}
Реализация по myproject.data.dao.jpa
.
abstract class AbstractDaoJpa
@Repository
abstract class AbstractDaoJpa implements AbstractDao<T,K> {
protected EntityManager em;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
em = entityManager;
}
public T save(T entity) {
em.persist(entity);
return entity;
}
public T update(T entity) {
return em.merge(entity);
}
}
class MyEntityDaoJpa extends AbstractDaoJpa implements MyEntityDao
@Repository
class MyEntityDaoJpa extends AbstractDaoJpa<MyEntity,Integer> implements MyEntityDao {
@Override
public MyEntity get(Integer key) {
return em.find(MyEntity.class, key);
}
@Override
public MyEntity get(String name) {
return em.createQuery("select E from MyEntity E where E.name = :name", MyEntity.class).setParameter("name", name).getSingleResult();
}
...
}
Сервисный уровень:
Интерфейсы в myproject.data.service
interface EntityService
@Service
public interface EntityService<T> extends Serializable {
public Collection<T> getAll();
}
interface MyEntityService extends EntityService
@Service
public interface MyEntityService extends EntityService<MyEntity> {
public MyEntity create(String name);
public MyEntity get(String name);
public MyEntity rename(String name);
...
}
Реализация по myproject.data.service.impl
class MyEntityServiceImpl implements MyEntityService
@Service
public class MyEntityServiceImpl implements MyEntityService {
private MyEntityDao dao;
public MyEntityServiceImpl(MyEntityDao newDao) {
dao = newDao;
}
@Override
public MyEntity create(String name) {
MyEntity e = new MyEntity();
e.name = name;
...
return dao.save(e);
}
...
@Override
public MyEntity rename(String oldName, String newName) {
MyEntity e = dao.get(oldName);
e.name = newName;
dao.update(e); // An attempt to fix by explicitly merging the modified entity.
// Didn't fix the problem.
return e;
}
...
}
Пружинная конфигурация:
...
[ Declaration of DAOs and Service beans. Appropriate DAOs are injected into Service beans. ]
...
<!-- Tomcat-managed DataSource lookup via JNDI -->
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDS"/>
<!-- Configure the EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"/>
</property>
</bean>
<!-- Create the Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- Configure the Transaction Manager for AOP -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- Some methods are read-only. -->
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
<!-- All others, use defaults. -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
...
<!-- Configure Spring AOP -->
<aop:config>
<aop:pointcut id="wholeProject" expression="within(myproject..*)"/>
<aop:pointcut id="serviceLayerOperation" expression="execution(* myproject.data.service.*.*(..))"/>
<!-- Configure transaction management. -->
<aop:advisor advice-ref="txAdvice" order="1" pointcut-ref="serviceLayerOperation"/>
<!-- Configure logging interceptor. -->
...
</aop:config>