更新数据库列后检索数据库列的值

时间:2018-06-05 09:22:00

标签: java mysql spring hibernate jpa

很抱歉提前发帖。我正在使用Java WebApplication,它使用Spring(2.0,我知道......)和Jpa使用Hibernateimplementation(使用hibernate 4.1和hibernate-jpa-2.0.jar)。我在更新它后从DB表(MySql 5)中检索列的值时遇到问题。这是我的情况(简化,但这是它的核心):

KcUser

    Id:Long (primary key)
    Name:String
    .
    .
    .
    Contract_Id: Long (foreign key, references KcContract.Id)

KcContract

    Id: Long (primary Key)
    ColA
    .
    .
    ColX

在我的服务器中我有这样的东西:

MyController {
    myService.doSomething();    
}


MyService {

    private EntityManager myEntityManager;

    @Transactional(readOnly=true)
    public void doSomething() {
        List<Long> IDs = firstFetch();   // retrieves some users IDs querying the KcContract table
        doUpdate(IDs);                   // updates a column on KcUser rows that matches the IDs retrieved by the previous query
        secondFecth(IDs);                // finally retrieves KcUser rows <-- here the returned rows contains the old value and not the new one i updated in the previous method
    }

    @Transactional(readOnly=true)
    private List<Long> firstFetch() {
        List<Long> userIDs = myEntityManager.createQuery("select c.id from KcContract c" ).getResultList();   // this is not the actual query, there are some conditions in the where clause but you get the idea

        return userIDs;
    }

    @Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW)
    private void doUpdate(List<Long> IDs) {
        Query hql =  myEntityManager().createQuery("update KcUser t set t.name='newValue' WHERE t.contract.id IN (:list)").setParameter("list", IDs);   
        int howMany = hql.executeUpdate();
        System.out.println("HOW MANY: "+howMany); // howMany is correct, with the number of updated rows in DB

        Query select = getEntityManager().createQuery("select t from KcUser t WHERE t.contract.id IN (:list)" ).setParameter("list", activeContractIDs);
        List<KcUser> users = select.getResultList();
        System.out.println("users: "+users.get(0).getName()); //correct, newValue!
    }

    private void secondFetch(List<Long> IDs) {          
        List<KcUser> users = myEntityManager.createQuery("from KcUser t WHERE t.contract.id IN (:list)").setParameter("list", IDs).getResultList()

        for(KcUser u : users) {
            myEntityManager.refresh(u);
            String name = u.getName(); // still oldValue!
        }
    }
}

奇怪的是,如果我对第一个方法(myService.firstFetch())进行注释并使用常量ID列表调用其他两个方法,我会在{{1}中获得正确的新KcUser.name值}}) 方法。

我对Jpa和Hibernate不是很专业,但我认为这可能是一个缓存问题,所以我尝试过:

  • 在更新后使用myEntityManager.flush()
  • 使用myEntityManager.clear()和myEntityManager.getEntityManagerFactory()清除缓存.evictAll();
  • 使用hibernate Session.clear()
  • 清除缓存
  • 在KcUser实体上使用myEntityManager.refresh
  • 使用本机查询(myEntityManager.createNativeQuery(“”)),这对我的理解不应该涉及任何缓存

没有任何效果,我总是在secondFetch(方法中返回旧的KcUser.name值。

迄今为止唯一有效的方法是:

  • secondFetch()方法公开并将其调用移到myService.doSomething()之外,所以在MyController中执行类似的操作:

    firstFetch()

  • List<Long> IDs = myService.firstFetch(); myService.doSomething(IDs);中使用新的EntityManager,所以做这样的事情:

secondFetch(

并使用它来执行后续查询以从DB中获取用户

使用最后两种方法中的任何一种,第二种选择工作正常,我在“名称”列中获得具有更新值的用户。 但是我想知道实际发生了什么以及为什么其他任何事情都不起作用:如果它实际上是一个缓存问题,我认为只需要EntityManager newEntityManager = myEntityManager.getEntityManagerFactory().createEntityManager();.clear()。或者也许我完全错了,它根本与缓存无关,但后来我对实际可能发生的事情感到有点迷茫。

我担心我们使用hibernate / jpa的方式可能会出现问题,这可能会影响我们未来。 有什么好主意吗?如果您需要更多详细信息并感谢您的帮助,请告诉我。

1 个答案:

答案 0 :(得分:2)

按以下顺序执行操作:

  1. 只读事务A打开。
  2. 首次提取(事务A)
  3. 打开非只读事务B.
  4. 更新(事务B)
  5. 交易B关闭
  6. 第二次获取(事务A)
  7. 交易A关闭

交易A是只读的。该事务中的所有后续查询仅查看在事务开始之前提交的更改 - 您的更新在其之后执行。