1、char和varchar的区别?

(1)char的长度是不可变的,而varchar的长度是可变的。也就是说,定义一个char[10]和varchar[10],如果存进去的是‘abcd’,那么char所占的长度依然为10,除了字符‘abcd’外,后面跟六个空格,而varchar就立马把长度变为4了,取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的。

(2)char的存储方式是,对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。

(3)varchar的存储方式是,对每个英文字符占用2个字节,汉字也占用2个字节。

2、事务的隔离级别

事务隔离级别

脏读

不可重复读

幻读

读未提交(read-uncommitted)

不可重复读(read-committed)

可重复读(repeatable-read)

串行化(serializable)

mysql默认的事务隔离级别为repeatable-read

3、事务的并发问题

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

4、Mysql 中有哪几种锁?

MyISAM 支持表锁,InnoDB 支持表锁和行锁,默认为行锁

1、表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低

2、行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高;InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。

(1)共享锁,也称读锁,多用于判断数据是否存在,多个读操作可以同时                      进行而不会互相影响。当如果事务对读锁进行修改操作,很可能会造                      成死锁

(2)排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他                       写锁和读锁。

行锁的劣势:开销大;加锁慢;会出现死锁行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:共享锁:select * from tableName where ... + lock in share more排他锁:select * from tableName where ... + for update

总结

1. InnoDB 支持表锁和行锁,使用索引作为检索条件修改数据时采用行锁,否则采用表锁。2. InnoDB 自动给修改操作加锁,给查询操作不自动加锁3. 行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain执行计划查询索引是否被实际使用。4. 行锁相对于表锁来说,优势在于高并发场景下表现更突出,毕竟锁的粒度小。5. 当表的大部分数据需要被修改,或者是多表复杂关联查询时,建议使用表锁优于行锁。6. 为了保证数据的一致完整性,任何一个数据库都存在锁定机制。锁定机制的优劣直接影响到一个数据库的并发处理能力和性能。

5、MySQL索引

索引从实现上说,分成 2 种:聚簇索引和辅助索引(也叫二级索引或者非聚簇索引)

从功能上说,分为 6 种:普通索引,唯一索引,主键索引,复合索引,外键索引,全文索引。

聚簇索引(主键索引)

1.使用记录主键值的大小来进行记录和页的排序。

页内的记录是按照主键的大小顺序排成一个单项链表。

各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双       向链表。

2.叶子节点存储的是完整的用户记录。

注:聚簇索引不需要我们显示的创建,他是由InnoDB存储引擎自动为我们创建的。如果没有主键,其也会默认创建一个。聚簇索引只能在搜索条件是主键时才能发挥作用,因为聚簇索引可以根据主键进行排序的。

非聚簇索引(二级索引)

1.叶子节点内部使用(非主键假设为name)字段排序,叶子节点之间也是使用name字段排序。

2.叶子节点不再是完整的数据记录,而是name和主键值。

如果我搜索条件是基于name,需要查询所有字段的信息,那查询过程是啥?

1.根据查询条件,采用name的非聚簇索引,先定位到该非聚簇索引某些记录行。

2.根据记录行找到相应的id,再根据id到聚簇索引中找到相关记录。这个过程叫做回表。

联合索引

简单来说,如果name和age组成一个联合索引,那么先按name排序,如果name一样,就按age排序。

一些原则

1.最左前缀原则。一个联合索引(a,b,c),如果有一个查询条件有a,有b,那么他则走索引,如果有一个查询条件没有a,那么他则不走索引。

2.不要过度索引。每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能。在修改表的内容时,索引必须进行更新,有时可能需要重构,因此,索引越多,所花的时间越长。

3.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2021-01-01’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2021-01-01’)。

6、什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。常见的解决死锁的方法

1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

如果业务处理不好可以用分布式事务锁或者使用乐观锁

7、悲观锁与乐观锁

锁的一种宏观分类方式是悲观锁和乐观锁。悲观锁与乐观锁并不是特指某个锁(Java中没有哪个Lock实现类就叫PessimisticLock或OptimisticLock),而是在并发情况下的两种不同策略。

悲观锁(Pessimistic Lock), 就是很悲观,每次去拿数据的时候都认为别人会修改。所以每次在拿数据的时候都会上锁。这样别人想拿数据就被挡住,直到悲观锁被释放。

乐观锁(Optimistic Lock), 就是很乐观,每次去拿数据的时候都认为别人不会修改。所以不会上锁,不会上锁!但是如果想要更新数据,则会在更新前检查在读取至更新这段时间别人有没有修改过这个数据。如果修改过,则重新读取,再次尝试更新,循环上述步骤直到更新成功(当然也允许更新失败的线程放弃操作)。

悲观锁阻塞事务,乐观锁回滚重试,它们各有优缺点,不要认为一种一定好于另一种。像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

。。。。。持续更新中