JDBC之Connection
Connection
Java连接MySQL
Connection必备知识点
使用MySQLClient发送指令给MySQLServer,可以通过connection进行SQL操作,也可以进行事务等操作。
但是下面首先了解以下知识点:
连接方式:在Java中,使用了java.sql.Connection
实例来表示应用和数据库的一个连接,通信的方式目前基本上采用的是TCP/IP 连接方式。
连接创建时间:java连接MySQL从发送请求到响应,经过多次测试,平均消耗时间为0.1S。要知道在程序中0.1S占比是很大的。
长链接:通过上面的测试,可以知道,客户端连接到服务端的一个连接,是一个长链接。这是一个很消耗性能和时间的事情。因为MySQL服务端需要当前连接分配资源并对资源进行管理。
超时时间:通过上面的描述,如果在长连接内,客户端没有指令发出,要超过服务端的数据。那么MySQL客户端也会做出对应的措施来断掉来自客户端连接
客户端如果长时间不发送command到Server端,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。
查看wait_timeout对应的SQL:
mysql> show global variables like "wait_timeout";
mysql>set global wait_timeout=28800; 设置全局服务器关闭非交互连接之前等待活动的秒数
利用JDBC使用Connection
概念:接口的实现在数据库驱动中。所有与数据库交互都是基于连接对象的。
作用:
- 1、创建执行SQL的对象(Statement[普通]、PreparedStatement[预编译]、CallableStatement[存储过程]);
- 2、事务操作:(1)setAutoCommit、commit/rollback (2)设置隔离级别[无用]
- 3、设置事务回滚点
- 4、关闭连接:close
问题一:为什么Java操作数据库的连接不是越多越好
手动创建Java连接数据库的connection连接,会带来问题。
应用程序和数据库之间建立 Connection
连接,而数据库机器会为之分配一定的线程资源来维护这种连接,连接数越多,消耗数据库的线程资源也就越多;
另外不同的connection实例之间,可能会操作相同的表数据,也就是高并发,为了支持数据库对ACID特性的支持,数据库又会牺牲更多的资源。
简单地来说,建立Connection
连接,会消耗数据库系统的如下资源:
资源 | 说明 |
---|---|
线程数 | 线程越多,线程的上下文切换会越频繁,会影响其处理能力 |
创建Connection的开销 | 由于Connection负责和数据库之间的通信,在创建环节会做大量的初始化 ,创建过程所需时间和内存资源上都有一定的开销 |
内存资源 | 为了维护Connection对象会消耗一定的内存 |
锁占用 | 在高并发模式下,不同的Connection可能会操作相同的表数据,就会存在锁的情况,数据库为了维护这种锁会有不少的内存开销 |
上述的几种资源会限制数据库的链接数和处理性能。
结论: 数据库资源是比较宝贵的有限资源,当应用程序有数据库连接需求过大时,很容易会达到数据库的连接并发瓶颈。
所以这也是为什么要使用数据库连接池的原因
问题二、数据库最多支持多少Connection连接
以 MYSQL为例,可以通过如下语句查询数据库的最大支持情况:
-- 查看当前数据库最多支持多少数据库连接
show variables like '%max_connections%';
-- 设置当前运行时mysql的最大连接数,服务重启连接数将还原
set GLOBAL max_connections = 200;
-- 修改 my.ini 或者my.cnf 配置文件
max_connections = 200;
具体的设置范围,应当具体的业务背景来调优。
问题三、数据库连接connection执行SQL的顺序
上面也说过,MySQLClient连接到MySQLServer时,在长连接内,客户端没有指令发出,要超过服务端的数据。那么MySQL客户端也会做出对应的措施来断掉来自客户端连接。默认时间是8小时。
也就是说,客户端在持有连接八小时内,没有执行任何命令,那么服务端就会断掉对应的连接。
如果时不时的给MySQL服务端发送一些无用的查询SQL,那么MySQL就会认为当前数据库连接是在起到作用的
我觉得这就是使用数据库连接池的操作过程,为了防止断开数据库连接
那么我们可以给一个数据库连接connection定义一个生命周期。从创建出来数据库连接开始到断开数据库连接之间称之为数据库连接的生命周期。
场景一、一个线程操作一个数据库连接
自动提交
一个线程在持有数据库连接中,默认是在MySQL默认隔离级别下,对于增删改查的SQL来说,都是按照下面的流程来执行
默认添加上了begin和commit/rollback,针对的是每一条增删改查的SQL。
如以下SQL:
select * from account;
update account set name = 'xxx' where id = 1;
select * from account;
那么按照上面的执行流程,在数据库中真实的指令应该如下所示:
begin;
select * from account;
commit/rollback;
begin;
update account set name = 'xxx' where id = 1;
commit/rollback;
begin;
select * from account;
commit/rollback;
问题以及弊端
首先需要知道的是,在上面的三条SQL中,只有一个update操作会创建事务id,对于查询来说不会创建事务id。
那么创建数据库事务id,也需要消耗性能,可以忽略不计。
但是如果想要实现一组SQL是属于同一个事务中的,也就是想让一批SQL的执行是原子性的。要么是同时成功,要么是同时失败,那么就需要手动的来开启事务。
手动提交[开启事务]
按照上面的分析接着向下走,原始一组SQL如下所示:
select * from account;
update account set name = 'xxx' where id = 1;
select * from account;
那么如果手动开启了事务的执行流程应该如下所示:
begin;
select * from account;
update account set name = 'xxx' where id = 1;
select * from account;
commit/rollback;
对于上面的只会创建一个事务id,那么创建事务的性能消耗更能够忽略不计了。
场景二、多个线程操作同一个数据库连接
多个线程操作同一个数据库连接,我们理想的情况是下面这样子
但是也可能存在下面这种情况:
thread_1和thread_2在交叉执行,那么来列表说明一下情况:
用上面的SQL来进行举例说明:
select * from account;
update account set name = 'xxx' where id = x;
select * from account;
thread_1 | thread_2 |
---|---|
begin | |
select * from account; | begin; |
update account set name = 'xxx' where id = 1; | |
select * from account; | |
update account set name = 'xxx' where id = 2; | |
select * from account; | |
commit | |
select * from account; | |
rollback; |
本来thread_2中应该执行的SQL是:
select * from account;
update account set name = 'xxx' where id = 2;
select * from account;
但是现在执行的却是:
select * from account;
update account set name = 'xxx' where id = 1;
update account set name = 'xxx' where id = 2;
select * from account;
但是因为thread_2将其中的一条SQL给提交了,那么就造成了对持有同一个数据库连接的事务造成了影响,但是这又是别的线程所不知道的情况。
但是thread_1又将数据进行了回滚,那么就造成了数据安全问题
解决方式
如果是单机应用的话,可以采用syncronized关键字、lock锁来进行解决,但是只针对于单机应用来说。
如果是分布式架构,那么就需要通过分布式锁来进行解决;
对应的伪代码如下所示:
java.sql.Connection sharedConnection = <创建流程>
## thread #1 的业务伪代码:
synchronized(sharedConnection){
try{
begin;
` update xxx`;
`update yyy`;
`commit`;
} catch(Exception e){
`rollback`;
}
}
## thread #2 的业务伪代码:
synchronized(sharedConnection){
try{
begin;
`delete zzz`;
`insert ttt`;
`rollback`;
} catch(Exception e){
`rollback`;
}
}
小结
综上所述,解决多个线程访问同一个Connection
对象时,必须遵循两个基本原则:
1、以资源互斥的方式访问Connection对象;
2、在线程执行结束时,应当最终及时提交(commit)或回滚(rollback)对Connection的影响;不允许存在尚未被提交或者回滚的语句。
问题四、线程生命周期和数据库连接生命周期
我们最容易理解的是:请求------>controller---->service----->dao---->响应
上述我们可以理解一个线程的生命周期,但是相对比来说,我们的数据库连接只是在其中占据了很小的一部分。
那么我们可以总结出来:线程的执行时间远远大于数据库连接执行SQL的时间。
画图如下所示:
这种情况就会出现狼多肉少的情况,那么就可能会导致多个线程公用一个数据库连接的情况。
总结
JDBC之Connection的更多相关文章
- JDBC driver connection string大全
Database / data source URL format / driver name Value Default port MySQL URL format: jdbc:mysql: ...
- atitit.故障排除------有时会错误com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset by peer: soc
atitit.故障排除------有时会错误com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset by peer: soc ...
- jdbc 获取connection 对象的三种方式
获取数据库连接方法一:驱动实现类 //创建mysql的Driver对象 Driver driver=new com.mysql.jdbc.Driver(); //jdbc url 定位一个数据库: S ...
- jdbc、Connection pool、jndi的理解和关系
一.概念和理解: ①.jdbc:Java Data Base Connectivity,java数据库连接,最为传统的一种方式,直接连接操作数据库,需要连接时创建连接,使用结束时销毁连接. ②.Con ...
- JDBC:Connection.close()
https://www.2cto.com/database/201501/369246.html Connection对象在执行close() 方法之后,并不是直接把Connection对象设置为nu ...
- Weblogic常见故障常:JDBC Connection Pools(转)
WebLogic Server中数据库连接池是一个经常出问题的地方,总结一下出问题的原因和解决办法. 一.数据库连接泄漏 此类问题一般都是由于开发人员没有正确关闭数据库连接造成的.比如使用完Conne ...
- Weblogic常见故障一:JDBC Connection Pools
最近系统老是出现数据库连接池不够用的问题,由于weblogic数据源里没有配置JDBC连接数,取的是默认值15,太小导致connection耗尽,是不是就报一堆错.后来通过修改WebLogic数据源配 ...
- [原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载
问题: 一. 1. Spring 如何处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSession ? 3. propagati ...
- [原理][来源解析]spring于@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关联
Spring 捆绑Hibernate. 夹: 一. 1. Spring 怎样处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSe ...
- Weblogic常见故障常:JDBC Connection Pools【转】
WebLogic Server中数据库连接池是一个经常出问题的地方,总结一下出问题的原因和解决办法. 一.数据库连接泄漏 此类问题一般都是由于开发人员没有正确关闭数据库连接造成的.比如使用完Conne ...
随机推荐
- ionic混合开发总结之调用手机相机
整理一下,给接触ionic的伙伴们一些参考,少走弯路. 调用手机的前提是已经成功创建了项目. 首先,要下载两个插件,一个是 cordova-plugin-camera,是调用相机的插件,还有一个是Ng ...
- centos8 安装docker启动失败
借鉴https://www.zqcnc.cn/post/71.html systemctl status docker● docker.service - Docker Application Con ...
- 1.markdown
markdown 使用学习 # +标题名字 选择标题 最多6级 一个#表示加一级 一级最大 字体 对字体加粗等操作 hello **hello** 粗体 hello *hello* 斜体 hello ...
- Excel VBA实例
有个朋友让帮忙看下excel数据怎么处理,初步一看有点复杂,难以下手.进一步分析.搜索,发现VBA可以很好地解决这个问题,总结记录一下. 问题描述:如下图,有N个sheet,每个sheet记录了一个公 ...
- java-javaSE-异常机制
java中的异常结构 java 中的所有异常都来自于顶级父类 Throwable,Throwable 有两个子类 Exception 和 Error Error 是 Java 虚拟机无法解决的严重问题 ...
- 前端js校验小数点
let result = (value.toString()).indexOf("."); if (result != -1 && value.toString() ...
- aqueduct “Uncaught error Bad state: No element" 或者 "NoSuchMethodError: The getter 'location' was called on null.”
可以先将Pub\Cache目录下的内容清空(移除aqueduct命令),随后重新运行命令生成 pub global activate aqueduct 设置环境变量 创建用户变量 PUB_HOSTE ...
- openGL 学习笔记 (二) 使用GL API 绘制出属于自己的矩形
在OpenGL中所有的事物都是在3D空间中,但是我们所看到的屏幕成像却是2D的像素数组.这导致OpenGL的大部分工作就是把得到的3D坐标转换为适应屏幕的2D图像.转换的整个处理过程是由OpenGL的 ...
- 快速使用时序数据库InfluxDB
快速使用时序数据库InfluxDB InfluxDB是一款优秀的时间序列数据库,适合存储设备性能.日志.物联网传感器等带时间戳的数据. 1. InfluxDB主要特性 InfluxDB也就是TSDB, ...
- vite + vue3 + js + xlsx 导出excel
安装依赖 1 npm install xlsx --save 使用版本 封装js /* 导出excel文件 */ /** * 导出excel文件实现思路分析 * * 1.通过XLSX插件的 XLSX. ...