Spring @Transactional不起作用
我以前在这个问题上已经解决了一个职位。 但是,由于使用自动连线bean和较less的XMLconfiguration重build项目,我发现我正在重新审视这个问题。 我已经按照我以前的项目实施这个方式,但它不工作。 有人能帮助我为什么或者我应该改变什么来使它工作?
我有意使用插入用户详细信息方法中不存在的表名来故意引发exception。 但是,插入用户和插入用户angular色的语句不会回滚。 请帮忙。
我目前的注册devise是这样的。
部分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"/>
部分应用程序上下文 :
<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>
注册控制器 :
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"; } }
注册服务 :
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); } }
注册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; } }
将context:component-scan
标签移动到应用上下文xml的原因是固定了事务行为: <tx:annotation-driven />
是一个后置处理器,用一个AOP方法拦截器来处理@Transactional
注释的bean方法,行为。 Spring后处理器只能在定义的特定应用程序上下文中运行。
就你而言,你已经在应用上下文中定义了<tx:annotation-driven />
后处理器,而用@Transactional
注释的bean在servlet应用上下文中。 因此, <tx:annotation-driven />
后处理器仅对应用程序上下文bean进行操作,而不是对servlet上下文bean进行操作。 当context:component-scan
标签移动到应用程序上下文时, <tx:annotation-driven />
后置处理程序将其事务方法适当地包装起来。
希望这是有道理的。
[编辑]
应用程序上下文和Servlet上下文有什么区别?
什么是Spring后期处理器,它是如何工作的?
什么是春季AOP?