spring事务回滚处理+多线程异步处理

spring事务回滚处理:

准备:配置好spring+mybatis环境。

一、XML方式配置spring事务处理

第一步: spring.xml配置:

  <tx:advice id="apptxAdvice" transaction-manager="txManager">
		<tx:attributes>
			<!-- 需要回滚的方法都写在这 -->
			<tx:method name="trade*" read-only="false" rollback-for="Exception"/>
		</tx:attributes>
	</tx:advice>
	
	<aop:config>
		<aop:pointcut id="appServiceOperation" expression="execution(* org.jun.service..*Service.*(..))" />
		<aop:advisor pointcut-ref="appServiceOperation" advice-ref="apptxAdvice" />
	</aop:config>

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

第二步:编写测试代码:

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


第三步:结果分析:

如果事务正常回滚,表中数据无变化。

如果事务没有回滚,表中对应记录的余额被更新,但没有新添加的记录

spring事务回滚处理+多线程异步处理

第四步:如果事务无法回滚:

检查:确认有抛异常,确认扫描包的位置正确,确认没有重复扫描对应包。

通常只会在service层处理事务回滚操作.


一、注解方式配置spring事务处理

XML配置:
spring.xml:
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource" />
	</bean>
	<tx:annotation-driven transaction-manager="txManager"/>
    
 	<context:component-scan base-package="org.web.service">
  		<context:exclude-filter type="annotation" expression="org.springframework.transaction.annotation.Transactional" /> 
 	</context:component-scan>

springmvc.xml:
<context:component-scan base-package="org.web.controller"/> 

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只扫描一次,重复扫描会导致事务失效。

操作结果:

spring事务回滚处理+多线程异步处理

多线程异步处理:

/*** 
    用户注册接口
    @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<String, Integer> 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<Runnable>(), 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;
    }
}


你可能感兴趣的:(spring事务回滚处理+多线程异步处理)