spring多线程中事务处理

什么是事务:参考链接:https://blog.csdn.net/sinat_33536912/article/details/51200630

项目中遇到的问题:

在加有事务的类中启用线程,线程不会重新开启新的事务而是与当前类共用事务。事务的提交也是一起进行。

代码:

import com.transaction.dao.UserDao;
import com.transaction.handler.ThreadHandler;
import com.transaction.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
@Transactional
public class TestService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private ThreadHandler threadHandler;
    public void testTransaction (){
        try{
            User user=new User();
            user.setUserphone("18255556666");
            user.setUsername("孔空空");
            user.setCreateDate(new Date());
            userDao.insert(user);
            threadHandler.testHandler();
            System.out.println("线程执行完毕");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("testService 异常");
        }
    }
    //查询用户方法,多线程下调用
    public void selectUser (){
        System.out.println("查询开始");
        User user=userDao.selectUser("孔空空");
        System.out.println(user.getId());
    }
}

//多线程下查询用户数据
@Service("threadHandler")
public class ThreadHandler {
    public static Log logger = LogFactory.getLog(ThreadHandler.class);
    @Autowired
    private Executor taskAsyncPool;
    @Autowired
    private TestService testService;
    public void testHandler() {
        taskAsyncPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("测试多线程事务任务启动");
                try {
                    testService.selectUser();
                    Thread.sleep(1200000);
                    System.out.println("testHandler线程执行完毕");
                }catch(Exception e) {
                    e.printStackTrace();
                    logger.info("系统异常===="+e);
                }
            }
        });
    }
}

运行结果:抛出空指针异常。。。。。。。

原因:

testTransaction方法中调用线程去查询user表中的数据,在线程中让线程等待,保证testTransaction中的插入执行完毕,但是线程中调用查询方法时发现user表中并没有刚刚插入的数据,也就是testTransaction的事务没有提交,因为线程还没有执行完毕。通过这个实验发现,新开启的线程并没有开启新的事务,而是跟service中的方法公用同一个事务,这才导致查询方法中出现空指针异常的情况。

解决方法:在多线程的方法上加注解

@Transactional(propagation = Propagation.REQUIRES_NEW)

@Transactional(propagation = Propagation.REQUIRES_NEW)在多线程的方法或类上加上该注解,那么线程就会新开启一个事务,与service中的事务没有关系。service中方法执行完毕之后就提交它的事务,多线程的事务自己管理。

代码:

@Service("threadHandler")
public class ThreadHandler {
    public static Log logger = LogFactory.getLog(ThreadHandler.class);
    @Autowired
    private Executor taskAsyncPool;
    @Autowired
    private TestService testService;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testHandler() {
        taskAsyncPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("测试多线程事务任务启动");
                try {
                    testService.selectUser();
                    Thread.sleep(1200000);
                    System.out.println("testHandler线程执行完毕");
                }catch(Exception e) {
                    e.printStackTrace();
                    logger.info("系统异常===="+e);
                }
            }
        });
    }
}

加注解之后的结果:查询正常并没有出现空指针的情况

注意:在用该注解时,还发现了个问题,在同一类中使用Propagation.REQUIRES_NEW注解,该注解不作用,只有在不同的类中使用该注解才会重新开启新的事务。至于为什么还没有进行深究。。。。。

猜你喜欢

转载自blog.csdn.net/kongkongyanan/article/details/81703415