MySQL基础

MySQL基础

非关系型数据库和关系型数据库的区别?

关系型数据库:将数据存储在表中的数据库,以二维表为数据结构。表和字段类型之间的关系需要明确定义,以SQL语句为操作指令,也称为SQL数据库。

**非关系型数据库:**不像关系数据库那样使用行和列的表格模式的数据库。相反,它的存储模型是针对它所存储的数据类型进行优化的。不只有使用SQL语句作为操作指令,可以使用其他类型的查询语言,也被称为NoSQL(Not only SQL)数据库, 不需要预先定义关键数据的模式,比SQL数据库更加灵活。

事务的四大特性了解么?

  1. 原子性Atomicity) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  2. 一致性Consistency): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
  3. 隔离性Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
  4. 持久性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个级别,分别是读取未提交、读取已提交、可重复读、可串行化。

乐观锁与悲观锁的区别?

https://mp.weixin.qq.com/s/3567q9Ai3jTGblp_VWMSSg

  • 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
  • 悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。

悲观锁的实现方式是加锁,加锁既可以是对代码块加锁(如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. 线程1读取内存中数据为A;
  2. 线程2将该数据修改为B;
  3. 线程2将该数据修改为A;
  4. 线程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支持数据库异常崩溃后的安全恢复

updatedupdated2024-11-082024-11-08