Arrylist基于数组实现,用下标访问 支持随机访问 连续存储
扩容机制:
数组长度固定,长度超出后再插入新的数据需要新建数组,将老数组数据拷贝到新的数组,不是尾插会涉及元素的移动,尾插法设置好初始化容量,性能可以极大提升,甚至超过LinkList
LinkList:
基于链表,存储在分散的内存中,适合数据的插入删除操作,不适合查询
遍历必须用iterator不能用for循环
因为每次放循环内用get(i)都会对list遍历性能消耗极大
此外尽量不用indexof,当其结果为空时会遍历整个列表
HashTable 每个方法加了锁–>同步锁 用了synchronied 修饰 线程安全
HashMap 线程不安全 允许key value 为null
通过数组和链表实现
jdk8之后,链表长度达到8,数组长度达到64 链表转换为红黑树,元素以内部Node节点存在
HashMap:数组加列表
1:计算key的hash值,二次hash然后对数组长度取模 获取到对应的数组下标
2:若未产生hash冲突,直接放入数组
3:产生hash冲突,则进行equal比较,相同则取代该元素,否则判断链表长度,插入链表,若高度超过8,数组大小超过64.则转换为红黑树,当长度减小6,则转换为链表
4:key为null则存在下表为0 的位置
1:引用计数法
每个对象都有一个计数属性,新增一个引用+1,释放一个引用-1计数为0 则回收
缺点:A中引用了B。B又引用了A 就算不再使用但是相互引用计数不为0就永远无法无法回收
2:可达性分析
利用GCroots向下搜索,搜索过的路径为引用链,若一个对象到GCroots没有任何引用链相连则不可用事务即可判断时可回收对象
GCroots对象:
虚拟机栈中的引用对象、
方法区的静态引用对象、
方法区常量引用对象、
本地方法栈引用的对象
索引的基本原理:使无序数据变为有序查询
B树:所有节点都存储信息
B+树:只有叶子节点存储数据
都是基于B+树存储的
把数据存储和索引放到一起,按照一定顺序组织,找到索引就找到了数据,数据的物理存储位置和索引的顺序是一致的。
聚簇、非聚簇是基于主键的索引、
其他列的索引叫做辅助索引,辅助索引的叶子结点查询到的是主键信息 利用辅助索引还需要通过辅助索引获取的主键值进行另外一次聚簇或者
叶子结点存储数据,存储的是数据 的行地址, 根据索引查询得到的是数据行的地址,然后再去磁盘查找数据,有一次回表操作,会降低性能
1:聚簇索引查询可以直接获取数据,而非聚簇索引查询需要二次查询执行在磁盘的回表操作,相比聚簇索引效率更高
2:聚簇索引对于范围查询效率更高,其按照顺序双链表排列
3:聚簇索引适应于排序的场合
1:维护索引代价很高,大量插入数据等会导致索引树结构发生巨大改动
2:主键占用内存很大,辅助索引叶子节点存储的也是主键,会导致占用内存也会很大
一定有主建,
聚簇索引,不手动设置则会unique索引,没有unique索引则会使用数据库内部的隐藏ID 作为主键索引。在聚簇索引基础上会设置辅助索引,辅助索引查找数据都需要进行二次索引,
非聚簇都是用辅助索引叶子节点存储的不是物理位置,而是主键值
使用非聚簇索引,没有聚簇索引,非聚簇索引的两棵B+树没什么不同,结构一致,只是存储的内容不同,主键索引存储了主键,辅助索引B+树存储了辅助键,表的数据存储在单的地方,两个B+树的叶子节点都使用一个地址指向真正的数据
大数据量的排序、扫描、count等操作MYISAM的性能更好,其占用的空间更小
大多数需要单条数据查询使用哈希索引性能更快,需要范围查询等使用Btree更好
B+树:
平衡多叉树,根到每个叶子的高度差不超1,叶子节点同层级之间指针相互连接 双向指针
哈希索引:
哈希算法映射,使用单条数据等值查询,速度极快,范围查询则很慢
1:数据量基础较小,使用索引效果较差,没必要建立索引,因为数据量小还要维护索引树,没有必要
2:索引过度,太多索引,会由于插入删除导致索引树重构,开销很大
3:频繁修改的字段不适合创建索引
4:尽量用可以有效区分地段做的索引
5:尽量拓展索引。不要新建索引
6:查询中很少涉及的列,重复值比较多的列不要建立索引
1:基于属性的分类:共享锁、排他锁
2:基于所得粒度:表级锁、行级锁 、页级锁、记录锁、间隙锁、临键锁
3:基于锁的状态:意向共享锁、意向排它锁
共享锁:——读锁—–S锁
一个事务对数据加上共享锁后其他事务只能对它加读锁,不能加写锁,直到它释放读锁,别的事物才可以加写锁
目的:为了支持并发访问数据,读取时不允许
排他锁:写锁 X锁
一个事务对数据加写锁后,其他事务不能对它加任何锁,知道写锁释放,其他事务才可以操作
目的:在数据修改时不允许别人修改,读取,防止出现脏读脏数据
表锁:
锁住整个表,别的事务访问该锁必须等它释放才可以对表进行访问
特点:粒度大 实现简单但是容易冲突、效率慢
行级锁:
上锁的时候锁住 的是表中的一行或者多行,其他行可以访问
特点:粒度小、加锁麻烦、不容易冲突、并发性高
记录锁:
行锁的一种,锁的是一条记录,精准命中, 且是唯一索引
加了记录锁可以避免重复读的问题,也避免脏读问题
页锁:介于行锁和表锁的中间
一次锁定相邻一组数据
介于表锁行锁之间;可能出现死锁问题
间隙锁:行锁的一种
锁的是表记录的一个区间 中间的范围 左开右闭
临建锁:
把查询出来的记录锁住,把间隙空间也会锁住
意向锁:A事务对数据加锁后就会设置一个状态告诉后面的人,已经有人对数据加排他锁了,不能对表再加锁了,后面的事务就可以获取这个状态判断自己是否可以对表进行加锁,避免了对整个索引树节点的扫描是否有锁,这个状态就是意向锁
意向共享锁:
当一个事务试图对整个表进行加共享锁之前,首先获取这个表的意向共享锁
意向排他锁:
当一个事务试图对整个表进行加排他锁之前,首先获取这个表的意向排他锁
事务的基本特性
概念:一组SQL语句,要么全部执行成功要么全部执行失败,以原子性的方式处理
A:actomicity 原子性
全部执行成功要么全部执行失败
C consistency 一致性
数据库总是从一个一致状态转换为另一个一致状态,若事务最后未提交则不会保存修改
I isolation 隔离性:
一个事务的修改在它提交以前对其他事务来说是不可见的
D durability 持久性
一旦提交即可在数据库中永久存储即使崩溃,数据也不会丢失
1:读未提交(脏读)
A在读取时读取到了B修改但未提交的数据,最后B 若取消修改则A获取到的数据是错误的
2:读已提交(不可重复读)
A读取一条数据后,B对该数据修改,A再一次读取该数据时发现数据已被修改出现错误
3:可重复读(幻读)
A在读取某个范围内的数据后,B在该范围内插入了新的记录,使得A的读取内容出现了幻行(上次没有这次出现)
4:可串行序列化:
强制事物按照序列执行,不同事务不会产生冲突,但是会使得每条数据都加锁,导致大量的锁的争用问题,并发性受到极大的影响
概念:多个事物互相持有和请求相同资源的锁使得产生循环依赖
解决:InaoDB将最少行级排他锁的事务进行回滚
预写式日志:修改数据后存储引擎只会修改内存中的数据副本,将更改的记录写入日志中,持久保存与磁盘,后期空闲时间某进程会由此更新磁盘中的数据
若发生故障,可根据日志进行逆操作实现数据的恢复
将行级锁与对版本并发控制MVCC技术相结合
概念:一个行级锁的变种,在多数情况下避免了加锁的操作,使得开销的以降低,实现了非阻塞的读操作,以及只锁定必要写操作的行
工作原理:使用数据在某个时间点的快照实现 ——>无论事务运行多久都可以看到数据的一致视图,也意味着不同的事务可以在同一时间看到同一张表的不同数据
概念:将一个节点只执行的写操作分发到其他节点
用途:将数据写入多台服务器或者多个地区
所有的异常来自父类Throwable
Throwable其中分为Exceptiorn和Error
1:Error是无法处理的错误,出现错误会导致程序终止
2:Exceptiorn:不会导致程序终止,有运行异常RunTImeException、编译异常 CheckException
运行异常RunTImeException 导致当前 线程执行失败 不会影响别的线程
编译异常 CheckException 会导致编译不会通过
生命周期状态:创建、就绪、阻塞、运行、死亡
新建:new一个线程对象
就绪:对象创建后,调用了该对象的statrt方法,置于可运行线程中,变得可运行,等待获取cpu使用权
运行:获取了cpu使用权开始执行程序代码
阻塞:因为某种原因放弃cpu使用权,暂时停止运行,直到进入就绪状态,才有机会转换到运行状态
死亡状态:线程执行完了或者因为异常退出了run方法,线程的生命周期结束
1:等待阻塞 :调用wait()方法,释放占用的资源、jvm把线程放入等待池中,不能自动唤醒,必须用notify或者notifyall等唤醒
2:同步阻塞: 获取同步锁时,若同步锁被别的线程占用则会放入锁池中
3:其他阻塞 :sleep、join等方法
锁池:需要竞争同步锁的线程会被放入锁池,当其中一个线程获取到同步锁,其他的线程就需要在这个锁池等待,当前面的线程释放同步锁后,锁池中的线程才会去竞争同步锁,当某个线程获取到同步锁后就会进入就绪队列等待cpu资源的分配。
等待池:wait()调用该方法后该线程会进入等待池,不会竞争同步锁,只有调用notify后才会从等待池中选择随机一个线程放入锁池,或者notifyall调用全部线程放入锁池中参与锁的竞争。