I am new to Spring Transaction. Something that I found really odd, probably I did understand this properly.
I wanted to have a transactional around method level and
With Spring 4 it's possible to Self autowired
@Service
@Transactional
public class UserServiceImpl implements UserService{
@Autowired
private UserRepository repository;
@Autowired
private UserService userService;
@Override
public void update(int id){
repository.findOne(id).setName("ffffd");
}
@Override
public void save(Users user) {
repository.save(user);
userService.update(1);
}
}
Starting from Java 8 there's another possibility, which I prefer for the reasons given below:
@Service
public class UserService {
@Autowired
private TransactionHandler transactionHandler;
public boolean addUsers(List<User> users) {
for (User user : users) {
transactionHandler.runInTransaction(() -> addUser(user.getUsername, user.getPassword));
}
}
private boolean addUser(String username, String password) {
// TODO call userRepository
}
}
@Service
public class TransactionHandler {
@Transactional(propagation = Propagation.REQUIRED)
public <T> T runInTransaction(Supplier<T> supplier) {
return supplier.get();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public <T> T runInNewTransaction(Supplier<T> supplier) {
return supplier.get();
}
}
This approach has the following advantages:
It may be applied to private methods. So you don't have to break encapsulation by making a method public just to satisfy Spring limitations.
Same method may be called within different transaction propagation and it is up to the caller to choose the suitable one. Compare these 2 lines:
transactionHandler.runInTransaction(() -> userService.addUser(user.getUserName, user.getPassword)); transactionHandler.runInNewTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
It is explicit, thus more readable.