简体   繁体   中英

Spring JPA @Transactional data accessing

im having trouble resolving or handling data between my @Transational methods. Or i may have a wrong understanding of @Transactionl .

This is my scenario

Method A

@Transactional
public void methodA {
   MyEntity e = myRepo.findByid(1).orElseThrow();

   e.setMyFlag(1123);

   methodB();

   myRepo.save(e);
}


@Transactional 
public void methodB {
    MyEntity e = myRepo.findByMyFlag(1123).orElseThrow(); <--- This throws Not Found Exception
    // do something 'e' entity that is having a myFlag = 1123
    // i am not modifying the entity just doing something externally 
    // using myFlag value 1123
}

My understanding is that, methodB is using the session in methodA . Now, given that it is using the same session, i can get the data set in methodA that was not yet commited or save() is not yet called. Please do correct me if i am wrong and point me to the correct one. Also, the above scenario is what i wanted to achieve.

FYI i also tried moving methodB call after save() call. Still Not found exception occurs

You're right that it uses the same session and it is part of the same transaction. Where you're mistaken is that setting the value in the entity (without having saved yet) puts it anywhere that doing another query will find it.

In other words, the findByMyFlag in methodB is still not going to find the entity which you just modified, because the value you're searching on hasn't been saved to the database, yet.

If, on the other hand, you had searched in methodB using findByid(1), then you would have found the same entity that would have that change in it.

In the same class, a method calls another annotated method (such as @Async, @Transational), the annotation will not take effect

It is only from the various comments that you have added the answer can be deduced ie your question itself fails to give all relevant information.

You note that you look up query is "just a normal @Query(value="select * from my_table where my_flag =?1", nativeSql=true)".

And that is your problem: the fact you are executing a native sql query rather than a JPQL query.

If this was aa JPQL query then any pending changes in the same transaction would be flsuhed to the database (not committed, only flushed) in order that the query returned accurate results ie.e.reflected any changes pending but not yet flushed to the database.

See further here for a more detailed explanation:

https://vladmihalcea.com/how-does-the-auto-flush-work-in-jpa-and-hibernate/

So to fix your problem change your query to:

@Query(value="select e from MyEntity e where e.myFlag =?1") ie a JPQL query which will trigger a flush of pending changes.

Even moving myRepo.save(e); above the call to methodB() will not fix it. You would need to save and flush for the native query to find it.

Which begs the question, why are you using a native query?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM