Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring数据JPA:可分页查询回滚事务_Spring_Jpa_Spring Data_Spring Data Jpa_Spring Transactions - Fatal编程技术网

Spring数据JPA:可分页查询回滚事务

Spring数据JPA:可分页查询回滚事务,spring,jpa,spring-data,spring-data-jpa,spring-transactions,Spring,Jpa,Spring Data,Spring Data Jpa,Spring Transactions,在尝试从Spring数据存储库运行带分页的@NamedQuery时,我考虑了一个问题。 实体类如下所示: @NamedQueries({ @NamedQuery( name = "Customer.findByNamePattern", query = "select c from Customer c where c.name like :pattern" ) }) @Entity public class Customer { @Id

在尝试从Spring数据存储库运行带分页的@NamedQuery时,我考虑了一个问题。 实体类如下所示:

@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);
}
在存储库方法上使用
org.springframework.data.jpa.repository.Query
注释在事务上下文中也可以正常工作

经过一段时间的调试,问题似乎是由
org.springframework.data.jpa.repository.query.NamedQuery
,在
doCreateCountQuery()
hasNamedQuery()
中:

这对我来说并不清楚:

  • 调用
    findAll()。为什么?
    
  • 使用
    org.springframework.data.jpa.repository.Query
    而不是
    @NamedQuery
    也不会导致问题,为什么
  • 如何在事务上下文中使用带pageable选项的@NamedQuery来避免问题(而不是显式创建count查询)
任何帮助都将不胜感激

更新

使用的版本为: 弹簧:4.0.5.0释放 弹簧数据:1.6.0.RELEASE,1.7.0.RELEASE 休眠:4.3.5.4

在[]上读到类似的错误后,我将hibernate版本降级为4.2.15.Final,解决了这个问题。
但是问题仍然存在,是否可以在不更改Hibernate版本的情况下解决问题?

您遇到的问题由多个工件驱动:

根据定义,JPA
EntityManager
必须关闭(并可能重新创建)在它抛出异常之后。这通常是在实体操作失败的情况下发生的,您可以确定
EntityManager
s的状态。对于简单的命名查询查找,这是非常严格的,因为它肯定不需要创建新的
EntityManager
。但是,我们需要处理这个问题


也就是说,我们已经针对手动定义的查询解决了这个问题(这就是为什么您认为它适用于
@Query
)。但是,我们为我们引入的防御机制不适用于命名的查询部分。我为您创建了此机制。

我添加了一个带有潜在修复的PR: 我们使用一个新的(一次性的)EntityManager来执行命名查询查找,以便原始EntityManager不会受到失败查找的影响。 事实证明,你的问题很难重现。你介意把它转一转吗?
也许你甚至可以为此提供一个小测试用例?

谢谢你的回答!托马斯,谢谢你的帮助,我已经在网站上上传了一个小演示,非常感谢你的测试用例。我们对DATAJPA-617的更改似乎解决了你的问题。我创建了一个带有Spring Boot的小示例和带有修复程序的JPA版本:托马斯,非常感谢修复程序,现在看来它可以工作了。请问,在哪个官方版本(以及何时)我们可以使用该修复程序?再次发送!
@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);       
    }
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
@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;
    }
}   
@NamedQuery(
    name = "Customer.findByNamePattern.count",
    query = "select count(c.id) from Customer c where c.name like :pattern"
),