我試圖用Spring數據存儲庫中的分頁運行@NamedQuery時考慮過一個問題。 實體類看起來是這樣的: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;
}
}
它試圖從生成的名字Customer.findByNamePattern.count
,它不存在創建TypedQuery
EntityManager的命名查詢庫。 hasNamedQuery()
檢查它,捕獲拋出的IllegalArgumentException
, 並以另一種方式創建它。問題是,雖然IllegalArgumentException
被捕獲,該事務回滾
我發現下面的解決方法(有時!):
使用的庫法
org.springframework.data.jpa.repository.Query
註釋OR-創建另一個命名查詢@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
使用的版本是: 春:4.0.5.RELEASE 彈簧數據:1.6.0.RELEASE,1.7.0.RELEASE 休眠:4.3.5.Final
在[https://jira.spring.io/browse/DATAJPA-442]上閱讀了類似的錯誤之後,我將hibernate版本降級到4.2.15.Final,從而解決了問題。 但是問題仍然存在,是否可以在不更改Hibernate版本的情況下解決問題?
Thomas,感謝您的幫助,我已經在https://github.com/sztgeza/springdata-pageable-query上傳了一個小樣本 – demura 2014-10-26 20:46:29
非常感謝您的測試案例。我們對DATAJPA-617的更改似乎解決了您的問題。我使用Spring Boot創建了一個小例子,並使用FIX創建了JPA版本:https://github.com/thomasdarimont/spring-data-bugs/tree/master/DATAJPA-617 – 2014-10-27 09:17:58
Thomas,非常感謝修復,它似乎它現在有效。請問,我們可以在哪個官方發佈(以及何時)使用修復程序? TX。再次! – demura 2014-10-27 15:36:58