spring中事务和同步锁的采坑日记

/ 默认分类 / 0 条评论 / 954浏览

一.问题描述

@ResponseBody
    @Transactional
    @GetMapping("/up")
    public String up(String upid,HttpServletRequest request) {
        synchronized (this)
        {
            System.out.println("开始"+new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()));
            User loginUser = (User)request.getSession().getAttribute("loginUser");
            User userTemp = userMapper.getUserByUid(upid);
            System.out.println(request.getHeader("User-Agent")+"取出来了==="+userTemp.getUpcount());
            userTemp.setUpcount(userTemp.getUpcount()+1);
            userMapper.updateUser(userTemp);
            System.out.println(request.getHeader("User-Agent")+"更新完了==="+userTemp.getUpcount());
            System.out.println("结束"+new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()));
            return String.valueOf(userTemp.getUpcount());
        }
//      }
    }

上面的代码是我为了测试方便,改的,所以业务方面都没有,是测试的

Thread thread01 = new Thread(()->{
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"--"+i+'次');
            uptest(Thread.currentThread().getName()+i);
        }
    },"A");
    Thread thread02 = new Thread(()->{
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"--第"+i+'次');
            uptest(Thread.currentThread().getName()+i);
        }
    },"B");
    thread01.start();
    thread02.start();
public static void uptest(String rename)
    {
        try {
            try {
//                HttpClient httpclient = HttpClients.custom().build();
                HttpClient httpclient = HttpClients.custom().setDefaultCookieStore(STORE).build();
                HttpGet httpGet = new HttpGet();
                httpGet.setHeader("User-Agent", rename);
                httpGet.setHeader("Accept-Encoding", "gzip, deflate, br");
                httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
                httpGet.setHeader("accept", "text/plain, */*; q=0.01");
                httpGet.setHeader("X-Requested-With","XMLHttpRequest");
                httpGet.setURI(new URI(url));
                HttpResponse httpresponse = httpclient.execute(httpGet);
                response = EntityUtils.toString(httpresponse.getEntity());
                System.out.println(Thread.currentThread().getName()+" ===返回数据=== "+response.toString());
            }
            catch (Exception a)
            {
                a.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
开始2020-04-09 18:16:10
A0取出来了===1
A0更新完了===2
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B0取出来了===2
B0更新完了===3
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A1取出来了===3
A1更新完了===4
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B1取出来了===4
B1更新完了===5
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A2取出来了===5
A2更新完了===6
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B2取出来了===6
B2更新完了===7
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A3取出来了===6
A3更新完了===7
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B3取出来了===7
B3更新完了===8
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A4取出来了===8
A4更新完了===9
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B4取出来了===9
B4更新完了===10
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A5取出来了===10
A5更新完了===11
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
B5取出来了===11
B5更新完了===12
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A6取出来了===12
A6更新完了===13
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
B6取出来了===13
B6更新完了===14
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
A7取出来了===14
A7更新完了===15
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
B7取出来了===15
B7更新完了===16
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
A8取出来了===16
A8更新完了===17
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
B8取出来了===17
B8更新完了===18
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
A9取出来了===18
A9更新完了===19
结束2020-04-09 18:16:12
开始2020-04-09 18:16:12
B9取出来了===19
B9更新完了===20
结束2020-04-09 18:16:12

上面是打印出来的日志记录,可以发现:

开始2020-04-09 18:16:11
B2取出来了===6
B2更新完了===7
结束2020-04-09 18:16:11
开始2020-04-09 18:16:11
A3取出来了===6
A3更新完了===7
结束2020-04-09 18:16:11

也就是说B2和A3似乎同时获得了synchronize同步锁,这........

二.问题分析

三.问题解决








    @Service
    public class CommonService {

    @Autowired
    UserMapper userMapper;

    @Transactional
    public User getUserByUid(String upid)
    {
       return userMapper.getUserByUid(upid);
    }

    @Transactional
    public void updateUser(User user)
    {
        userMapper.updateUser(user);
    }

    }
 @ResponseBody
    @GetMapping("/up")
    public String up(String upid,HttpServletRequest request) {
        synchronized (this)
        {
            System.out.println("开始"+new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()));
            User loginUser = (User)request.getSession().getAttribute("loginUser");
            User userTemp = commonService.getUserByUid(upid);
            System.out.println(request.getHeader("User-Agent")+"取出来了==="+userTemp.getUpcount());
            userTemp.setUpcount(userTemp.getUpcount()+1);
            commonService.updateUser(userTemp);
            System.out.println(request.getHeader("User-Agent")+"更新完了==="+userTemp.getUpcount());
            System.out.println("结束"+new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss").format(new Date()));
            return String.valueOf(userTemp.getUpcount());
        }
    }