java - 新的 EntityManager 有时会从 MySQL 获取陈旧数据

标签 java mysql hibernate jpa entitymanager

联合会; hibernate 4.3.6; MySQL 6.2(InnoDB);在 Tomcat 上运行的 Vaadin Web 应用程序

当我从数据库中读取一个实体时,我有时会得到过时的数据。我找不到模式 - 有时相同的代码会提取陈旧数据,然后清理数据,然后再次陈旧。

我在每次查询之前都得到一个新的 EntityManager。(我担心我可能会以某种方式从重复使用的 EntityManager 池中获取它们,但是刷新"new"EntityManager 给我一个错误没有正在进行的交易。)

Hibernate 的调试日志和单步执行代码,都表明它每次都在访问数据库。

一切都指向经典错误:事务中的 REPEATABLE-READ 先前已读取(现在过时的)数据。果然,如果我将 MySQL 的事务隔离设置从 REPEATABLE-READ 更改为 READ-COMMITTED,问题就会消失。但是,如果我每次都分配一个新的 EntityManager,这怎么可能呢?

细节: 我运行下面的代码并看到 templateFile 字段的正确值“OLD”。然后我手动编辑并提交对数据库中行的更改,将其设置为“NEW”。当我再次运行代码时,我可以看到以下任何内容:

Filename1: OLD
Filename2: OLD
OR
Filename1: OLD
Filename2: NEW
OR
Filename1: NEW
Filename2: NEW

我得到的任何结果都倾向于“坚持”,每次代码运行时都会重复,至少直到我弄乱了程序的其他部分。下次我返回测试时,结果可能会或可能不会改变。

代码:

// the factory is a static instance, initialized once
EntityManagerFactory myFactory = Persistence.createEntityManagerFactory(“foo.entities.persistence-unit”);
// . . .

// The actual test:
EntityManager entityManager1 = myFactory.getNewEntityManager();
Household household1 = entityManager1.find(Household.class, 7);
entityManager1.refresh(household1);
System.out.println("Filename1: " + household1.getTemplateFile());
// read second copy of same entity
EntityManager entityManager2 = myFactory.getNewEntityManager();
Household household2 = entityManager2.find(Household.class, 7);
entityManager2.refresh(household2);
System.out.println("Filename2: " + household2.getTemplateFile());

持久性.xml:

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">

    <persistence-unit name=“foo.entities.persistence-unit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
       <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/myschema"></property>
       <property name="javax.persistence.jdbc.user" value="mydba"></property> 
       <property name="javax.persistence.jdbc.password" value=“********”></property>
       <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
       <property name="javax.persistence.schema-generation.create-database-schemas" value="false"></property>
    </properties>
    </persistence-unit>
</persistence>

更新: 新线索。当我从使用通过属性定义的数据源切换到 Tomcat 连接池时,问题似乎也消失了。持久化单元现在看起来像这样:

<persistence-unit name="foo.entities.persistence-unit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <non-jta-data-source>java:comp/env/jdbc/foo</non-jta-data-source>
</persistence-unit>

最佳答案

出于某种原因,我认为隐式事务 entityManager join 是一个新事务。但是Hibernate docs状态:“当您在事务中创建实体管理器时,实体管理器会自动加入当前事务。”

所以显然有另一个事务已经在运行(不足为奇)并且我的获取结果会根据它已经读取的内容而变化(因为数据库正在以可重复读取模式运行。)

在短期内,我将遍历我的代码,以在缺少的地方显式开始()事务。从长远来看,我将研究 Spring Transactions,以了解如何以更简单的方式管理事务(如评论中所建议的那样。)

关于java - 新的 EntityManager 有时会从 MySQL 获取陈旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27023935/

相关文章:

php - 拉维尔 4 : How to get selected/specific columns in a many to many relationship?

MYSQL - 我应该使用多个子表还是一个子表作为数据描述符?

mysql - MariaDB/MySQL 查询区分大小写吗?

hibernate - Hibernate 限制中的日期重叠

java - 根据 selectOneRadio 上选择的内容重新渲染 panelGroup 或区域

java - 正则表达式在 Java 中不起作用

php - Mysql正则表达式使用多个规则来匹配字符串

Hibernate无法添加外键约束

java - 如何在 "if"中使用零长度 boolean 数组

java - 三元打印操作