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.
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.
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.