Я рассмотрел проблему при попытке запустить @NamedQuery с пейджингом из репозитория Spring Data. класса Лица выглядит следующим образом:Spring Data JPA: транзакция отложенных запросов на страницы данных
@NamedQueries({
@NamedQuery(
name = "Customer.findByNamePattern",
query = "select c from Customer c where c.name like :pattern"
)
})
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
private String name;
интерфейс репозиторий:
public interface CustomerRepository extends JpaRepository<Customer, Long> {
//@Query("select c from Customer c where c.name like :pattern")
Page<Customer> findByNamePattern(@Param("pattern") String pattern,Pageable pageable);
}
Когда я пытаюсь вызвать страничное хранилище методов из нетранзакционного контекста (JUnit), он отлично работает.
Когда я называю это из метода транзакционного обслуживания, как:
@Service("customerService")
@Transactional
public class CustomerServiceImpl implements CustomerService {
private static Logger log = Logger.getLogger(CustomerServiceImpl.class.getName());
@Autowired
private CustomerRepository customerRepository;
@Transactional(readOnly = true)
public Page<Customer> findAllPaged(int pageNum, int pageSize) {
PageRequest pr = new PageRequest(pageNum,pageSize);
return customerRepository.findAll(pr);
}
@Transactional(readOnly = true)
public Page<Customer> findByNamePatternPaged(String keyword, int pageNum, int pageSize) {
PageRequest pr = new PageRequest(pageNum,pageSize);
String pattern = "%"+keyword+"%";
return customerRepository.findByNamePattern(pattern, pr);
}
... вызова findAllPaged()
снова работает нормально.
Однако, когда я пытаюсь вызвать метод, который следует использовать именованный запрос, я всегда получаю исключение:
javax.persistence.RollbackException
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:524)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy35.findByNamePatternPaged(Unknown Source)
at datapagedquery.service.TestCustomerService.testFindByPatternPaged(TestCustomerService.java:36)
...
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:74)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
... 33 more
Использования org.springframework.data.jpa.repository.Query
аннотацию на методе репозитория отлично работает снова из транзакционного контекста.
Через некоторое время отладки, кажется, что эта проблема вызвана в org.springframework.data.jpa.repository.query.NamedQuery
, в doCreateCountQuery()
и hasNamedQuery()
:
@Override
protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
EntityManager em = getEntityManager();
TypedQuery<Long> countQuery = null;
if (hasNamedQuery(em, countQueryName)) {
countQuery = em.createNamedQuery(countQueryName, Long.class);
} else {
Query query = createQuery(values);
String queryString = extractor.extractQueryString(query);
countQuery = em.createQuery(QueryUtils.createCountQueryFor(queryString, countProjection), Long.class);
}
return createBinder(values).bind(countQuery);
}
private static boolean hasNamedQuery(EntityManager em, String queryName) {
try {
em.createNamedQuery(queryName);
return true;
} catch (IllegalArgumentException e) {
LOG.debug("Did not find named query {}", queryName);
return false;
}
}
Он пытается создать TypedQuery
из сгенерированного имени Customer.findByNamePattern.count
, который не существует в репозиторий запросов EntityManager. hasNamedQuery()
проверяет его, бросает бросок IllegalArgumentException
, и создает его по-другому. Проблема заключается в том, что, хотя IllegalArgumentException
поймана, транзакция откатывается
я нашел следующие обходные пути (иногда!):
с использованием
org.springframework.data.jpa.repository.Query
аннотацию хранилища методомИЛИ- создавая еще один именованный запрос
@NamedQuery( name = "Customer.findByNamePattern.count", query = "select count(c.id) from Customer c where c.name like :pattern" ),
Что не ясно для меня:
- вызова
findAll()
должен вызывать тот же вопрос, но оно не. Зачем? - с использованием
org.springframework.data.jpa.repository.Query
вместо@NamedQuery
также не вызывает проблемы, почему? - Как я могу использовать @NamedQuery с возможностью страницы, из контекста транзакции, чтобы избежать проблемы (и не создавать явно запрос на счет)?
Любая помощь будет оценена!
UPDATE
используемые варианты были: Spring: 4.0.5.RELEASE весна-данные: 1.6.0.RELEASE, 1.7.0.RELEASE Спящий 4.3.5.Final
После прочтения подобной ошибки в [https://jira.spring.io/browse/DATAJPA-442], я понизил версию спящего режима до версии 4.2.15.Final, которая решила проблему. Однако вопрос все еще жив, можно ли решить проблему без изменения версии Hibernate?
Thomas, спасибо за вашу помощь, я загрузил небольшую демонстрационную версию на https://github.com/sztgeza/springdata-pageable-query – demura
Большое спасибо за тестовый файл. Наши изменения для DATAJPA-617, похоже, устраняют вашу проблему. Я создал небольшой пример с Spring Boot и JPA с FIX: https://github.com/thomasdarimont/spring-data-bugs/tree/master/DATAJPA-617 –
Томас, большое спасибо за исправление, похоже что он работает сейчас. Могу ли я спросить, в каком официальном выпуске (и когда) мы можем использовать исправление? Tx. еще раз! – demura