MySQL基础
非关系型数据库和关系型数据库的区别?
关系型数据库:将数据存储在表中的数据库,以二维表为数据结构。表和字段类型之间的关系需要明确定义,以SQL语句为操作指令,也称为SQL数据库。
**非关系型数据库:**不像关系数据库那样使用行和列的表格模式的数据库。相反,它的存储模型是针对它所存储的数据类型进行优化的。不只有使用SQL语句作为操作指令,可以使用其他类型的查询语言,也被称为NoSQL(Not only SQL)数据库, 不需要预先定义关键数据的模式,比SQL数据库更加灵活。
事务的四大特性了解么?
- 原子性(
Atomicity
) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; - 一致性(
Consistency
): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的; - 隔离性(
Isolation
): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的; - 持久性(
Durability
): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
https://blog.csdn.net/wenwenaier/article/details/123218255
ACID 原子性:一个事务中的操作要么全都成功,要么全都不成功;一致性:就是数据库从一个一致性的状态,转换到另一个一致性的状态;隔离性:一个事务的修改在最终提交前,对其他事务是不可见的;持久性:事务一旦提交,所做的修改就会永久保存在数据库中。
比如A向B转账,A有500元,B有100元,A要向B转账100元,这就代表A要-100,B要+100,A-100和B+100的操作是一个整体,不能说只做一半,A要-100,B要+100,要么一起成功,要么一起失败,最终的结果一定要达到A=400,B=200才保证了事物的原子性,而数据从A=500,B=100变成了A=400,B=200状态的转变是事物的一致性,如果当A转钱成功要将200写入B的时候,C也在向B转钱,同时也要把200写入B,C应该等200被真正写入B时才能进行转账操作,否则就违反了事物的隔离性,当B=200确定之后,这个值应该是固定的,不能说因为某些原因(例如宕机)就丢失数据,否则违反持久性。
MySQL 事务隔离级别?默认是什么级别?
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;
命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;
MySQL事务隔离有4个级别,分别是读取未提交、读取已提交、可重复读、可串行化。
乐观锁与悲观锁的区别?
- 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
- 悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如Java的synchronized关键字),也可以是对数据加锁(如MySQL中的排它锁)。
乐观锁的实现方式主要有两种:CAS机制和版本号机制
1、CAS(Compare And Swap)
CAS操作包括了3个操作数:
- 需要读写的内存位置(V)
- 进行比较的预期值(A)
- 拟写入的新值(B)
CAS操作逻辑如下:如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止。
这里引出一个新的问题,既然CAS包含了Compare和Swap两个操作,它又如何保证原子性呢?答案是:CAS是由CPU支持的原子操作,其原子性是在硬件层面进行保证的。
2、版本号机制
除了CAS,版本号机制也可以用来实现乐观锁。版本号机制的基本思路是在数据中增加一个字段version,表示该数据的版本号,每当数据被修改,版本号加1。当某个线程查询数据时,将该数据的版本号一起查出来;当该线程更新数据时,判断当前版本号与之前读取的版本号是否一致,如果一致才进行操作。
优缺点和适用场景
乐观锁和悲观锁并没有优劣之分,它们有各自适合的场景;下面从两个方面进行说明。
1、功能限制 与悲观锁相比,乐观锁适用的场景受到了更多的限制,无论是CAS还是版本号机制。
例如,CAS只能保证单个变量操作的原子性,当涉及到多个变量时,CAS是无能为力的,而synchronized则可以通过对整个代码块加锁来处理。再比如版本号机制,如果query的时候是针对表1,而update的时候是针对表2,也很难通过简单的版本号来实现乐观锁。
2、竞争激烈程度 如果悲观锁和乐观锁都可以使用,那么选择就要考虑竞争的激烈程度:
- 当竞争不激烈 (出现并发冲突的概率小)时,乐观锁更有优势,因为悲观锁会锁住代码块或数据,其他线程无法同时访问,影响并发,而且加锁和释放锁都需要消耗额外的资源。
- 当竞争激烈(出现并发冲突的概率大)时,悲观锁更有优势,因为乐观锁在执行更新时频繁失败,需要不断重试,浪费CPU资源。
乐观锁加锁吗?
- 乐观锁本身是不加锁的,只是在更新时判断一下数据是否被其他线程更新了;AtomicInteger便是一个例子。
- 有时乐观锁可能与加锁操作合作,例如,在前述updateCoins()的例子中,MySQL在执行update时会加排它锁。但这只是乐观锁与加锁操作合作的例子,不能改变“乐观锁本身不加锁”这一事实。
CAS有哪些缺点?
1、ABA问题
假设有两个线程——线程1和线程2,两个线程按照顺序进行以下操作:
- 线程1读取内存中数据为A;
- 线程2将该数据修改为B;
- 线程2将该数据修改为A;
- 线程1对数据进行CAS操作
在第(4)步中,由于内存中数据仍然为A,因此CAS操作成功,但实际上该数据已经被线程2修改过了。这就是ABA问题。 在AtomicInteger的例子中,ABA似乎没有什么危害。但是在某些场景下,ABA却会带来隐患,例如栈顶问题:一个栈的栈顶经过两次(或多次)变化又恢复了原值,但是栈可能已发生了变化。
对于ABA问题,比较有效的方案是引入版本号,内存中的值每发生一次变化,版本号都+1;在进行CAS操作时,不仅比较内存中的值,也会比较版本号,只有当二者都没有变化时,CAS才能执行成功。Java中的AtomicStampedReference类便是使用版本号来解决ABA问题的。
2、高竞争下的开销问题
在并发冲突概率大的高竞争环境下,如果CAS一直失败,会一直重试,CPU开销较大。针对这个问题的一个思路是引入退出机制,如重试次数超过一定阈值后失败退出。当然,更重要的是避免在高竞争环境下使用乐观锁。
3、功能限制
CAS的功能是比较受限的,例如CAS只能保证单个变量(或者说单个内存值)操作的原子性,这意味着:(1)原子性不一定能保证线程安全,例如在Java中需要与volatile配合来保证线程安全;(2)当涉及到多个变量(内存值)时,CAS也无能为力。
除此之外,CAS的实现需要硬件层面处理器的支持,在Java中普通用户无法直接使用,只能借助atomic包下的原子类使用,灵活性受到限制。
乐观锁就是操作数据时,比较乐观,认为不会有人也修改数据,所以其实乐观锁本质上是没有加锁的,只在更新的时候判断了一下是否这期间也有其他人修改了数据,如果没有人修改就正常执行,否则就放弃操作;悲观锁在操作数据时比较悲观,认为总有别人修改了数据,于是就要把操作数据的行为加锁,这期间其他人不能操作修改数据,直到完成操作才把锁释放了,别人才能继续操作。 乐观锁一般有两种实现方式:版本号机制和CAS; 悲观锁的实现方式就是加锁,如Java的synchronized还有MySQL的排它锁。
版本号机制:就是在数据中加一个version字段来表示当前版本,每当数据修改这个字段就加1,当某个线程操作修改数据时,会把这个版本号一起查出来,更新的时候再判断一下版本号跟之前读取的是否一致,一致才继续操作。 CAS:比较并交换,CAS涉及了三个操作数,内存中的值V,预期的值A,要更新的值B,正常情况下预期的值是和内存中的值相等的,这个时候就会正常把内存中的值更新为B,如果不相等就不操作;
MySQL 数据库两种存储引擎的区别?
1.是否支持行级锁
MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。 也就说,MyISAM 一锁就是锁住了整张表,这在并发写的情况下是多么滴憨憨啊!这也是为什么 InnoDB 在并发写的时候,性能更牛皮了!
2.是否支持事务 MyISAM 不提供事务支持。 InnoDB 提供事务支持,具有提交(commit)和回滚(rollback)事务的能力。
3.是否支持外键 MyISAM 不支持,而 InnoDB 支持。
4.是否支持数据库异常崩溃后的安全恢复
MyISAM 不支持,而 InnoDB 支持。
使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 redo log
。
5.是否支持 MVCC MyISAM 不支持,而 InnoDB 支持。 MVCC 可以看作是行级锁的一个升级,可以有效减少加锁操作,提高性能
InnoDB 支持事务,MyISAM 不支持事务;InnoDB 支持外键,而 MyISAM 不支持;InnoDB 是聚集索引,MyISAM 是非聚集索引;InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁;InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);InnoDB支持数据库异常崩溃后的安全恢复