索引:索引是对数据库表中一列或者多列的值进行排序的一个结构
一.索引的优点:
(1)创建索引可以大幅度的提高系统的性能,可以帮助用户能够更快查询到需要查询数据
(2)通过索引的唯一性,也可以保证数据库中每一行数据的唯一性
二.索引的缺点:
(1)当数据库中的数据非常大时,创建索引和维护的代价就非常大,可能会导致数据库的卡死
(2)创建索引会造成数据库在空间以及增删改的效率降低
索引的核心数据结构为:B+数(在本质上为一个N叉搜索树)-->查找过程和二叉树相似
事务:事务是数据库的操作序列
事务的特性(原子性,一致性,持久性,隔离性);
(1)原子性:把多个SQL打包成一个整体,要么执行就执行到底,要么就不执行,抵制半途而废(也不是说真的一个都不执行,而是执行一半了发现出现了问题,那么就可以自动的把前面的SQL执行的效果进行还原 这就叫做回滚)
(2)一致性:事务在执行的前后,数据必须处于“一致的状态”,类似于银行转账(A账户转给B账户一百元,A账户就减少一百元同时B账户就必须增加一百元,)
(3)持久性:事务一旦提交过后数据是存放在硬盘的,无论是数据库卡死过后的重启还是故障,数据都不会丢失
(4)隔离性:多个事务在并发执行的时候,事务之间能够保持‘隔离’,相互不干扰(也就是说一个事务的执行不能被另一个事务而干扰,每个事务都有各自的空间)
脏读问题:脏数是一个临时的数据,不代表最终的数据(一个事务A在修改数据还未提交之前,另外一个事务B读取了数据,此时事务A又修改了数据然后提交上去,那么事务B读到的就是一个“无效数据”也就成为脏读)
解决脏读问题:事务A在写数据还未提交之前,事务B不能读,只有A写完数据过后提交完成,B事务才能读-——>相当于对写操作加锁
在写加锁之前,事务A与事务B就是完全并发的 并发性是最高的,隔离性是最低的
当写加锁之后,事务A写的时候事务B就不能读了 并发性降低(效率降低)隔离性提高(数据准确性提高)
不可重复读:解决完脏读问题后,又出现了一个不可重复问题,当事务A提交完数据时,事务B在读数据,但是事务A突发奇想的想修改数据,于是修改完成后又提交了,这时事务B读数据读着读着就会发现数据被改变了(也就是在同一个事务中读两次数据应该是两次相同的结果 但是结果不相同这就是不可重复读 原因就是读的过程中被数据被修改了)
解决不可重复读问题:利用读加锁 事务A与事务B约定 在事务A写数据的时候事务B不去读(写加锁) 同时在事务B读数据的时候事务A不去修改(读加锁)
随之读加锁,并发程序又进一步的降低(效率降低)隔离性又提高了(数据准确性也提高了)
幻读(不可重复读的特殊情况):当事务B去读文件A时,事务A去修改文件B/去新增删除文件,只要不影响事务B读的那个文件就好了,但是这样做对事务B直接读取的数据没有影响,但是事务B会发现两次读虽然数据一样,但是结果集会被改变(第一次事务B看到一个.java文件 下次读就突然看见两个.java文件)
解决幻读问题:“串行化”(先执行完成一个再执行下一个)事务B在读数据读代码的时候,事务A就必须不能修改数据,就必须放下电脑,数据不可以动
这时并发程度最低(串行执行的了),效率是最低的,隔离性是最高的,数据的准确性也是最高的了
如果需求对于数据精度要求不高,上述问题就不是bug,因此就可以让并发程度高一些,隔离性低一些,提高效率(例如某手某音的点赞,游戏排位的分数)
如果需求对于数据精度要求很好,上述问题就可能是bug,因此就得让并发程度低一些,隔离性高一些,提高准确度(例如关于钱的)
于是MySQL就提供了‘隔离级别’选项 共有四个档位 当我们根据实际情况而选择
隔离级别:
1.read uncommitted : 允许读未提交的数据,并发程度最高,隔离性最低,效率最高,可能出现 脏读/不可重复读/幻读 问题
2.read committed :只能读提交之后的数据,相当于写加锁,并发程度降低,隔离性提高,解决了脏读问题,可能存在不可重复读/幻读 问题
3.repeatable read(默认) :相当于读和写都加锁,并发程序再降低,隔离性在提高,解决了脏读/不可重复读的问题 可能存在幻读问题
4.serializable :严格执行串行化,并发程度最低,隔离性最高,解决了脏读/不可重复读/幻读问题,效率最低
补充ArrayList和LinkedList之间的区别
1.ArrayList底层是顺序表 LinkedList底层是链表
2.ArrayList具备了随机访问的能力(根据下标获取元素)
ArrayList查找并不快,查找的时候要遍历的时间复杂度为O(N) 没有优势
查找:根据值来获取元素的位置(indexOf)
3.LinkedList增加删除也不快!首位增删可以做到O(1) ,中间位置增删还是O(N) 封装为一个 add(n,value)也是通过下标的方式来查找的,这种封装导致java的链表没有发挥出应有优势,相比之下C++中STL 中 std::list 插入元素的时候需要显式的指定一个迭代器(迭代器就指向了需要插入的位置) 这里的中间位置插入是O(1);