Какая связь между @Transactional и каскадом? - PullRequest
2 голосов
/ 15 сентября 2011

Кажется, существует связь между наличием аннотации @Transactional в тесте Spring JUnit и каскадным отображением при сохранении / объединении сущности JPA2.

На данный момент у меня нет конфигурации, но, может быть, это кому-то здесь звонит?


Допустим простой случай объектов JPA на трех уровнях: объект A ссылается на объект класса B, а этот экземпляр класса B ссылается на экземпляр класса C.

A -> B -> C

Класс A выполняет каскадирование ALL для B. И B выполняет каскадирование ALL для C. И в классе C есть метод прослушивания событий, аннотированный @PrePersist и @PreUpdate. Он регистрирует сообщение, чтобы доказать, что каскад был сделан там.


Теперь измените сущность C каким-либо образом и попросите менеджера сущностей объединить или сохранить экземпляр A. Логически сущность C в конечном итоге также будет сохранена или объединена. Из-за каскадирования было установлено значение ALL от класса A до B до C.

Когда модульный тест Spring не аннотируется @Transactional, сообщение журнала из метода прослушивателя событий класса C печатает свое сообщение. OK.

Но если для указано с аннотацией @Transactional, сообщение вообще не печатается. И действительно, ничего не было передано в базу данных для класса C. Только для класса A. Следовательно, я пришел к выводу, что каскадирование не перешло из A в C.

Удаление аннотации устраняет проблему.


Кто-нибудь знает? :-) Логически я бы подумал, что транзакции и каскадирование - это две совершенно разные вещи.


Типичная конфигурация тестового набора:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-beans.xml")
@TransactionConfiguration
@Transactional
public class MyUnitTest {

...

  @Test
  public void testSomething() {}  

...

}

Извлечение конфигурационного файла Spring xml - ничего особенного, я думаю ...

  <context:annotation-config />

  <tx:annotation-driven transaction-manager="transactionManager" />

  <context:component-scan base-package="com.foo.bar"  />

  <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
    <property name="persistenceUnitName" value="bar" />
  </bean>

  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>

Извлечение из файла persistence.xml

<persistence-unit name="bar" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
      <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/bar" />
      <property name="hibernate.connection.username" value="bar" />
      <property name="hibernate.connection.password" value="pwd" />
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
      <property name="hibernate.hbm2ddl.auto" value="create"/>
      <property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
    </properties>
  </persistence-unit>

Библиотека

  • Spring 3.0.6 ORM / CONTEXT / TEST
  • Hibernate 3.6.7.Final
  • JUnit 4.9
  • JPA2

1 Ответ

0 голосов
/ 16 сентября 2011

Нашли это! Неправильное использование менеджера сущностей становилось плохим, когда транзакции были разрешены. Это не было связано с постоянством, но было сделано прямо перед этим. Вызывает упорство в некотором роде.

Я реализовал итератор результата запроса, для которого требовался EntityManager. Я думал, что смогу создать его из EntityManagerFactory jpaTemplate.

final EntityManager em = jpaTemplate.getEntityManagerFactory().createEntityManager();
return new QueryIterator<T>(em.createQuery("FROM Foo"));

Очевидно, нет. Похоже, EntityManager должен быть получен по-другому. Как описано ниже.

jpaTemplate.execute(new JpaCallback() {
  @Override
  public Object doInJpa(final EntityManager em) throws PersistenceException {
    return new QueryIterator<T>(em.createQuery("FROM Foo"));
  }
});

Теперь все работает нормально. Как и должно быть, независимо от того, присутствуют транзакции или нет. : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...