MySQL的事务
索引也是一种数据结构,目的时为了加快查找效率(会影响到插入,删除,修改的效率)
索引适用于一写多读的情况.
索引的核心结构:
B+树
-
为什么不用hashMap呢
因为哈希表只能查找key相等的情况,因为不能按范围查找 -
为啥不用红黑树呢?
红黑树只有两个叉,意味着表示数据量大的时候,高度就会比较高,具体操作效率就越慢
B树是N叉树
B+树把数据存在叶子节点上,叶子节点直接用链表来连接
- 索引结构不包含数据,直接存到内存即可
- 使用链表就更方便进行范围查找
不是B树不好,而是B树再MySQL这种关系型数据库中不是特别适用
事务🌂
主要解决的问题 : 转账问题
A给B转500元
- A -500;
- B +500;
一旦执行第一步,第二步出现问题了,数据就错了.
事务,就是把一组操作打包在一起,执行的时候能够保证这些操作之间满足一定的特性,避免出现上面的情况.
特性:
1.原子性:一个事务是一个不可分割的工作单位,要么全都做了,要么全不做(本质上是通过回滚方式实现的)
2.一致性:事务执行前后,数据处于合法状态
3.持久性:事务执行完毕之后,数据就被持久修改了(写到磁盘里了)
4.隔离性:多个事务并发执行时事务之间不能相互干扰. 🌂
本质上就是线程安全问题
隔离性和并发是相悖的
隔离是为了保证数据的准确
并发是为了提高事务执行的效率
如果多个事务之间隔离性越强,并发程度就越低,效率越低
如果多个事务之间隔离性越弱,并发程度就越高,效率越高
虽然两者是相悖的,但是不同的场景下,对数据准确性的要求不一样
就可以在满足数据准确要求的前提下尽可能地提高并发程度
这就涉及到MySQL的事务隔离级别
并发执行事务时,产生的问题:
此处考虑的并发执行多个事务,可以类比成多线程执行一些逻辑
但是此处的写加锁,读加锁不要和synchronized类比
1.脏读
如果一个事务A正在修改数据(还没提交呢),另外一个事务B读取了这里的修改内容.此时这样的事务B的读操作就是藏独
因为事务A在提交数据之前,随时可能有修改刚才的数据
解决脏读的方法:给写操作加锁,
A在修改数据的过程中,B尝试去读,就会阻塞,一直阻塞到A提交数据之后,B才能读取数据
2.不可重复读
事务A内部两次读取同一个数据,发现数据不一样(读的过程中事务B对数据进行了修改)
就叫不可重复读
解决方案:
之前写加锁是指修改代码的时候,别人不能读
但是别人读的时候,我还能改代码
此时读加锁的意思就是别人读的时候,我也不能改
此时就能解决不可重复读问题
3.幻读
一次事务执行过程中,多次读取到的结果集不一样,具体的结果数据是一样的(原来有十行,这次读完有12行了,原有的数据没变,但是多了几个或者少了几分数据)
解放方案:
串行化,让老湿的修改操作和同学们的读操作彻底串行执行.
我改数据的时候别人不能读,别人读的时候我啥也不能改
数据库中并发执行事务所带来的问题
只要是并发编程都会有这些问题
synchronized比较简单粗暴,加上synchronized就相当于串行化执行
好处是简单,坏处就是粗暴
这也是juc包中为啥要提供其他风格的锁的原因
MySQL的隔离级别:对隔离性的要求具体多高(隔离性高了,并发程度就低了,数据可靠性搞了,效率就低了)
- read uncommitted:允许读取未提交的数据(隔离程度最低,并发性最高,会有脏读问题)
- read committed:只允许读取已经提交的数据(隔离性提高了一些,并发性降低了一些,解决了脏读问题,但是会有不可重复读问题,相当于写加锁
- repeatable read(MySQL的默认隔离级别):给读也加锁(隔离性又提高了,并发性又降低了,解决了不可重复读问题,但是会有幻读问题)
- serializble:严格串行化执行(隔离性最高,并发最低,解决了幻读问题)
SQL语句中显示的指定当前SQL使用哪种隔离级别.不指定,默认就是repeatable read