【问题标题】:Several operation on DAO executionDAO执行的几个操作
【发布时间】:2010-08-06 07:27:41
【问题描述】:

我尝试在一个 DAO 方法中执行多个查询。测试失败(数据未更新)。无异常记录。

public List<Domain> getNewDomains(final int maxAllowedItems, final Date timestamp) {

    return getJpaTemplate().execute(new JpaCallback<List<Domain>>() {
        @SuppressWarnings("unchecked")
        public List<Domain> doInJpa(EntityManager entityManager) throws PersistenceException {
            Calendar dayBefore = Calendar.getInstance();
            dayBefore.setTime(timestamp);
            dayBefore.add(Calendar.HOUR, -24);

            List ids = entityManager.createQuery("SELECT d.id FROM domain d WHERE d.crawlDate IS NULL and (d.lastRead IS NULL OR d.lastRead <= :dayBefore ) ")
            .setParameter("dayBefore", dayBefore.getTime())
            .setMaxResults(maxAllowedItems)
            .getResultList();

            LOG.debug("new domain IDS : " + ids.toString());

            if(ids.isEmpty()) {
                return new ArrayList<Domain>();
            }

            int result = entityManager.createQuery("UPDATE domain d SET d.lastRead = :timestamp WHERE d.id IN (:ids)")
            .setParameter("timestamp", timestamp)
            .setParameter("ids", ids).executeUpdate();

            LOG.debug("update result : " + result);

            return entityManager.createQuery("SELECT d FROM domain d WHERE d.id IN (:ids) ")
            .setParameter("ids", ids)
            .setMaxResults(maxAllowedItems)
            .getResultList();
        }
    });
}


首先选择正确处理。但更新“lastRead”字段状态相同。

测试:

@Test
public void testGetNewItems() {
    List<Domain> items = domainDAO.getNewDomains(2, new Date());
    Assert.assertNotNull(items);
    Assert.assertTrue(items.isEmpty());

    String domainName = "example.com";
    Domain domain1 = new Domain(domainName);
    domainDAO.save(domain1);

    String domainName2 = "example2.com";
    Domain domain2 = new Domain(domainName2);
    domainDAO.save(domain2);
    Domain domain2FromDB = domainDAO.getByName(domainName2);
    Assert.assertEquals(domain2, domain2FromDB);
    Assert.assertNull(domain2FromDB.getCrawlDate());

    domain2FromDB.setCrawlDate(new Date());
    domainDAO.update(domain2FromDB);

    String domainName3 = "example3.com";
    Domain domain3 = new Domain(domainName3);
    domainDAO.save(domain3);

    items = domainDAO.getNewDomains(2, new Date());
    Assert.assertNotNull(items);
    Assert.assertEquals(2, items.size());
    Assert.assertTrue(items.contains(domain1));
    Assert.assertTrue(items.contains(domain3));
    Assert.assertFalse(items.contains(domain2FromDB));

    for (Domain item : items) {
        Assert.assertNotNull(item.getLastRead()); // FAILED assert
    }
}

更新后需要刷机吗? 处理多个查询的正确方法是什么?

【问题讨论】:

    标签: hibernate spring jpa dao


    【解决方案1】:

    更新和删除查询在 JPA 中被视为批量更新,并且具有不同的规则。批量更新直接在数据库上执行,持久性上下文 (EntityManager) 不会随着这些更改而更新。因此,当您查询持久性上下文时,它会找到一个匹配的实体——在不知不觉中返回过时的数据。

    JPA 规范是这样写的:

    在执行批量更新或删除操作时应小心,因为它们可能会导致 数据库和活动持久性上下文中的实体之间的不一致。一般来说,散装 更新和删除操作只能在新的持久性配置中的事务内执行 文本或在获取或访问其状态可能受此类操作影响的实体之前。

    对于如何解决问题,您有多种选择。

    重写第一个查询以返回实体而不仅仅是 id。并修改实体。像这样的东西应该可以工作

    public List<Domain> doInJpa(EntityManager entityManager) throws PersistenceException {
        Calendar dayBefore = Calendar.getInstance();
        dayBefore.setTime(timestamp);
        dayBefore.add(Calendar.HOUR, -24);
    
        List<Domain> domains = entityManager.createQuery("SELECT d FROM domain d WHERE d.crawlDate IS NULL and (d.lastRead IS NULL OR d.lastRead <= :dayBefore ) ")
            .setParameter("dayBefore", dayBefore.getTime())
            .setMaxResults(maxAllowedItems)
            .getResultList();
    
        if(domains.isEmpty()) {
            return new ArrayList<Domain>();
        }
    
        for(Domain d : domains) { 
            d.setLastRead(timestamp);
        }
    
        return domains;     
    }
    

    现在您只有一个查询,实体将与持久性上下文同步,您的测试应该会通过。

    如果您无法通过在每个域上调用 entityManager.refresh() 来解决批量更新问题 - refresh 方法将使用数据库中的最新状态更新实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-11
      • 2023-03-31
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 2013-08-27
      相关资源
      最近更新 更多