2012-04-04 12 views
17

Poprzednio miałem post na ten problem, który został rozwiązany. Jednak od czasu przebudowy projektu z automatycznym wiązaniem fasoli i mniejszą konfiguracją XML stwierdzam, że ponownie analizuję ten problem. Postępowałem zgodnie ze sposobem, w jaki realizował to mój poprzedni projekt, ale to nie działa. Czy ktoś może mi pomóc, dlaczego lub co powinienem zmienić, aby to zadziałało?Spring @ Transactional nie działa

Celowo używam nieistniejącej nazwy tabeli w metodzie wstawiania szczegółów użytkownika, aby celowo wyrzucić wyjątek. Jednak instrukcje wstawiania użytkownika i wstawiania ról użytkownika nie są wycofywane. Proszę pomóż.


Mój obecny projekt rejestracji jest właśnie taki.

Część servlet.xml:

<context:component-scan base-package="com.doyleisgod.golfer.controllers"/> 
<context:component-scan base-package="com.doyleisgod.golfer.dao"/> 
<context:component-scan base-package="com.doyleisgod.golfer.services"/> 
<context:component-scan base-package="com.doyleisgod.golfer.validators"/> 


Część kontekst aplikacji:

<context:annotation-config /> 
<tx:annotation-driven />  

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
<property name="driverClassName" value="${jdbc.driverClassName}"/> 
<property name="url" value="${jdbc.url}"/> 
<property name="username" value="${jdbc.username}"/> 
<property name="password" value="${jdbc.password}"/> 
</bean> 

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource"/> 
</bean> 


Rejestracja kontroler:

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


Rejestracja serwis:

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


Rejestracja 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; 
    } 
} 
+0

Problem wydawał się z konieczności skanów dla elementów składowych innych niż regulatorów w XML serwletu. Przeniosłem kontekst 'W kontekście xml aplikacji, który wydawał się rozwiązać problem.Nie jestem pewny, dlaczego tak, jeśli ktoś chce podać przyczynę, dlaczego prace te spadły swobodnie post. –

Odpowiedz

39

Dlatego, że przeniesienie context:component-scan tagów xml kontekstowego aplikacji stałe zachowanie transakcyjną jest : <tx:annotation-driven /> to postprocesor, który owija @Transactional metody z adnotacjami ziarnistymi za pomocą przechwytywacza metody AOP, który obsługuje zachowanie transakcyjne. Wiosenne postprocesory działają tylko w określonym kontekście aplikacji, w którym są zdefiniowane.

W twoim przypadku zdefiniowałeś post-procesor <tx:annotation-driven /> w kontekście aplikacji, podczas gdy fasole opatrzone komentarzem @Transactional znajdują się w kontekście aplikacji serwletów . Tak więc postprocesor <tx:annotation-driven /> działał tylko na komponentach kontekstowych aplikacji, a nie na komponentach kontekstowych serwletu. Kiedy znaczniki context:component-scan zostały przeniesione do kontekstu aplikacji, wówczas post-procesor <tx:annotation-driven /> odpowiednio opakował swoje metody transakcyjne.

Mam nadzieję, że ma to jakiś sens.

[Edycja]

What is the difference between the Application Context and a Servlet Context?

What is a Spring post-processor and how does it work?

What is AOP in Spring?

+0

Myślałem, że Spring MVC * wymaga * kontrolera' @ być zeskanowanym z kontekstu DispatcherServlet, a nie z kontekstu głównego kontekstu ContextLoaderListener, dlatego jestem zaskoczony, że przenoszenie skanowania '@ Controller' również do kontekstu aplikacji nadal powoduje działanie' @ RequestMapping'. (Rzeczywiście, pozwoli jeden do użycia '@ Transactional' na zajęciach' @ Controller', po prostu zastanawiasz się nad efektami ubocznymi.) – Arjan

+0

(Szybki * * test usuwający skanowanie '@ Controller' z kontekstu DispatcherServlet i skanujący wszystko z kontekstu aplikacji, rzeczywiście sprawia, że ​​wszystkie moje "@ RequestMapping" są ignorowane, i tym samym zawodzą.) – Arjan

+2

OP stwierdza w komentarzach, że przeniósł dao i komponent usług skanowania w kontekst aplikacji, który naprawił problem z Transakcją. Pytanie w komentarzu brzmiało: dlaczego, na co odpowiedziałem. OP NIE przeniesiono skanowania składników dla kontrolerów MVC poza kontekst serwletu. Dlatego nie jestem pewien, o co chodzi z tymi komentarzami z @Arjan. – MarkOfHall