1、JDBC Connection实例是线程平安的吗?

Connection实例是线程平安的吗?


能不能只创立一次,共享Connection对象?

答案是不能的, Connection不是线程平安的,他会在多线程环境下,导致数据库操作的凌乱,特地是在事务存在的状况下:可能一个线程刚开启事务con.setAutoCommit(true),而另一个线程间接提交事务con.commit();对于独自查问的状况,仿佛不会呈现数据错乱的状况。是因为在JDBC中,应用了锁进行同步**源码:**com.mysql.cj.jdbc.CallableStatement#executeQuery


connection自身是线程不平安的,并且connection创立开销比拟大,所以个别应用数据库连接池来对立的治理connection对象,例如druid连接池,c3p0连接池等等

数据库连接池

在应用数据库连接池时,一个线程中所有DB操作都是应用同一个Connection实例吗?
在Spring环境中,获取connection源码如下所示:
源码:org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

非事务场景:在非事务创立中(同时没有应用Spring事务管理器),每一次拜访数据库,都是在DataSource中取出一个Connection实例,调用结束之后偿还资源,因而屡次调用,应该是不同的Connection实例

事务场景:在应用事务的状况下,实际上是在ConnectionHolder中获取的Connection。而ConnectionHolder是在TransactionSynchronizationManager中获取的resources属性的值,即connection对象信息

源码:
org.springframework.transaction.support.TransactionSynchronizationManager#doGetResource

而ThreadLocal<Map<Object,Object>>线程上下文共享。即Connection对于与Thread绑定。因而在事务中无论操作多少次DB,事实上都是操作的同一个Connection对象

2、MySQL架构设计


SQL接口:SQL的规范来承受
SQL解析器:了解这个SQL语句要干什么事件
查问优化器:抉择一个最优的查问门路
执行器:执行器就会去依据咱们的优化器生成一套执行打算,而后不停的调用存储引擎的各种接口去实现SQL语句的执行打算
存储引擎:存储引擎其实就是执行SQL语句的,他会依照肯定的步骤去查问内存数据,更新磁盘数据,查问磁盘数据,等等,执行诸如此类的一系列的操作,MySQL的架构设计中,SQL接口,SQL解析器,查问优化器其实都是通用的,他就是一套组件而已,然而存储引擎的话,他是反对各种各样的存储引擎的,比方咱们常见的InnoDB、MyISAM、Memory等等

3、InnoDB内存构造

4、Buffer Pool

Buffer Pool: 缓冲池,简称BP。其作用是用来缓存表数据与索引数据,缩小磁盘IO操作,提供效率
Buffer Pool由缓存数据页和对缓存数据页进行形容的管制块组成,管制块中存储着对应缓存页的所属的表空间、数据页的编号、以及对应缓存页在Buffer Pool中的地址等信息
Buffer Pool默认大小是128M,以Page页为单位,Page页默认大小16kb,而管制块的大小为数据页的5%,大略是800字节

留神:Buffer Pool大小为128M指的就是缓存页的大小,管制块则个别占5%,所以每次会多申请6M的内存空间用于寄存管制块

如何判断一个页是否在Buffer Pool中缓存?
MySQL中有一个哈希表数据结构,它应用表空间号+数据页号,作为一个key,而后缓存页对应的管制块作为value

  • 当须要拜访某个页的数据时,先从哈希表中依据表空间号+页号看看是否存在对应的缓存页
  • 如果有,则间接应用;如果没有,就从free链表中选出一个闲暇的缓存页,而后把磁盘中对应的页加载到缓存页的地位

Page页

Buffer Pool的底层采纳链表数据结构治理Page。在InnoDB拜访表记录和索引时会在Page页中缓存,当前应用能够缩小磁盘IO操作,晋升效率

Page分类

Page页依据状态分为三种类型 :

free page : 闲暇page,未被应用
clean page : 被应用page,数据没有被批改过
dirty page : 脏页,被应用page,数据被批改过,页中数据和磁盘数据产生了不统一

Page如何治理

针对下面所说的三种page类型,InnoDB通过三种链表构造来保护和治理

  • free list : 示意闲暇缓冲区,治理free page
    Buffer Pool的初始化过程中,是先向操作系统申请间断的内存空间,而后把它划分成若干个管制块&缓存页的键值对
    free链表是把所有闲暇的缓存页的管制块作为一个个的节点放到一个链表中,这个链表便称之为free链表
    基节点:free链表中只有一个基节点是不记录缓存页信息(独自申请空间),它外面就寄存了free链表头节点地址,尾节点地址,还有free链表以后有多少个节点

    磁盘加载过程 :

    • 从free链表中取出一个闲暇的管制块(对应缓存页)
    • 把该缓存页对应的管制块的信息填上(例如:页所在的表空间、页号之类的信息)
    • 把该缓存页对应的free链表节点(即:管制块)从连贯中移除。示意该缓存页曾经被应用
  • flush list : 示意须要刷新到磁盘的缓冲区,治理dirty page,外部page按批改工夫排序
    InnoDB引擎为了进步解决效率,在每次批改缓存页后,并不是立即把批改刷新到磁盘上,而是在将来的某个工夫点进行刷新操作,所以须要应用到flush链表存储脏页,但凡被批改过的缓存页对应的管制块都会作为节点退出到flush链表

    脏页即存在于flush链表,也在LRU链表中,然而两种互不影响,LRU链表负责管理page的可用性和开释,而flush链表负责管理脏页的刷盘操作
  • LRU list : 示意正在应用的缓冲区,治理clean page和dirty page
    一般LRU算法
    LRU = Least Recently Used(最近起码应用) : 就是开端淘汰法,新数据从链表头部减少,开释空间的从开端淘汰

    • 当要拜访某个页时,如果不在Buffer Pool,须要把该页加载到缓冲池,并且把缓存页对应的管制块作为节点增加到LRU链表的头部
    • 当要拜访某个页时,如果在Buffer Pool中,则间接把该页对应的管制块挪动到LRU链表的头部
    • 当须要开释空间时,从开端淘汰

    待持续。。。,喜爱的话,点赞加关注哈!