【问题标题】:JPA Hibernate - Can't persist and executeUpdate query in same Entity TransactionJPA Hibernate - 无法在同一实体事务中持久化和执行更新查询
【发布时间】:2018-09-30 18:51:24
【问题描述】:

我一直在尝试持久化一个实体实例,然后就在此之后 通过 JPQL 查询更新同一个实体实例。 两个操作都参与一个实体事务,但是在提交之后, 更新查询似乎尚未执行或在提交之前已执行。

如何做到正确?

代码:

    EntityManager em = getEntityManager();
    EntityTransaction transaction = em.getTransaction();
    transaction.begin();

    Person person = new Person();
    person.setAge(25);
    person.setName("John Ive");
    em.persist(person);

    Query q = em.createQuery("Update Person p set p.age=27 where p.personId=:id");
    q.setParameter("id",person.getPersonId());
    q.executeUpdate();
    transaction.commit();

Person.java

@Entity
public class Person {
    @Id
    @GeneratedValue
    private int personId;
    private String name;
    private int age;

    //Getters and setter here
}

persistence.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="example-db" transaction-type="RESOURCE_LOCAL">

    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <class>example.entities.Person</class>

    <exclude-unlisted-classes>false</exclude-unlisted-classes>

    <properties>
        <property name="hibernate.archive.autodetection" value="class, hbm" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
        <property name="hibernate.connection.autocommit" value="false" />
        <property name="hibernate.connection.release_mode" value="after_transaction" />
        <property name="org.hibernate.flushMode" value="commit" />
        <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
        <property name="javax.persistence.jdbc.user" value="sa"/>
        <property name="javax.persistence.jdbc.password" value=""/>
        <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
    </properties>

</persistence-unit>

