mysql 基础
MySql 引擎
InnoDB 引擎
1、行级锁
2、不支持全文检索
3、不记录表行数,count(*) 是需要扫描全表
4、插入慢,update 时慢
5、写入是不会锁定表,适用并发较高的场景下使用
6、支持事务处理的故障恢复、利用日志进行数据恢复
7、主键查询也比较快
MyISAM 引擎
1、表级锁
2、支持全文检索
3、insert 时比InnoDB快
4、对表操作多、且不需要事务时,比较适合
MySql 索引有几种类型
普通索引
唯一索引
主键索引
组合索引
全文索引
java 基础
java 数据结构:
类型 优点 缺点
数组: 插入快 查找、删除慢;大小固定,只能存一个元素
有序数组: 比数据查询快 插入、删除慢:大小固定 ,只能存一个元素
栈(Stack): 先进后出 存取他项慢
队列(Queue): 先进先出 存取他项慢
连表(linked List): 插入、删除快 查找慢
树(tree): 插入、查找、删除都快 删除算法复杂
哈希表(Hash Table): 如果关键字已知则存取都快 删除慢、如果不知道关键字则慢,对存储空间利用不充分
堆(heap): 插入、删除快,对大数据存取快 对其他数据项存取慢
图(Graph): 对现实世界建模 有些算法慢且复杂
常用的集合:
map list set存取值有什么特点
集合:
List:有序,线程不安全,查询速度快,允许重复,允许插null
Vectoe:线程安全
LinkedList:对于插入和删除更适合
Set:无序插入时会检查key是否存在,存在则反回false,查询速度快
TreeSet:有排序的能力,底层通过二叉树进行排序
map:
hashmap 无序,key不允许重复,值允许重复,线程不安全,
hashTable 无序,不允许键重复,线程安全
treeMap 底层是二叉树
事务:
四个特性:
原子性:所有操作要么成功,要么失败
一致性:从一个一致性状态到另,一个一致性状态;数据都是一致的,在事务操作前后,两个帐户的钱加起来都是相等的
隔离性:每个事务之间不能相互影响,如果一个事务正在进行,则其他事务需要等这个事务结束后才能执行,
持久性:事务一旦提交,那么数据库里的数据改变就是永久性的;即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
脏读:A 事务正在操作数据(未提交事务),B并发的事务来访问数据拿到了修改的数据,但如果事务不提交(提交失败)则数据会发生回滚,则B拿到数据是无效的
不可重复读:A 事务在B 事务进行读取了数据,B 事务在A 事务读取后做了修改操作,A 事务再次读取了数,发现多次读取数据不一致
虚读:幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
不同点:幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
spring 隔离级别:
默认数据库的
未提交读 【脏读,幻读,不可重复读】
提交读 sql server 默认 【幻读,不可重复读】
可重复读 mysql 默认 【幻读】
串行化
spring 传播行为
PROPAGATION_REQUIRED 支持当前事务,如当前没有事务,则新建一个。
PROPAGATION_SUPPORTS 支持当前事务,如当前没有事务,则以非事务性执行
PROPAGATION_MANDATORY 支持当前事务,如当前没有事务,则抛出异常
PROPAGATION_REQUIRES_NEW始终新建一个事务,如当前原来有事务,则把原事务挂起。
PROPAGATION_NOT_SUPPORTED 不支持当前事务,始终已非事务性方式执行,如当前事务存在,挂起该事务。
PROPAGATION_NEVER 不支持当前事务;如果当前事务存在,则引发异常。
PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行,如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作
乐观锁与悲观锁
乐观锁不需要加锁,操作后再检查
悲观锁需要加锁:
共享锁:门有两把锁匙,lock in share mode 用于mysql中
排他锁:一个事务操作时,另外的事务无法访问
实现同步的三种类型
synchronize关键字
ReentrantLock
volatile
java 线程同步的几种方式:
同步方法
同步代码块
使用特殊域变量(volatile)实现线程同步
使用重入锁实现线程同步(ReentrantLock)
使用局部变量实现线程同步 (ThreadLocal)
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
使用阻塞队列实现线程同步
LinkedBlockingQueue
使用原子变量实现线程同步
索引失效的几种情况
is null
or
like '%xx'
in
or
1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
2.对于多列索引,不是使用的第一部分,则不会使用索引
3.like查询以%开头
4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引
spring bean 的作用域
singleton 单例
prototype 原型
request 一次请求
session 一次会话
global Session 在一个全局的Http Session中
死锁产生的四个必要条件
互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
循环等待条件:在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。
redis 相关
redis 的五种数据类型
hash
list
set
string
zset(有序列)
过期删除策略:
定时删除:
创建定时器,在时间到了时候,立刻对键进行删除过期键能尽可能被删除,并释放内存在过期键比较多的情况下,删除操作可能会占用一部分CPU时间。当内存不紧张而CPU非常紧张的情况下,会对服务器响应时间和吞吐量造成影响
惰性删除:
每次从键空间获取键时,都检查是否过期,过期则删除,未过期,则返回该键 只有取出键时才对其进行过期检查,不会删除其他键,不会花费CPU太多时间。若一个键早已过期,但一直未被取到,它便会一直占用内存。若有大量的未被访问的键,而服务器又不会主动释放,就会造成大量的内存浪费。
定期删除:
每隔一段时间删除里面的过期键 每隔一段时间删除过期键,减少了对cpu占用时间的影响 也有效的减少了过期键过多而造成的内存浪费 删除操作执行的时长和频率。既不能太频繁也不能太稀疏,需合理设置
失效策略:
volatile-lru:根据LRU算法生成的过期时间来删除。
allkeys-lru:根据LRU算法删除任何key。
volatile-random:根据过期设置来随机删除key。
allkeys->random:无差别随机删。
volatile-ttl:根据最近过期时间来删除(辅以TTL)
noeviction:谁也不删,直接在写操作时返回错误。
雪崩和数据穿透:
雪崩:
定义:
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。
解决方案:
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存
不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。
数据穿透:
定义:
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决方案:
对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
也可以采用一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
虚拟机相关
线程共享
直接内存:
堆(heap):
静态方法区:
线程私有
栈:
程序计数器:
本地方法栈:
内存回收系统
GC判断策略:
1,引用计数
2,要节点可达
GC收集算法:
1,标记-清除
2,标记-清除-整理(标记-整理)
3,标记-复制-清除(复制)
4,分代回收
GC收集器: