探索多线程使用同一个数据库connection的后果

2023-11-08

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

 

   

转载于:https://www.cnblogs.com/swave/p/4363591.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • Java - 因内存不足错误而关闭

    关于如何最好地处理这个问题 我听到了非常矛盾的事情 并且陷入了以下困境 OOME 会导致一个线程崩溃 但不会导致整个应用程序崩溃 我需要关闭整个应用程序 但不能 因为线程没有剩余内存 我一直认为最佳实践是让它们离开 这样 JVM 就会死掉
  • 获取文件的锁

    我想在对特定文件开始 threo read 时获取文件上的锁定 以便其他应用程序无法读取已锁定的文件并希望在线程终止时释放锁定文件 您可以获得一个FileLock https docs oracle com javase 8 docs ap
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • 当路径的点超出视野时,Android Canvas 不会绘制路径

    我在绘制路径时遇到了 Android Canvas 的一些问题 我的情况是 我有一个相对布局工作 如地图视图 不使用 google api 或类似的东西 我必须在该视图上绘制一条路径 canvas drawPath polyPath bor
  • 如何强制jar使用(或jar运行的jvm)utf-8而不是系统的默认编码

    我的Windows默认编码是GBK 而我的Eclipse完全是utf 8编码 因此 在我的 Eclipse 中运行良好的应用程序崩溃了 因为导出为 jar 文件时这些单词变得不可读 我必须在 bat 文件中写入以下行才能运行该应用程序 st
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • 在 Struts 2 中传递 URL 参数而不使用查询字符串

    我想使用类似的 URL host ActionName 123 abc 而不是像这样传递查询字符串 host ActionName parm1 123 parm2 abc 我怎样才能在 Struts 2 中做到这一点 我按照下面的方法做了
  • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

    这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
  • 为什么 MOVE CURSOR 在 OS X Mountain Lion 上不显示?

    我正在做一个项目 想看看 Swing 提供的每个光标是什么样子的 public class Test public static void main String args JFrame frame new JFrame frame set
  • Android蓝牙java.io.IOException:bt套接字已关闭,读取返回:-1

    我正在尝试编写一个代码 仅连接到运行 Android 5 0 KitKat 的设备上的 目前 唯一配对的设备 无论我尝试了多少方法 我仍然会收到此错误 这是我尝试过的最后一个代码 它似乎完成了我看到人们报告为成功的所有事情 有人能指出我做错
  • 如何通过注解用try-catch包装方法?

    如果应该在方法调用中忽略异常 则可以编写以下内容 public void addEntryIfPresent String key Dto dto try Map
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 如何在Java中对对象数组进行字段级别排序以进行等级比较?

    In Java Class StudentProgress String Name String Grade CTOR goes here main class main method StudentProgress arrayofObje
  • 源值 1.5 的错误已过时,将在未来版本中删除

    我使用 scala maven plugin 来编译包含 scala 和 java 代码的项目 我已经将源和目标设置为1 7 但不知道为什么maven仍然使用1 5 这是我在 pom xml 中的插件
  • 使用 JFreeChart 为两个系列设置不同的 y 轴

    我正在使用 JFreeChart 使用折线图绘制两个数据系列 XYSeries 复杂的因素是 其中一个数据系列的 y 值通常远高于第二个数据系列的 y 值 假设第一个系列的 y 值约为数百万数量级 而第二个数据系列的 y 值约为数百万数量级
  • try-with-resources 中出现死代码警告,但翻译后的 try-catch-finally 中没有出现死代码警告

    以下代码使用try 有资源 https docs oracle com javase specs jls se7 html jls 14 html jls 14 20 3Java 8 中引入的构造 偶尔抛出 方法被声明为抛出一个偶尔的异常
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • 蓝桥杯——修改数组

    问题描述 给定一个长度为N的数组A A1 A2 AN 数组中有可能有重复出现的整数 在小明要按以下方法将其修改为没有重复整数的数组 小明会依次修改A2 A3 AN 当修改Ai时 小明会检查Ai是否在A1 Ai 1中出现过 如果出现过 则小明
  • C#中的事件和委托_札记1

    C 中的事件和委托 札记1 委托 自定义委托 静态方法 被委托 委托是一种类型 所以任何定义类的地方都可以定义委托类型 自定义委托的基本格式示例如下
  • RobotFramework 安装教程

    动化测试框架 具盘点 安装步骤 页面介绍 标准库 不需要安装 直接 RF 带 扩展库 快捷键 实战 RobotFramework 安装教程 动化测试框架 具盘点 java junit和testng 具 postmen newman git
  • html动态爱心代码【二】(附源码)

    目录 前言 效果演示 内容修改 完整代码 总结 前言 七夕马上就要到了 为了帮助大家高效表白 下面再给大家带来了实用的HTML浪漫表白代码 附源码 背景音乐 可用于520 情人节 生日 表白等场景 可直接使用 效果演示 内容修改 文案 di
  • go - flag包(处理命令行参数小能手)

    前言 在golang中有很多方法来处理命令行参数 简单情况下可以不使用任何库 直接使用os Args 但是golang标准库提供了flag包来专门处理命令行参数 当然还有第三方提供的处理命令行参数的库cobra cli可以参考 flag包绑
  • qt没有mysql驱动的解决办法

    qt没有mysql驱动的解决办法 第一部分 qtcreator上没有mysql驱动的解决办法 第一步 找到你的qt的版本的源码src 第二步 点击mysql pro 电脑会自动打开qtcreater 然后就是进行编译器的选择 我选择的是 在
  • BootStrap的使用

    是别人帮我们已经写好的css样式 我们如果想要使用这个BootStrap 下载BootStrap 使用 在页面上引入BootStrap 自定置 先在网上下载好BootStrap 并导入到Pycharm 引入BootStrap 注意引入的是
  • 【react】文本内容超过一行,显示为单行省略,并且出现icon图标;点击此图标,可以进行展开或收起文本功能实现

    需求 多条数据展示 每条数据的文本内容不超过一行 文本内容为一行时 不显示 展开收起icon图标 文本超过一行时 内容单行省略 并且显示 点击图标 图标切换为收起按钮 后端返回数据 const data name 测试测试测试 time 2
  • BinaryViewer(二进制查看器)使用教程(附下载)

    1 BinaryViewer操作界面 2 面板功能 1 数据面板 此面板占据了屏幕的最中央部分 其目的是顺序显示打开的文件或物理驱动器中的所有数据 此面板通常以两列显示数据 每列都可以按用户选择的格式显示数据 请转到数据显示模式 查看如何更
  • 对indexedDB的一些使用方法

    indexedDB的使用 1 打开数据库和创建数据仓库 createDB function dbName version tableName key cursor callBack 参数为 dbName数据库名 version版本号 tab
  • Python运维开发工程师养成记(while循环语句)

    图示 案例 contine和break用法 无限循环 while else语句 今天分享到这里 喜欢的盆友可以关注一下博主 链接 https ke qq com course 4300856 tuin d8aedf68
  • android 环信集成,Android 环信集成使用总结

    最近因为项目需要 需要集成环信 对于一些账号的注册 配置的添加官方文档上写的都有 就不在记录 就记录一下集成过程中遇到的问题 环信demo中的代码太乱 而且一些功能用不到 我们就移值些自己有用的放到自己的项目中 1 消息监听 环信在收到消息
  • mysql如何查询成绩前5名_sql 语句查询 前5名后5名的成绩

    蝴蝶不菲 两种办法 分别求最大和最小 然后union allselect from select from table order by 成绩 where rownum lt 5union allselect from select fro
  • 每隔5分钟输出最近一小时内点击量最多的前N个商品(SQL实现版)

    代码 package com zjc flow analysis hotitems analysis import org apache flink api common serialization SimpleStringSchema i
  • 智能合约调试指南

    不像你在其他地方看到的纸质合约 以太坊的智能合约是代码组成的 需要你以非常谨慎的态度去对待它 这是一件好事 想象下如果现实世界的合同需要编译的话会更清晰么 如果我们的合同没有被正确的编码出来 我们的交易可能会失败 导致以太币的损失 以 ga
  • 真题详解(Flynn分类)-软件设计(四十六)

    真题详解 计算机总线 软件设计 四十五 https blog csdn net ke1ying article details 130046829 Flynn分类将计算机分为四类 单指令流单数据流机器 SISD 早期的机器 在某个时钟周期
  • C++ 读取结束的判断

    cin 可以用来从键盘输入数据 将标准输入重定向为文件后 cin 也可以用来从文件中读入数据 在输入数据的多少不确定 且没有结束标志的情况下 该如何判断输入数据已经读完了呢 从文件中读取数据很好办 到达文件末尾就读取结束了 从控制台读取数据
  • shell脚本系列:6、shell扩展

    shell脚本系列 6 shell扩展 文章目录 shell脚本系列 6 shell扩展 1 花括号扩展 2 波浪号扩展 3 shell参数扩展 4 命令替换 5 算术扩展 6 进程替换 7 分词 8 文件名扩展 8 1 模式匹配 9 引号
  • 【upload-labs】————8、Pass-07

    闯关界面 前后端检测判断 查看源代码 文件后缀大小写 去除 DATA 关键词过滤 在这里可以发现所有的都考虑到了 但是却没有考虑后缀为 的情况 在windows中PHP会自动去除后缀名中最后的 我们可以通过这种方式来绕过 加 来绕过
  • 探索多线程使用同一个数据库connection的后果

    在项目中看到有用到数据库的连接池 心里就思考着为什么需要数据库连接池 只用一个连接会造成什么影响 只用一个connection 1 猜想 jdbc的事务是基于connection的 如果多线程共用一个connection 会造成多线程之间的