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 ...
随机推荐
- C++中链表报错member access within null pointer of type 'ListNode'
报错原因:指针有指向空节点的可能,所以报错,C++中链表的使用比较严格 解决方法:在给指针确定指向节点之前,先判断此节点是否为空节点
- DEV 导出多行头
//在winfrom 中添加个Gridcontrol 和按钮 public partial class MultTitle : XtraForm { BandedGridView bandedGrid ...
- cenots7 rpm 包升级ssh
rpm下载地址 也可以自行官网下载 链接: https://pan.baidu.com/s/1S945MehpmZbIriKK6l7Sfw 提取码: y5ua centos7rpm包升级ssh 逻辑思 ...
- 如何使用postman
一. 了解postman 1. 什么是postman? ------ 软件测试用来做接口测试的工具. 2. 如何下载postman ------ https://www.getpostman.com/ ...
- shell脚本:报错syntax error near unexpected token `$'\r''解决方法
之前的shell脚本是在服务器上编写的,后来又已复制的方式存在在了电脑上,以txt文件的形式存放的.于是复制到了编辑工具中,进行了相应项的修改.修改完毕后,拿到服务器上测试,结果执行sh XXX.sh ...
- nacos启动失败
报错如下: 通过第二个圈可以看出,没有发现9848端口,才想起来自己Spring Cloud Alibaba依赖对应的nacos版本是2.0.4,而启动的nacos服务却是1.x版本,才导致这个报错. ...
- NXOpen拉伸
#include <NXOpen/Annotations.hxx> #include <NXOpen/Assemblies_Component.hxx> #include &l ...
- 一、100ASK_IMX6ULL嵌入式裸板学习_LED实验(知识点补充二)
MUX是什么? MUX(multiplexer数据选择器): 在多路数据传送过程中,能够根据需要将其中任意一路选出来的电路,叫做数据选择器,也称多路选择器或多路开关. 多路转换器的作用主要 ...
- JavaScript案例:短信验证码倒计时
展示效果: 代码示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- js数组去重,删除重复的属性值
let a=[] let hash={} a=a.reduce((pre,next)=>{ hash[next.name]?"":(hash[next.name]=true& ...