问题描述
我以前有一个关于此问题的帖子已得到解决.但是,由于使用自动有线Bean和较少的XML配置重建项目,因此我发现自己正在重新研究此问题.我遵循了我以前的项目实现此方法的方式,但是没有用.有人可以为我提供帮助,为什么我应该做出什么改变?
I previously had a post on this issue that was resolved. However since rebuilding the project with auto wired beans and less XML configuration I find I am revisiting this issue. I have followed the way my previous project implemented this but it doesn't work. Can someone help me with why or what I should change to make it work?
我故意在insert用户详细信息方法中使用不存在的表名来故意引发异常.但是,insert user和insert user角色的语句不会回滚.请帮忙.
I am on purpose using a non existent table name in the insert user details method to deliberately throw an exception. However the statements for insert user and insert user roles are not rolled back. Please help.
我当前的注册设计是这样的.
My current design for the registration is like this.
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"/>
应用程序上下文的一部分:
Part of application context:
<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 />
是包装了@Transactional
的后处理器.带注释的Bean方法,带有处理事务行为的AOP方法拦截器. Spring后处理器只能在定义它们的特定应用程序上下文中运行.
The reason that moving the context:component-scan
tags to the application context xml fixed the transactional behavior is: <tx:annotation-driven />
is a post-processor that wraps @Transactional
annotated bean methods with an AOP method interceptor which handles transactional behavior. Spring post-processors, only operate on the specific application context they are defined in.
在您的情况下,您已经在应用程序上下文中定义了<tx:annotation-driven />
后处理器,而用@Transactional
注释的bean在servlet应用程序上下文中.因此,<tx:annotation-driven />
后处理器仅在应用程序上下文Bean上运行,而不在Servlet上下文Bean上运行.当context:component-scan
标记移至应用程序上下文时,<tx:annotation-driven />
后处理器适当地包装了它们的事务方法.
In your case, you have defined the <tx:annotation-driven />
post-processor in the application context, while the beans annotated with @Transactional
are in the servlet application context. Thus, the <tx:annotation-driven />
post-processor only operated on the application context beans, not the servlet context beans. When the context:component-scan
tags were moved to the application context, then the <tx:annotation-driven />
post-processor wrapped their transactional methods appropriately.
希望如此.
这篇关于Spring @Transactional无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!