spring @Transactional não está funcionando

Eu já tinha uma postagem sobre esse problema que foi resolvida. No entanto, desde a reconstrução do projeto com beans com fio automático e menos configuração XML, descubro que estou revisitando esse problema. Eu segui a maneira como meu projeto anterior implementou isso, mas não funciona. Alguém pode me ajudar com o porquê ou o que devo mudar para que funcione?

Estou propositalmente usando um nome de tabela inexistente no método de detalhes do usuário de inserção para lançar deliberadamente uma exceção. No entanto, as instruções para inserir usuário e inserir funções do usuário não são revertidas. Por favor ajude.


Meu design atual para o registro é assim.

Parte do servlet.xml :

    

Parte do contexto da aplicação :

            

Controlador de registro:

 package com.doyleisgod.golfer.controllers; import javax.validation.Valid; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.doyleisgod.golfer.formdata.RegistrationForm; import com.doyleisgod.golfer.services.IRegistrationService; import com.doyleisgod.golfer.validators.RegistrationFormValidator; /** * Description: Registration controller provides and processes the registration form. * @author Chris Doyle */ @Controller @RequestMapping("/registration.htm") public class RegistrationController { protected final Log logger = LogFactory.getLog(getClass()); @Autowired private IRegistrationService iRegistrationService; @Autowired private RegistrationFormValidator registrationFormValidator; // sets a customer validator for the registration form @InitBinder protected void initBinder(WebDataBinder binder) { binder.setValidator(registrationFormValidator); } // Description: Method called by a get request to the registration controller. Returns the @RequestMapping(method=RequestMethod.GET) public String registration (Model model){ model.addAttribute(new RegistrationForm()); return "registration"; } // Description: Method called by a post request to the registration controller. Method calls validation on the registration form using custom validator and returning // any errors back to the user. @RequestMapping(method=RequestMethod.POST) public String processRegistration (@Valid RegistrationForm registrationForm, BindingResult bindingResult, Model model){ logger.info("Received the following registration form details"); logger.info(registrationForm.toString()); if (bindingResult.hasErrors()) { logger.warn("Registration Validation Failed"); model.addAttribute("validationError", "Please correct the fields marked with errors"); return "registration"; } try { iRegistrationService.registerUser(registrationForm); } catch (Exception e) { logger.error("An Exception has occured processing the registration form"); model.addAttribute("exceptionError", "An exception has occured, please try again."); e.printStackTrace(); return "registration"; } return "redirect:login.htm?registration=sucessful"; } } 

Serviço de registro:

 package com.doyleisgod.golfer.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.encoding.ShaPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronizationManager; import com.doyleisgod.golfer.dao.IRegistrationDAO; import com.doyleisgod.golfer.formdata.RegistrationForm; @Service("IRegistrationService") public class RegistrationService implements IRegistrationService { @Autowired private IRegistrationDAO iRegistrationDAO; private final boolean enabled = true; private final String roles = "ROLE_USER"; @Override @Transactional (rollbackFor = Exception.class) public void registerUser(RegistrationForm registrationForm) throws Exception { System.out.println("inside the registerUser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive()); String username = registrationForm.getUsername(); String password = registrationForm.getPassword(); String firstname = registrationForm.getFirstname(); String lastname = registrationForm.getLastname(); String email = registrationForm.getEmail(); int handicap = Integer.parseInt(registrationForm.getHandicap()); String encryptedPassword = ((new ShaPasswordEncoder()).encodePassword(password, username)); iRegistrationDAO.insertUser(username, encryptedPassword, enabled); iRegistrationDAO.insertRoles(username, roles); iRegistrationDAO.insertUserDetails(username, firstname, lastname, email, handicap); } @Override public boolean checkUser(String username) { return iRegistrationDAO.checkUserName(username); } } 

Registro DAO :

 package com.doyleisgod.golfer.dao; import javax.annotation.Resource; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.support.TransactionSynchronizationManager; @Repository("iRegistrationDAO") public class RegistrationDAO extends JdbcTemplate implements IRegistrationDAO { @Resource private BasicDataSource dataSource; @Override public boolean checkUserName(String username) { int db_user = queryForInt("select count(username) from users where username = ?", username); if (db_user == 1 ){ return true; } return false; } @Override public void insertUser(String username, String password, boolean enabled) throws Exception { System.out.println("inside the insertuser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive()); update("insert into users (username, password, enabled) VALUES (?,?,?)", username, password, enabled); } @Override public void insertRoles(String username, String roles) throws Exception { update("insert into user_roles (username, authority) VALUES (?,?)", username, roles); } @Override public void insertUserDetails(String username, String firstname, String lastname, String email, int handicap) throws Exception { update("insert into user_detailss (username, first_name, last_name, email_address, handicap)" + "VALUES (?,?,?,?,?)", username, firstname, lastname, email, handicap); } public void setDataSource(BasicDataSource dataSource) { this.dataSource = dataSource; } public BasicDataSource getDataSource() { return dataSource; } } 

O motivo pelo qual mover o context:component-scan tags de context:component-scan para o contexto de aplicativo xml corrigido o comportamento transacional é: é um pós-processador que encapsula methods de bean anotados @Transactional com um interceptor de método AOP que manipula transacional comportamento. Os pós-processadores da mola operam apenas no contexto de aplicativo específico no qual estão definidos.

No seu caso, você definiu o pós-processador no contexto do aplicativo, enquanto os beans anotados com @Transactional estão no contexto do aplicativo de servlet. Portanto, o pós-processador operava apenas nos beans de contexto do aplicativo, não nos beans de contexto do servlet. Quando o context:component-scan tags de context:component-scan foram movidas para o contexto do aplicativo, o pós-processador envolveu seus methods transacionais apropriadamente.

Espero que isso faça algum sentido.

[Editar]

Qual é a diferença entre o contexto de aplicativo e um contexto de servlet?

O que é um pós-processador da Spring e como funciona?

O que é AOP na primavera?