Java基础知识——数据库

锁:读写锁 行页表锁 乐观锁
连接:内连接 外连接 交叉连接
底层设计:HashB B与二叉
引擎:五大引擎 MYISAM和innoDB的区别
基础知识:删除 优先级 视图 约束(五大约束 完整性 断言 触发器)
主从复制:分布式 种类 策略 过程
mysql机制:server组成 日志

活锁:饿死
死锁:
乐观锁:认为读多于写
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作(类似于自旋操作)。
java 中的乐观锁基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。
如果v中存储的值==A,则成功,写入新值B否则失败不写入

缺点:

  1. ABA 问题
    如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。
    部分乐观锁的实现是通过版本号(version)的方式来解决 ABA 问题,乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1 操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现 ABA 问
    题,因为版本号只会增加不会减少。
  2. 循环时间长开销大

悲观锁:常用的加锁机制
互斥锁:未得到锁后即阻塞
自旋锁:循环去申请锁而不会阻塞
优点为不用切换上下文,缺点是可能长期占用cpu资源
自旋锁时间阈值:若超过自旋等待的最大时间扔没有释放锁,这时争用线程会停止自旋进入阻塞状态。
在 1.6 引入了适应性自旋锁,适应性自旋锁意味着自旋的时间不在是固定的了,而是由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定

悲观锁按使用性质

MYISAM:没有行锁,不支持事务
表级锁:读,写锁
MyISAM 总是一次获得 SQL 语句所需要的全部锁,Dead free
非聚簇索引:如果MyISAM表在数据文件中间没有空闲块,则行始终插入数据文件的末尾。 在这种情况下,你可以自由混合并发使用MyISAM表的INSERT和SELECT语句而不需要加锁
不会死锁

InnoDB:行级锁
行锁:建立在b+数的索引上,所以只有走索引的才可以使用行锁。否则使用表锁(或next-key)
使用mvcc机制,所以普通的select不用加任何锁

锁类型:
共享锁(S锁):对行加锁,与X不兼容
排他锁(X):写锁,与S,X都不兼容
意向锁:获取行锁前必须取得相应的意向锁。与其他意向锁兼容,也和行锁兼容,和表锁互斥。主要用于其他lock table时候,避免其检查每一行的行锁,而是只用检查意向锁
意向排他锁IX
意向共享锁IS

为什么要意向锁?
1:对于Lock table,对全表加所,首先需要判断每一行有没有X锁。因为建立在索引上,所以对索引进行扫描,很费时间
有了意向锁,因为X必须先获得IX,所以只需要判断表上有没有IX就可以判断X,非常简单
2:select for update获取X锁,防止死锁
哪些时候加锁?
普通select 不加锁【范围select +间隙锁(解决幻读)】
insert/update/delete:X+IX
select for update:X+IX
select lock in share mod:S+IS

隐式加锁:两阶段。可以在事务的任何时候加锁,但是只能在commit/rollback的时候释放锁
显式加锁:
select for update:获取意向排他锁+排他锁,保证获取最新的数据,并且可以最先修改
select lock in share mod:获取意向共享锁+共享锁,保证获取最新的数据,但是不一定最先修改

死锁:innodb可以使用事务回滚进行释放资源。
一般来说,事务内需要修改的行都先用for update获取IX才修改

参考:
https://zhuanlan.zhihu.com/p/29150809
https://juejin.cn/post/6844903666332368909
https://yq.aliyun.com/articles/626848

悲观锁按作用范围划分


参考资料

行锁:对索引加锁,对操作属性中包含索引
开销大,加锁慢;会出现死锁;需要具体检索到某一行,当没有释放某一行而去请求另一行则可能导致死锁
锁定粒度小,发生锁冲突的概率低,并发度高

表锁:对非索引加锁,不包含索引
锁定力度大,发生锁冲突概率高,并发度最低
开销小,加锁快;不会出现死锁;一次性获得表所涉及的所有锁,要么全部得到要么全部不得到

如果操作的是索引,那么就是行锁;如果是非索引,那么就是表锁

乐观锁

时间戳,版本号

锁协议

锁协议对应四种隔离几杯
1)一级封锁协议:事务T在修改数据R之前必须先对其加写锁,直到事务结束才释放(避免丢失修改)
2)二级封锁协议:在一级封锁协议的基础上增加事务T在读取数据R之前必须先对其加读锁,读完后即可释放读锁(避免丢失修改和读脏数据)
3)三级封锁协议:在一级封锁协议的基础上增加事务T在读取数据R之前必须先对其加读锁,直到事务结束才释放(避免丢失修改、读脏数据、不可重复读)
4)两段锁协议:在对任何数据进行读写操作之前,首先要先申请并获得对该数据的封锁
加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁,在进行写操作之前要申请并获得X锁。加锁不成功,则事务进入等待状态,直到加锁成功才继续执行。
解锁阶段:当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作。
两段封锁法可以这样来实现:事务执行第一条语句为加锁阶段,一直到执行ROLLBACK和COMMIT之前都是加锁阶段。ROLLBACK和COMMIT使事务进入解锁阶段,即在ROLLBACK和COMMIT模块中DBMS释放所有封锁。

Next-Key Lock的算法

行锁+Gap Lock
Gap Lock间隙锁:对间隙加锁
目的:防止幻读

案例数据

id(主键)	c(普通索引)	d(无索引)
5	5	5
10	10	10
15	15	15
20	20	20
25	25	25

有6条间隙锁,(-∞,5](5,10](10,15](15,20](20,25](25,+supernum] (其中supernum是数据库维护的最大的值。为了保证间隙锁都是左开右闭原则。)
加锁原则是左开右闭原则

事务与隔离
  1. 原子性(Atomicity)
    事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
  2. 一致性(Consistency)
    数据库在事务执行前后都保持一致性状态。
    在一致性状态下,所有事务对一个数据的读取结果都是相同的。
  3. 隔离性(Isolation)
    一个事务所做的修改在最终提交以前,对其它事务是不可见的。即事务之间不会互相影响
  4. 持久性(Durability)持久化粗处

可能出现的问题
前提:T1,T2都开启事务
丢失修改:T1 和 T2 对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。
脏读:T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。
不可重复读:T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
幻读:T1 读取某个范围的数据,T2 在这个范围内插入/删除新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
不可重复读关注update/delete,幻读关注insert

隔离的等级

  1. 未提交读(READ UNCOMMITTED)
    事务彼此并发执行
    写会加X锁,而读不需要加S锁
    解决:丢失修改

  2. 提交读(READ COMMITTED)
    一个事务只能读取已经提交的事务所做的修改。
    写会加X锁,并且持续到释放结束,读需要加S锁。所以

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值