0

I have a entity call Company, and another entity call token.

1 Company will have many tokens.

So in my Company entity, I will have something like follow:

 @OneToMany(mappedBy = "companyId")
 public Set< Token > getTokens() {
    return tokens;
 }

However, I will have some logic during the return, it will change the token list before return, its something like follow:

@OneToMany(mappedBy = "companyId")
 public Set< Token > getTokens() {
    tokens.remove( token );
    return tokens;
 }

Because of I changing the value in token list, thus, every time I select the company object from db using hibernate, the company table will be updated automatically.

Base on my understanding, this is a behavior of hibernate dirty checking. So when Hibernate detect that there something changes on it, it will do the update to database.

Is there any way that can avoid this? For example maybe just call existing hibernate function, so that hibernate will know the token list is dirty, and it will no do the update.

Yes, I know the filtering logic in the getTokens() is not suitable. By right filtering logic should not apply in entity level. But because of currently there is many place using this method, if I change in this entity level, then there will impact others and if I change other place as well, it will need to retest whole application again.

Thus I am trying to find a better way on this.

Panadol Chong
  • 1,793
  • 13
  • 54
  • 119
  • 1
    One alternate you can do is, instead of changing the original data, create copy of your original data and then perform your logic on copied data and then return copied data. – Sreenath Reddy Nov 17 '17 at 09:07

1 Answers1

2

What you actually want is to prevent Hibernate from auto flushing.

See hibernate docs:

Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.

A solution to this problem is to change the default configuration of FlushMode from auto to manual by setting FlushMode.MANUAL. In this way the dirty check mechanism will stop causing the aforementioned synchronization.

Although the Session is only ever flushed when Session.flush() is explicitly called by the application as described in the hibernate documentation.

Here it has to be mentioned that if you follow the suggested solution you need to pay the price of the explicitly flushing which means that you need to explicitly call the Session.flush() method every time you want to commit something on the database.

Read here some useful material regarding FlushMode as were officially documented in hibernate documentation.

UPDATE:
This solution applies on the Session, so if you want to apply this only on the specific entity you should try to create two methods. One for setting it to MANUAL and one for back to the default AUTO. In this way you will change your value after MANUAL setting to prevent flushing and subsequently you will set it back to the default in order not to affect the other entities.
Maybe the below implementation will help:

@Autowired
private SessionFactory sessionFactory;


@OneToMany(mappedBy = "companyId")
 public Set< Token > getTokens() {
    setFlushModeManual();
    tokens.remove( token );
    setFlushModeAuto();
    return tokens;
 }

private void setFlushModeManual() {
    sessionFactory.getCurrentSession().setFlushMode(FlushMode.MANUAL);
}

private void setFlushModeAuto() {
    sessionFactory.getCurrentSession().setFlushMode(FlushMode.AUTO);
}
  • 1
    Ya, I have to explicitly call the Session.flush() if I do so. Actually I just want to avoid the hibernate dirty checking at this module, but not other modules. I am trying to find a way to only apply in this company.getTokens(), not sure is it possible or not. – Panadol Chong Nov 17 '17 at 09:20
  • I have updated my answer with a workaround. Try it and see if this is helpful. – Anastasios Vlasopoulos Nov 17 '17 at 09:41
  • Hi @Anastasios, sorry still not really understand on it. The `setFlushModeManual()` and `setFlushModeAuto()` method, how's it going to work? I didnt assign any `FlushMode` to any term or variable, how's the program will understand the getTokens part will become Manual or Auto? I am quite new to hibernate. – Panadol Chong Nov 20 '17 at 07:45
  • Hi @Panadol. Regarding `FlushMode`, this is a native final class of hibernate library which represents the flushing strategy per Session. You do not need to assign it to any variable. Read [this](https://stackoverflow.com/questions/18149876/what-to-use-flush-mode-auto-or-commit) and you will understand better how it works. – Anastasios Vlasopoulos Nov 20 '17 at 08:26
  • Hi @Anastasios, I read those document, and found that the `FlushMode` is use on the.`query.setFlushMode()` or `session.setFlushMode()`. Still cant get the answer you provide, If I using your code, it will hit `Syntax error, insert "AssignmentOperator Expression" to complete Expression`. – Panadol Chong Nov 21 '17 at 08:33
  • You are right, so I have updated my answer accordingly assuming that you are using Spring. If not then we should find another way. – Anastasios Vlasopoulos Nov 21 '17 at 09:11
  • Hi @Anastasios, sorry for late reply. Your solution is correct and work for me actually, it solved my problem !! But can you try to change your answer to do at DAO layer or service layer? Because I think do this at entity layer is not really suitable, I apply your solution in my DAO layer, and its good : ) – Panadol Chong Nov 29 '17 at 02:15