【发布时间】:2014-03-17 16:14:43
【问题描述】:
在我们的应用程序中,我们希望根据当前状态更新一些记录。在数据库表中,我们有2个字段名为status和notified,当status处于活动状态时,notified为0,我们需要将notified更新为1。由于数据会不断插入和更新,所以我写了一个线程定期扫描表. 这是线程的伪代码:
public class DataPublisher implements Runnable {
private JPADAO dao;
public DataPublisher(JPADAO dao) {
this.dao = dao;
}
@Override
public void run() {
List<Entity> list = dao.getUpdateInformation();
for(Entity entity : list) {
dao.updateNotifiedStatus(entity.getId());
}
}
}
我使用预定的线程池运行线程。 我使用 jpa 来更新数据库。更新状态的代码是这样的:
public class JPADAO {
private EntityManager em;
public JPADAO(EntityManager em) {
if(em == null)
throw new NullPointerException("Invalid em argument.");
this.em = em;
}
public void updateNotifiedStatus(String id) {
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Entity request = em.find(Entity.class, id);
request.setNotified(1);
transaction.commit();
}
当我启动应用程序时,问题是,第一次,所有数据都会正确更新。当我使用数据库客户端手动将通知的字段更改为 0 时,线程可以发现它们匹配要更新的条件。但他们永远不会更新到 1 了。 为什么数据不会在线程中更新?
只是一个更新: 我已经解决了这个问题。主要原因是在我这边,我的进程会用jpa访问数据库。但是其他进程也在以不同的方式访问同一个进程。因为 jpa 默认会从缓存中读取数据。每次在我的查询中,它只会从缓存中获取数据,而不知道数据库已更改。因此,要从数据库中获取最新更新的数据,我们需要在 eclipselink 中禁用缓存。这是我添加的配置:
<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.cache.size.default" value="0"/>
<property name="eclipselink.cache.type.default" value="None"/>
【问题讨论】:
-
尝试在
transaction.commit()之前调用em.flush(),这有时有助于更新。
标签: java multithreading jpa eclipselink