spring事务回滚处理:
准备:配置好spring+mybatis环境。
一、XML方式配置spring事务处理
第一步: spring.xml配置:
第二步:编写测试代码:
TestController.java
package org.jun.controller;
import org.jun.controller.base.AbstractController;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
*
* @author xiejunbo
*
**/
@Controller
@RequestMapping("test")
public class TestController extends AbstractController {
@ResponseBody
@RequestMapping("trade")
public String trade(){
try {
testService.trade();
} catch (Exception e) {
logger.error("[error] trade error!" + e);
}
return "success";
}
}
==============================================================================
TestService.java
package org.jun.service;
/**
*
* @author xiejunbo
*
**/
public interface TestService {
void trade() throws Exception;
}
==========================================================================
TestServiceImpl.java
package org.jun.service;
import javax.annotation.Resource;
import org.jun.mapper.TestMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author xiejunbo
*
**/
@Service
public class TestServiceImpl implements TestService {
@Resource
private TestMapper testMapper;
public void trade() throws Exception{
try {
testMapper.updateBalance();
int i = 10/0;
testMapper.record();
} catch (RuntimeException e) {
throw new Exception(e);
}
}
}
第三步:结果分析:
如果事务正常回滚,表中数据无变化。
如果事务没有回滚,表中对应记录的余额被更新,但没有新添加的记录
第四步:如果事务无法回滚:
检查:确认有抛异常,确认扫描包的位置正确,确认没有重复扫描对应包。
通常只会在service层处理事务回滚操作.
一、注解方式配置spring事务处理
XML配置:
spring.xml:
springmvc.xml:
TestController.java:
package org.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.web.controller.base.AbstractController;
import org.web.domain.User;
@Controller
@RequestMapping("test")
public class TestController extends AbstractController{
@ResponseBody
@RequestMapping("trade")
public String trade() {
try {
User u = new User();
u.setId(1);
u.setUsername("xiejunbo");
u.setPwd("123456");
testService.trade(u);
} catch (Exception e) {
logger.error("[error]" + e);
}
return "success";
}
}
TestServiceImpl.java:
package org.web.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.web.domain.User;
import org.web.mapper.TestMapper;
import org.web.service.TestService;
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestMapper testMapper;
@Transactional(rollbackFor=Exception.class)
public void trade(User u) throws Exception {
try {
testMapper.substract(u);
u.setId(2);
testMapper.add(u);
testMapper.record(u);
int i = 10/0;
} catch (Exception e) {
throw new Exception(e);
}
}
}
注意:扫描包时,对事务注解annotation只扫描一次,重复扫描会导致事务失效。
操作结果:
多线程异步处理:
/***
用户注册接口
@RequestMapping("/register")
@ResponseBody
public Resp register(final User user, String verifyCode, HttpServletRequest request, HttpServletResponse response)
throws FileNotFoundException {
final String password = user.getPwd();
User result = null;
Map ageAndConstell = CommonHelper.getAgeAndConstell(user.getBirth());
try {
result = resource.createUser(user);
if (result != null) { // 异步注册
user.setId(result.getId());
threadPool.execute(new Runnable() {
@Override
public void run() {
String imid = CryptUtil.md5(user.getPhone());
String username = hx.register(imid, password, user.getNick());
if (StringUtils.isNotBlank(username)) { // 注册成功
user.setImid(imid);
redis.set(Consts.Cache.USER_PREFIX + user.getId(), user);
} else { //注册失败
log.error("register error imid:{}", imid);
}
}
});
}
} catch (Exception e) {
log.error("[/user/register] error ", e);
return error(e);
}
return result != null ? success(user, "注册成功") : fail(); // 将user返回
}
@Autowired
protected ThreadPool threadPool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPool extends ThreadPoolExecutor {
private String poolName;
/**
* 创建线程数固定大小的线程池
*
* @param poolSize
* @param poolName 线程池的名称必须设置
*/
public ThreadPool(int poolSize, String poolName) {
super(poolSize, poolSize, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamingThreadFactory(
poolName));
this.poolName = poolName;
}
public String getPoolName() {
return poolName;
}
public void setPoolName(String poolName) {
this.poolName = poolName;
}
private static class NamingThreadFactory implements ThreadFactory {
private String threadName;
private AtomicInteger counter = new AtomicInteger(1);
public NamingThreadFactory(String threadName) {
this.threadName = threadName;
}
@Override
public Thread newThread(Runnable r) {
int index = counter.getAndIncrement();
return new Thread(r, threadName + "-" + index);
}
}
public String toString() {
String str = super.toString();
int idx = str.indexOf("[");
if (idx == -1) {
return "[name = " + poolName + "]";
}
String s = str.substring(idx + 1);
return "[name = " + poolName + ", " + s;
}
}