2.7. Transactionality

As of version 2.0 Hades CRUD methods on DAO instances are transactional by default. For reading operations the transaction configuration readOnly flag is set to true, all others are configured with a plain @Transactional so that default transaction configuration applies. For details see JavaDoc of GenericJpaDao. If you need to tweak transaction configuration for one of the methods declared in GenericDao simply redeclare the method in your DAO interface as follows:

Example 2.25. Custom transaction configuration for CRUD

public interface UserDao extends GenericDao<User, Long> {

  @Override
  @Transactional(timeout = 10)
  public List<User> readAll();

  // Further DAO method declarations
}

This will cause the readAll() method to be executed with a timeout of 10 seconds and without the readOnly flag.


Another possibility to alter transactional behaviour is by using a facade or service implementation that typically covers more than one DAO the. Its purpose is to define transactional boundaries for non-CRUD operations:

Example 2.26. Using a facade to define transactions for multiple DAO calls

@Service
class UserManagementImpl implements UserManagement {

  private final UserDao userDao;
  private final RoleDao roleDao;

  @Autowired
  public UserManagementImpl(UserDao userDao, RoleDao roleDao) {
    this.userDao = userDao;
    this.roleDao = roleDao;
  }

  @Transactional
  public void addRoleToAllUsers(String roleName) {

    Role role = roleDao.findByName(roleName);

    for (User user : userDao.readAll()) {
      user.addRole(role);
      userDao.save(user);
    }
}

This will cause call to addRoleToAllUsers(…) to run inside a transaction (participating in an existing one or create a new one if none already running). The transaction configuration at the DAOs will be neglected then as the outer transaction configuration determines the actual one used. Note that you will have to activate <tx:annotation-driven /> explicitly to get annotation based configuration at facades working. The example above assumes you're using component scanning.


2.7.1. Transactional query methods

To let your query methods be transactional simply use @Transactional at the DAO interface you define.

Example 2.27. Using @Transactional at query methods

@Transactional(readOnly = true)
public interface UserDao extends GenericDao<User, Long> {

  List<User> findByLastname(String lastname);

  @Modifying
  @Transactional
  @Query("delete from User u where u.active = false")
  void deleteInactiveUsers();
}

Typically you will use the readOnly flag set to true as most of the query methods will be reading ones. In contrast to that deleteInactiveUsers() makes use of the @Modifying annotation and overrides the transaction configuration. Thus the method will be executed with readOnly flag set to false.


Note

It's definately reasonable to use transactions for read only queries as we can mark them as such by setting the readOnly flag. This will not act as check that you do not trigger a manipulating query nevertheless (although some databases reject e.g. INSERT or UPDATE statements inside a transaction set to be read only) but gets propagated as hint to the underlying JDBC driver to do performance optimizations. Furthermore Spring will do some optimizations to the underlying JPA provider. E.g. when used with Hibernate the flush mode is set to NEVER when you configure a transaction as read only which causes Hibernate to skip dirty checks that gets quite noticeable on large object trees.