2

I have been trying to persist an entity instance and then right after that update that same entity instance through a JPQL query. Both operations participate in a Entity Transaction, but after the commit, the Update query seems to not have been executed or to have been executed before the commit.

How to get it right?

Code:

    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>

Hibernate logs:

    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
m_junior
  • 591
  • 1
  • 8
  • 19

2 Answers2

2

Try this:

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();
Alberto
  • 745
  • 1
  • 6
  • 25
  • Are you telling me that the Update instruction is not supposed to work? Is it supposed to be executed on commit or not??? – m_junior Apr 20 '18 at 06:37
  • You are using distinct objects to make operations in database and it is possible that your Person has not the Id to do the update – Alberto Apr 20 '18 at 06:42
  • Hi @Alberto, should I assume that it’s not possible to update an entity instance via a query in the same transaction it is created? – m_junior Apr 20 '18 at 06:46
  • Yes should, but use jpql or entityManager to do the insert and update, but don't mixed. I think that is the problem. As you can see in logs, statements are executed by differents objects of hibernate – Alberto Apr 20 '18 at 06:50
  • Based on this assumption, EntityManager.merge is the only option left. As long as the same EntityManager instance used for persist is used. – m_junior Apr 20 '18 at 06:57
  • Or use jpql for insert: https://stackoverflow.com/questions/43347602/how-to-construct-an-insert-query-in-jpa – Alberto Apr 20 '18 at 07:30
-1

Try entitymanager.refresh(). It worked for me