How to force Hibernate read external database changes

问题: I have a common database that is used by two different applications (different technologies, different deployment servers, they just use the same database). Let's call t...

问题:

I have a common database that is used by two different applications (different technologies, different deployment servers, they just use the same database).

Let's call them application #1 and application #2.

Suppose we have the following scenario:

  • the database contains a table called items (doesn't matter its content)
  • application #2 is developed in Spring Boot and it is mainly used just for reading data from the database
  • application #2 retrieves an item from the database
  • application #1 changes that item
  • application #2 retrieves the same item again, but the changes are not visible

What I understood by reading a lot of articles:

  • when application #2 retrieves the item, Hibernate stores it in the first level cache
  • the changes that are done to the item by application #1 are external changes and Hibernate is unaware of them, and thus, the cache is not updated (same happens when you do a manual change in the database)
  • you cannot disable Hibernate's first level cache.

So, my question is, can you force Hibernate into refreshing the entities every time they are read (or make it go into the database) without explicitly calling em.refresh(entity)? The problem is that the business logic module from application1 is used as a dependency in application1 so I can only call service methods (i.e. I don't have access to the entityManager or session references).


回答1:

Hibernate L1 cache is roughly equivalent to a DB transaction when you run in a repeatable-read level isolation. Basically, if you read/write some data, the next time you query in the context of the same session, you will get the same data. Further, within the same process, sessions run independent of each other, which means 2 session are looking at different data in the L1 cache.

If you use repeatable read or less, then you shouldn't really be concerned about the L1 cache, as you might run into this scenario regardless of the ORM (or no ORM).

I think you only need to think about the L2 cache here. The L2 cache is what stores data and assumes only hibernate is accessing the DB, which means that if some change happens in the DB, hibernate might not know about it. If you just disable the L2 cache, you are sorted.

Further reading - Short description of hibernate cache levels


回答2:

Well, if you cannot access hibernate session you are left with nothing. Any operations you want to do requires session access. For instance you can remove entity from cache after reading it like this:

session.evict(entity);

or this

session.clear();

but first and foremost you need a session. Since you calling only services you need to create service endpoints clearing session cache after serving them or modify existing endpoints to do that.


回答3:

You can try to use StatelessSession, but you will lose cascading and other things.

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#_statelesssession

https://stackoverflow.com/a/48978736/3405171


回答4:

You can force to start a new transaction, so in this manner hibernate will not be read from the cache and it will redo the read from the db.

You can annotate your function in this manner

@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)

Requesting a new transaction, the system will generation a new hibernate session, so the data will not be in the cache.

  • 发表于 2019-07-07 07:13
  • 阅读 ( 237 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除