zoukankan      html  css  js  c++  java
  • 探索多线程使用同一个数据库connection的后果

    在项目中看到有用到数据库的连接池,心里就思考着为什么需要数据库连接池,只用一个连接会造成什么影响?(只用一个connection)?

    1  猜想:jdbc的事务是基于connection的,如果多线程共用一个connection,会造成多线程之间的事务相互干扰。(connection.setAutoCommit(false);//connection.commit())

    2  于是就模仿以下场景来做一个测试:

       在多用户请求的情况下,只用一个数据库connection。

    1)获取connection工具类:

    package jdbcPool.util;

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;

    public class ConnectorUtil {
        
        public static final String user="root";
        
        public static final String pwd="123456";
        
        public static final String driver="com.mysql.jdbc.Driver";
        
        public static final String url ="jdbc:mysql://localhost:3306/test";
        
        private static Connection conn;
        
        private static int connectCount=0;
        
        
        static {
            try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                System.out.println("找不到数据库驱动..");
                e.printStackTrace();
            }
        }
        
        /**
         * 获取数据库连接实例
         * @return
         */
        public synchronized static Connection getInstance(){
            if(conn==null){
                try {
                    conn=DriverManager.getConnection(url,user, pwd);
                    conn.setAutoCommit(false);//设置为不自动提交。。。
                    connectCount++;
                    System.out.println("连接数据库次数:"+connectCount);
                } catch (SQLException e) {
                    System.out.println("连接数据库失败....");
                    e.printStackTrace();
                }
            }
            return conn;
        }
    }

    2) 业务接口实现类:

    package jdbcPool.business;

    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;

    import jdbcPool.util.ConnectorUtil;

    public class StudentService {
        
        private Connection conn;
        
        private static StudentService studentService;
        
        
        private StudentService(){
            conn=ConnectorUtil.getInstance();
        }
        
        public static synchronized  StudentService getInstance(){
            if(studentService==null){
                studentService=new StudentService();
            }
            return studentService;
        }
        
        public void insert(String id,String name,String no) throws Exception {
            String addStr ="insert into student(id,name,no) values('"+id+"','"+name+"','"+no+"')";
            Statement statement=null;
            try {
                statement = conn.createStatement();
                statement.execute(addStr);
                if("1350".equals(id)){//模仿某个线程执行service某个方法中某个步骤出现异常
                        Thread.sleep(3000);//模仿当前线程执行时间较长。。。。。
                        System.out.println("发生异常。。。。。");
                        System.out.println("记录"+id+"插入失败。。。。");
                        conn.rollback();  //出现异常事务回滚。。。
                        throw new Exception();
                  }else{
                        conn.commit();
                        System.out.println("记录"+id+"插入成功。。。。");
                  }          
            } catch (SQLException e) {
                System.out.println("创建statement失败");
                e.printStackTrace();
            }finally{
                if(statement!=null){
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    3)模拟用户请求的线程类:

    package jdbcPool.thread;

    import jdbcPool.business.StudentService;

    public class Request implements Runnable{
        
        private String id;
        
        
        public Request(String id) {
            this.id=id;
        }

        @Override
        public void run() {
            //模仿service的单例模式
            try {
                StudentService.getInstance().insert(this.id, "name"+id, "no"+id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    4) 测试类:

    package jdbcPool.test;
    import jdbcPool.thread.Request;


    public class Main {  
        //两百个线程并发访问同一个connection
        public static void main(String[] args){
            for(int i=1300;i<1500;i++){
                Thread th=new Thread(new Request(String.valueOf(i)));
                th.start();
            }
        }
    }

    5)结果分析:

    打印台出现的结果:

    记录1489插入成功。。。。
    记录1490插入成功。。。。
    记录1491插入成功。。。。
    记录1495插入成功。。。。
    记录1492插入成功。。。。
    记录1493插入成功。。。。
    记录1494插入成功。。。。
    记录1496插入成功。。。。
    记录1497插入成功。。。。
    记录1498插入成功。。。。
    记录1499插入成功。。。。
    记录1300插入成功。。。。
    发生异常。。。。。
    记录1350插入失败。。。。
    java.lang.Exception
        at jdbcPool.business.StudentService.insert(StudentService.java:38)
        at jdbcPool.thread.Request.run(Request.java:18)
        at java.lang.Thread.run(Unknown Source)

    数据库中的表数据:

     

        id为1350的记录竟然成功的添加进数据库了,造成这一现象的原因显然是

          在添加id为1350的记录的线程遇到异常还没有来得及数据回滚时,

        别的线程先调用了 connection.commit()方法,以至于把不该提交的数据提交到数据库了。

    6)  总结:在多线程的环境中,在不对connection做线程安全处理的情况下,使用单个connection会引起事务的混乱....影响jdbc事务的使用。。。

       

  • 相关阅读:
    php知识点
    CommonsChunkPlugin知识点
    待学习
    svn知识点
    es6知识点
    webpack2新特性
    排序算法
    交流措辞
    js继承
    多行编辑软件
  • 原文地址:https://www.cnblogs.com/swave/p/4363591.html
Copyright © 2011-2022 走看看