Home > Net >  Hibernate does another select before save
Hibernate does another select before save

Time:01-25

I have the following sample code:

@Transactional
public void someMethod() {
    MyEntity myEntity = myRepo.findById(1).orElse(null);
    if (myEntity != null) {
        myEntity.setValue("something");
        myRepo.save(myEntity);
    }
}

And myRepo is an instance of:

public interface MyRepo extends CrudRepository<MyEntity, Integer> {}

So I can see the first SELECT is coming from myRepo.findById(1), which makes sense. But when the code runs to myRepo.save(myEntity), Hibernate somehow thinks the myEntity returned from findById() is not managed and so it does another SELECT again to create a managed entity, then replace its value using myEntity, then does the UPDATE.

Could you please explain why another SELECT is required and how can you avoid it? Also, the @Transactional annotation above the method does not change this behaviour with or without it.

CodePudding user response:

It comes from not very clear behavior of @Transactional in Spring. @Transactional means two things:

  1. Opened persistent context (Hibernate session)
  2. A transaction itself.

You have the second select because in your case @Transactional doesn't work at all. Hibernate opens a new persistent context for each call

  1. myRepo.findById(1)
  2. myRepo.save(myEntity)

if you want to do a self call, you need to pass a reference to your service to the method where you call a transactional method.

class SomeServiceImpl implements SomeService {

    public void doWork(SomeService self) {
        self.someMethod();
    }

    @Transactional
    public void someMethod() {
        MyEntity myEntity = myRepo.findById(1).orElse(null);
        if (myEntity != null) {
            myEntity.setValue("something");
            myRepo.save(myEntity);
        }
    }

}

Another way is to autoware self to the service field. But it is not very good because you have to use autoware via filed injection. It is impossible to autoware using constructor. So it will be hard to do unit tests for a service.

  •  Tags:  
  • Related