在项目中看到有用到数据库的连接池,心里就思考着为什么需要数据库连接池,只用一个连接会造成什么影响?(只用一个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事务的使用。。。

探索多线程使用同一个数据库connection的后果的更多相关文章

  1. 使用FMDB多线程訪问数据库,及database is locked的问题

    今天最终攻克了多线程同一时候訪问数据库时,报数据库锁定的问题.错误信息是: Unknown error finalizing or resetting statement (5: database i ...

  2. 同一个数据库实例,不同用户下多表创建视图,Hibernate完毕ORM映射,Spring整合,后台实现

    1.同一个数据库实例.同用户,多表创建视图 2.同一个数据库实例,不同用户下.多表创建视图 3.同一个数据库,不同数据库实例,多表创建视图 4.不同类型数据库,多表创建视图 1.同一个数据库实例.同用 ...

  3. Java多线程操作同一个对象,线程不安全

    Java多线程操作同一个对象 发现问题:多个线程操作同一资源的情况下,线程不安全,数据紊乱 代码: package multithreading; // Java多线程操作同一个对象 // 买火车票的 ...

  4. 编写Java程序,实现多线程操作同一个实例变量的操作会引发多线程并发的安全问题。

    查看本章节 查看作业目录 需求说明: 多线程操作同一个实例变量的操作会引发多线程并发的安全问题.现有 3 个线程代表 3 只猴子,对类中的一个整型变量 count(代表花的总数,共 20 朵花)进行操 ...

  5. verification TLM传输数据导致多线程访问同一个数据

    TLM传输数据导致多线程访问同一个数据 原因 TLM发送数据跟mailbox类似,都是发送的引用,这样发送端和接收端的引用都指向同一个数据,这样就会出现发送端修改数据会影响到接收端,比如发送的时候数据 ...

  6. 多线程并发同一个表问题(li)

    现有数据库开发过程中对事务的控制.事务锁.行锁.表锁的发现缺乏必要的方法和手段,通过以下手段可以丰富我们处理开发过程中处理锁问题的方法.For Update和For Update of使用户能够锁定指 ...

  7. java 多线程访问同一个对象数据保护的问题

    java 多线程同时访问统一个数据的时候,会引起一些错误,后面的线程会修改数据,而前面的线程还在使用修改前的内容, 使用 synchronized 关键字,保证代码块只能有一个线程来访问 public ...

  8. JDBC获取数据库Connection的工具抽取

    使用JDBC获取数据库的连接,大字分为三个步骤 1.获取驱动包名,定义URL,database_username,database_password 2.获取Connection对象 3.利用Conn ...

  9. python多线程应用——DB2数据库备份

    前言:DB2一个实例下,可以存在多个数据库,之前使用shell备份脚本,但是同一时刻只能备份一个数据库,对于几百G的备份文件,这个速度显然太慢,今天学习了Python多线程,刚好应用一下. 分析:1. ...

随机推荐

  1. OpenXML操作word

    OpenXML概述 项目中经常需要操作word,之前的方式是采用COM接口,这个接口很不稳定,经常报错.现在开始采用OpenXML.OpenXML(OOXML)是微软在Office 2007中提出的一 ...

  2. 遇见了这个问题:App.config提示错误“配置系统未能初始化”

    解决办法查找之后居然是这样的,受教了,记录一下 解决: "如果配置文件中包含 configSections 元素,则 configSections 元素必须是 configuration 元 ...

  3. HDU3033I love sneakers!(分组背包)

    http://acm.hdu.edu.cn/showproblem.php?pid=3033 本题的意思就是说现在有n种牌子的鞋子,每种品牌有一些不同的鞋,每双鞋子都有一个特定的权值,现在要求每种品牌 ...

  4. conn,stmt,rset 的关闭(规范)

    Connection conn = null; Statement stmt = null; ResultSet rset = null; try { conn = dataSource.getCon ...

  5. 特现C语言编程特点的小代码,itoa,数值转换成字符串

    #define BASE_MAX (26 + 10) char const* itostr(int x, int base) { /* map 居中, 支技负余数 */ static char con ...

  6. Linux之sed,awk(流编辑器)

    sed:  s----substitute(替换) 1. 文本替换(使用-i选项,可以将结果应用于原文件) many people在进行替换之后,借助重定向来保存文件(未使用-i选项): $ sed  ...

  7. (剑指Offer)面试题23:从上到下打印二叉树

    题目: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 思路: 很明显,这是一个广度优先遍历. 需要一个队列容器来保存结点,具体操作: 1.将根结点压入队列中,并打印根结点:如果根结点有子结点 ...

  8. 为什么无法发起qq临时会话,必须添加好友?如何设置才能临时会话?

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-06-03) 一. QQ等级低于10级不能进行临时会话 按照腾讯的设置,QQ等级如果低于10级(2个月亮+2颗星星),无法发起 ...

  9. MFC子窗口和父窗口

    转载声明: 本文转载自:http://www.cnblogs.com/BeyondTechnology/archive/2011/03/25/1995934.html 感谢BeyondTechnolo ...

  10. ENTBOOST 2014.180L 发布,开源企业IM免费企业即时通讯

    ENTBOOST,VERSION 2014.180 Linux版本发布,主要增加企业IM应用集成功能,完善安卓SDK功能及部分BUG修正: 7/1(明天)发布Windows版本,敬请关注! ENTBO ...