Vitaly Vitrenko Vitaly Vitrenko - 1 month ago 8
Java Question

Invoke flush() on a repository or service layer?

For example I have the following classes

@Repository
public class JpaUserRepository implements UserRepository {
...
public void create(User user) {
entityManager.persist(user);
}
}

@Trensactional
public class UserServiceImpl implements UserService {
...
public void register(User user) {
try {
repository.create(user);
} catch (DataIntegrityViolationException ex) {
throw new UserAlreadyExistException(user);
}
}
}


There is a problem with this approach. Jpa does not throw any exception until the transaction will be commited or
EntityManager#flush()
will be invoked.

I have two solutions. First is to add a flush() method to the UserRepository interface, and invoke
repository.flush()
after
repository.create(user)
in
UserServiceImpl#create
method. And second is invoke
entityManager.flush()
after
entityManager.persist(user)
in
JpaUserRepository#create
method and document it on the UserRepository interface.

The First solution is not quite flexible because another implementation of UserRepository may not use an instruction cache but must implement flush() method. But as I know JpaRepository from Spring Data uses it. What approach will be best in this situation from the point view of flexibility?

Answer

I solved this problem something like that

public class JpaCrudRepository<T, PK extends Serializable> implements CrudRepository<T, PK> {
    private boolean flushOnCreate = true

    public JpaCrudRepository(boolean flushOnCreate) {
        this.flushOnCreate = flushOnCreate;
    }


     /**
     * Persist the given entity to repository and flushes all instructions if isFlushOnCreate() == true
     * @param entity persisted entity
     */
    @Override
    public void create(T entity) {
        entityManager.persist(entity);
        if (flushOnCreate) {
            entityManager.flush();
        }
    }
}

@Repository
public class JpaUserRepository extends JpaCrudRepository<User, Long> implements UserRepository {

    public JpaUserRepository() {
        super(true);
    }
    .....
}

Service layer is remained without changes.