java - 更新后检索数据库列的值
问题描述
很抱歉,很长的帖子。我正在使用一个Java WebApplication,它使用Spring(2.0,我知道......)和带有Hibernateimplementation的Jpa(使用hibernate 4.1和hibernate-jpa-2.0.jar)。更新数据库表(MySql 5)后,我无法从数据库表(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 列表调用其他两个方法,我会在secondFetch(
) 方法中得到正确的新 KcUser.name 值。
我对 Jpa 和 Hibernate 不是很专家,但我认为这可能是缓存问题,所以我尝试过:
- 更新后使用 myEntityManager.flush()
- 使用 myEntityManager.clear() 和 myEntityManager.getEntityManagerFactory().evictAll() 清除缓存;
- 使用休眠 Session.clear() 清除缓存
- 在 KcUser 实体上使用 myEntityManager.refresh
- 使用本机查询(myEntityManager.createNativeQuery("")),据我了解,这不应该涉及任何缓存
这些都不起作用,我总是在方法中返回旧的 KcUser.name 值secondFetch()
。
到目前为止唯一有效的是:
公开该
firstFetch()
方法并将其调用移到 myService.doSomething() 之外,因此在 MyController 中执行以下操作:List<Long> IDs = myService.firstFetch(); myService.doSomething(IDs);
在 ) 中使用新的 EntityManager
secondFetch(
,因此执行以下操作:
EntityManager newEntityManager = myEntityManager.getEntityManagerFactory().createEntityManager();
并使用它执行后续查询以从数据库中获取用户
使用最后两种方法中的任何一种,第二个选择都可以正常工作,并且我在“名称”列中获得具有更新值的用户。但我想知道实际发生了什么以及为什么其他事情都没有奏效:如果它实际上是一个缓存问题,我认为这是一个简单.clear()
或.refresh()
应该有效的问题。或者也许我完全错了,它根本与缓存无关,但后来我对可能发生的事情有点迷失了。
我担心我们使用 hibernate / jpa 的方式可能有问题,这可能会在未来咬我们。请问有什么想法吗?如果您需要更多详细信息,请告诉我,并感谢您的帮助。
解决方案
操作按以下顺序执行:
- 只读事务 A 打开。
- 第一次提取(事务 A)
- 非只读事务 B 打开
- 更新(事务 B)
- 交易 B 结束
- 第二次提取(事务 A)
- 交易 A 结束
事务 A 是只读的。该事务中的所有后续查询只看到事务开始之前提交的更改 - 您的更新是在它之后执行的。
推荐阅读
- javascript - 关闭简单的 jQuery 弹出窗口的问题
- python - numpy.load() MemoryError 而数据只有 4.6MB 大
- c - 我需要为每个变量添加(浮点数)吗?
- javascript - 为什么代码不会增加数组中的所有变量
- prestashop - Prestashop - 仅在某些产品上显示视频
- visual-studio - Visual Studio - Xamarin Android 查看器错误
- django - 在 BeaverDam 中使用 djnago 打开静态文件的问题
- android - 将后台函数部署到我的 Firebase 云函数并从客户端 Android 端调用它
- python - 如何在 Django API 中解析 view.py 中的请求?
- spring - SDR - 只读存储库与 CrudRepository