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 ...
随机推荐
- Day13 字符串的常用方法
API帮助文档的使用流程 在索引的位置搜索自己要查看的类 看包 目的:是不是 Java.lang包(核心包),不需要编写导包代码(import) -------不是 java.lang包,都需要编写导 ...
- c++ class派生与多态
目录 类继承和类派生 继承时名字遮蔽 基类和派生类的构造函数 构造函数调用顺序 基类和派生类的析构函数 多重继承 虚继承和虚基类 将派生类赋值给基类(向上转型) 将派生类指针赋值给基类指针. 将派生类 ...
- VUE学习-渲染函数
渲染函数 x-template 引入外面组件文件写法 <template> <h1 v-if="level === 1"> <slot>< ...
- seql sever INSERT语句简介
INSERT语句简介 要向表中添加一行或多行,可以使用INSERT语句.下面说明了INSERT语句的最基本形式: INSERT INTO table_name (column_list) VA ...
- RestTemplate 远程服务调用
* 使用 Eureka 和 Nacos 为注册中心时也能使用这种方式调用 一.远程调用类 bean 配置注入 和 配置负载均衡 注意,必须在可配置类中注入 bean,例如 SpringBoot 启动 ...
- Oracle 验证身份证号
--验证身份证号是否正确CREATE OR REPLACE FUNCTION fn_checkidcard (p_idcard IN VARCHAR2) RETURN INT IS v_regstr ...
- redis底层数据结构之双向链表(linkedlist)
双向链表(linkedlist) redis的双向链表(linkedlist)是基于链表的一种数据结构 链表是一种常见的基础数据结构,是一种非顺序存储数据的线性表,在每一个节点里存储了下一个节点的指针 ...
- P2016题解
P2016题解 题目描述 Bob要建立一个古城堡,城堡中的路形成一棵无根树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路. 注意,某个士兵在一个结点上时,与该结点相连的所有边将 ...
- (app笔记)Memory Fill内存填充
Memory Fill 是实现app内存填充工具(运行内存,物理内存,网络空间内存) Used:已用内存 filled:未回收内存 Free:自由内存 1.Ram(Total Ram):手机运行内存 ...
- winform 中 label透明化
label1.BackColor = Color.Transparent;//设置背景颜色为透明 label1.Parent = pictureBox1;//将pictureBox1设为标签的父控件, ...