java多线程代码无法运行

belizer 发布于 2018/03/02 09:51
阅读 781
收藏 0

    昨天在学习mybatis的时间,讲到返回主键问题,其中有一种方法使用selectKey标签。这里我产生了这样一个疑问,mybatis使用的环境一般是web环境。这个环境是多线程的。那么在多线程环境中使用selectKey标签会不会存在问题。会不会存在这种情况:在一个线程插入了一条数据的时候。在它没有获取主键的之前,另一个线程也插入了一条数据。那么前一个线程通过selectKey标签获取的主键是不是就不是他的实际主键了?(数据库使用的是mysql,我不知道mysql默认事务隔离级别会不会阻止这种情况的发生)

    在有疑问的时间最恰当的方式是写代码演示,我简单写了一下:

    mapper.xml文件,

    

    我写了一个测试类,

    

  /**
     * 模拟现实环境中,多线程插入,观察使用selectKey标签获取的key是否会出现问题。
     */
    @Test
    public void insert3Test2(){

        Thread t1=new Thread(){
            @Override
            public void run() {
                SqlSession sqlSession=getSqlSession();
                try {
                    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
                    SysUser user=new SysUser();
                    user.setUserName ("testl");
                    user.setUserPassword("123456");
                    user.setUserEmail("test@mybatis.tk");
                    user.setUserInfo("test info");
                    //正常情况下应该读入一张图片存到byte 数纽中
                    user.setHeadImg(new byte[]{1 , 2 , 3});
                    user.setCreateTime(new Date());
                    //将新建的对象插入数据库中,特别注意这里的返回值result 是执行的SQL 影响的行数
                    int result= userMapper.insert2(user);

                    Assert.assertEquals(result,1);//
                    System.out.println("t1--"+user.getId());
                }finally {
                    //默认情况下,sqlSessionFactory.openSession()获得的session是不会主动提交修改到数据库的。
                    sqlSession.commit();
                    sqlSession.close();
                }
            }
        };

        Thread t2=new Thread(){
            @Override
            public void run() {
                SqlSession sqlSession=getSqlSession();
                try {
                    UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
                    SysUser user=new SysUser();
                    user.setUserName ("test2");
                    user.setUserPassword("123456");
                    user.setUserEmail("test2@mybatis.tk");
                    user.setUserInfo("test2 info");
                    //正常情况下应该读入一张图片存到byte 数纽中
                    user.setHeadImg(new byte[]{1 , 2 , 3});
                    user.setCreateTime(new Date());
                    //将新建的对象插入数据库中,特别注意这里的返回值result 是执行的SQL 影响的行数
                    int result= userMapper.insert2(user);

                    Assert.assertEquals(result,1);//
                    System.out.println("t2--"+user.getId());
                }finally {
                    //默认情况下,sqlSessionFactory.openSession()获得的session是不会主动提交修改到数据库的。
                    sqlSession.commit();
                    sqlSession.close();
                }
            }
        };
        t1.start();
        t2.start();
    }

getSqlSession方法继承自基础测试类中,以下是基础测试类的代码,

package com.belizer.mybatis.simple;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;

import java.io.IOException;
import java.io.Reader;

/**
 * Created by 47131 on 2018/2/28.
 */
public class BaseMapperTest {
    private  static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public  static void init(){
        try {
            Reader reader= Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public SqlSession getSqlSession(){
        return  sqlSessionFactory.openSession();
    }
}

但是代码是有问题的,没有打印出结果。我debug之后只知道代码有问题的地方在所创建线程的run方法内,求教大神,run方法内的代码有什么问题?如果你也按照上面的方式写了测试代码,我还有一个问题,这种情况是不是线程内有异常,如果有异常的话,它为什么没有在控制台打印,我怎么捕获这个异常?

加载中
0
MatchL
MatchL

http://blog.csdn.net/qq_29227939/article/details/52029065  去看看这篇文章,理解下线程安全。

b
belizer
回复 @belizer : 代码的问题是两个线程没有运行完,主线程就已经结束了
b
belizer
Mybatis会推测出parameterType,肯定不是这个原因
MatchL
MatchL
回复 @belizer : sql 问题其一,parameterType 没有指定user实体类 ,parameterType =“xxx.xxx.User”
b
belizer
看了,没明白为什么要用ThreadLocal,就算象我现在这样的代码,sqlSession也是每个线程一个啊?
0
郭里奥

你的sql的问题

 

0
b
belizer

sql有什么问题?

0
b
bluefly

sqlSession是线程不安全的 你这么弄肯定有问题啊  还是先去看看一楼的文章 在做把

b
belizer
是啊,SqlSession是每个线程一个,并不是共享变量。
郭里奥
人家的sqlsession是每个线程一个,并没有进行共享啊
0
很成立
很成立

Test是主线程结束,其他线程会直接关闭的,看看是不是这个问题,主线程弄个while一直sleep。。。

返回顶部
顶部