Spring @Transactional no funciona

Anteriormente tuve una publicación sobre este tema que se resolvió. Sin embargo, desde la reconstrucción del proyecto con beans autoalambrados y menos configuración XML, encuentro que estoy volviendo a visitar este tema. He seguido la forma en que mi proyecto anterior implementó esto, pero no funciona. ¿Alguien puede ayudarme con por qué o qué debería cambiar para que funcione?

Estoy deliberadamente utilizando un nombre de tabla inexistente en el método de inserción de detalles del usuario para arrojar deliberadamente una excepción. Sin embargo, las instrucciones para insertar usuario e insertar roles de usuario no se revierten. Por favor ayuda.


Mi diseño actual para el registro es así.

Parte de servlet.xml :

    

Parte del contexto de la aplicación :

            

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"; } } 

Servicio 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; } } 

El motivo por el que se mueve el context:component-scan tags de context:component-scan para el contexto xml de la aplicación se corrigió el comportamiento transaccional es: es un post-procesador que ajusta los métodos de bean anotados @Transactional con un interceptor de método AOP que maneja transacciones comportamiento. Los postprocesadores de spring solo operan en el contexto de aplicación específico en el que están definidos.

En su caso, ha definido el postprocesador en el contexto de la aplicación, mientras que los beans anotados con @Transactional están en el contexto de la aplicación de servlet. Por lo tanto, el postprocesador solo operaba en los beans de contexto de la aplicación, no en los beans de contexto del servlet. Cuando el context:component-scan tags de context:component-scan se movieron al contexto de la aplicación, entonces el postprocesador envolvió sus métodos transaccionales apropiadamente.

Espero que tenga sentido.

[Editar]

¿Cuál es la diferencia entre el contexto de la aplicación y el contexto del servlet?

¿Qué es un postprocesador de Spring y cómo funciona?

¿Qué es AOP en spring?