休眠日志:

    08:27:42.847 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - begin
    08:27:42.854 [main] DEBUG org.hibernate.SQL - call next value for hibernate_sequence
    Hibernate: call next value for hibernate_sequence
    08:27:42.860 [main] DEBUG org.hibernate.id.enhanced.SequenceStructure - Sequence value obtained: 1
    08:27:42.860 [main] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered
    08:27:42.863 [main] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Generated identifier: 1, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
    08:27:42.881 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
    08:27:42.882 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Dirty checking collections
        08:27:42.885 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
        08:27:42.885 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
        08:27:42.888 [main] DEBUG org.hibernate.internal.util.EntityPrinter - Listing entities:
        08:27:42.888 [main] DEBUG org.hibernate.internal.util.EntityPrinter - example.entities.Person{name=John Ive, personId=1, age=25}
        08:27:42.896 [main] DEBUG org.hibernate.SQL - insert into Person (age, name, personId) values (?, ?, ?)
        Hibernate: insert into Person (age, name, personId) values (?, ?, ?)
        08:27:42.913 [main] DEBUG org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - QueryTranslatorFactory : org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory@615f972
        08:27:42.913 [main] INFO org.hibernate.hql.internal.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
        08:27:42.942 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - parse() - HQL: Update example.entities.Person p set p.age=27 where p.personId=:id
        08:27:42.952 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- HQL AST ---
         \-[UPDATE] Node: 'Update'
            +-[FROM] Node: 'FROM'
            |  \-[RANGE] Node: 'RANGE'
            |     +-[DOT] Node: '.'
            |     |  +-[DOT] Node: '.'
            |     |  |  +-[IDENT] Node: 'example'
            |     |  |  \-[IDENT] Node: 'entities'
            |     |  \-[IDENT] Node: 'Person'
            |     \-[ALIAS] Node: 'p'
            +-[SET] Node: 'set'
            |  \-[EQ] Node: '='
            |     +-[DOT] Node: '.'
            |     |  +-[IDENT] Node: 'p'
            |     |  \-[IDENT] Node: 'age'
            |     \-[NUM_INT] Node: '27'
            \-[WHERE] Node: 'where'
               \-[EQ] Node: '='
                  +-[DOT] Node: '.'
                  |  +-[IDENT] Node: 'p'
                  |  \-[IDENT] Node: 'personId'
                  \-[COLON] Node: ':'
                     \-[IDENT] Node: 'id'

        08:27:42.952 [main] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
        08:27:42.992 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - update << begin [level=1, statement=update]
        08:27:43.015 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromElement - FromClause{level=1} : example.entities.Person (p) -> person0_
        08:27:43.017 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : p -> personId
        08:27:43.020 [main] DEBUG org.hibernate.hql.internal.ast.tree.DotNode - getDataType() : age -> org.hibernate.type.IntegerType@309e345f
        08:27:43.022 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : p.age -> age
        08:27:43.028 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : p -> personId
        08:27:43.028 [main] DEBUG org.hibernate.hql.internal.ast.tree.DotNode - getDataType() : personId -> org.hibernate.type.IntegerType@309e345f
        08:27:43.028 [main] DEBUG org.hibernate.hql.internal.ast.tree.FromReferenceNode - Resolved : p.personId -> personId
        08:27:43.031 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - update : finishing up [level=1, statement=update]
        08:27:43.032 [main] DEBUG org.hibernate.hql.internal.antlr.HqlSqlBaseWalker - update >> end [level=1, statement=update]
        08:27:43.033 [main] DEBUG org.hibernate.hql.internal.ast.QueryTranslatorImpl - --- SQL AST ---
         \-[UPDATE] UpdateStatement: 'Update'  querySpaces (Person)
            +-[FROM] FromClause: 'FROM' FromClause{level=1, fromElementCounter=1, fromElements=1, fromElementByClassAlias=[p], fromElementByTableAlias=[person0_], fromElementsByPath=[], collectionJoinFromElementsByPath=[], impliedElements=[]}
            |  \-[FROM_FRAGMENT] FromElement: 'Person' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=p,role=null,tableName=Person,tableAlias=person0_,origin=null,columns={,className=example.entities.Person}}
            +-[SET] SqlNode: 'set'
            |  \-[EQ] BinaryLogicOperatorNode: '='
            |     +-[DOT] DotNode: 'age' {propertyName=age,dereferenceType=PRIMITIVE,getPropertyPath=age,path=p.age,tableAlias=person0_,className=example.entities.Person,classAlias=p}
            |     |  +-[ALIAS_REF] IdentNode: 'personId' {alias=p, className=example.entities.Person, tableAlias=person0_}
            |     |  \-[IDENT] IdentNode: 'age' {originalText=age}
            |     \-[NUM_INT] LiteralNode: '27'
            \-[WHERE] SqlNode: 'where'
               \-[EQ] BinaryLogicOperatorNode: '='
                  +-[DOT] DotNode: 'personId' {propertyName=personId,dereferenceType=PRIMITIVE,getPropertyPath=personId,path=p.personId,tableAlias=person0_,className=example.entities.Person,classAlias=p}
                  |  +-[ALIAS_REF] IdentNode: 'personId' {alias=p, className=example.entities.Person, tableAlias=person0_}
                  |  \-[IDENT] IdentNode: 'personId' {originalText=personId}
                  \-[NAMED_PARAM] ParameterNode: '?' {name=id, expectedType=org.hibernate.type.IntegerType@309e345f}

        08:27:43.033 [main] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
        08:27:43.048 [main] DEBUG org.hibernate.hql.internal.ast.ErrorCounter - throwQueryException() : no errors
        08:27:43.066 [main] DEBUG org.hibernate.SQL - update Person set age=27 where personId=?
        Hibernate: update Person set age=27 where personId=?
        08:27:43.068 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - committing
08:27:43.069 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
08:27:43.069 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Dirty checking collections
08:27:43.069 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
08:27:43.070 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections

【问题讨论】:

  • 在persist后尝试使用em.flush();
  • 我看到你已经激活了配置“show_sql”。你能发送执行的sql吗?
  • 现在可以看到sql了
  • 插入语句未执行。如果要更新同一个人,首先必须存在。或者尝试使用 JPQL 的 em.merge(person) 实例

标签: java hibernate jpa


【解决方案1】:

试试这个:

EntityManager em = getEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();

Person person = new Person();
person.setAge(25);
person.setName("John Ive");
em.persist(person);

person.setAge(27);
em.merge(person);

transaction.commit();

【讨论】:

  • 你是在告诉我更新指令不应该工作吗?它是否应该在提交时执行???
  • 您正在使用不同的对象在数据库中进行操作,并且您的 Person 可能没有 ID 来进行更新
  • 嗨@Alberto,我是否应该假设不可能通过在创建实体实例的同一事务中的查询来更新它?
  • 是应该的,但是使用jpql或者entityManager来做插入和更新,但是不要混用。我认为这就是问题所在。正如你在日志中看到的,语句是由 hibernate 的不同对象执行的
  • 基于这个假设,EntityManager.merge 是唯一的选择。只要使用相同的用于持久化的 EntityManager 实例。
【解决方案2】:

试试 entitymanager.refresh()。它对我有用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-22
    • 2019-12-24
    • 2010-12-30
    • 1970-01-01
    • 2011-07-16
    • 2017-10-21
    • 1970-01-01
    • 2012-07-30
    相关资源
    最近更新 更多