mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-07-28 12:22:17 +08:00
Compare commits
6 Commits
1781487675
...
c94198df71
Author | SHA1 | Date | |
---|---|---|---|
|
c94198df71 | ||
|
8dd6408e70 | ||
|
da2564a8f3 | ||
|
5a47c64fb0 | ||
|
5238517a52 | ||
|
7c234c8959 |
@ -427,6 +427,10 @@ Dubbo 是一款国产的 RPC 框架,由阿里开源。相关阅读:
|
||||
* [从毕业到入职半年的感受](https://javaguide.cn/about-the-author/feelings-of-half-a-year-from-graduation-to-entry/)
|
||||
* [某培训机构盗我文章做成视频还上了B站热门](https://javaguide.cn/about-the-author/my-article-was-stolen-and-made-into-video-and-it-became-popular/)
|
||||
|
||||
## Star 趋势
|
||||
|
||||

|
||||
|
||||
## 公众号
|
||||
|
||||
如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
|
||||
|
@ -6,7 +6,6 @@ tag:
|
||||
- 大厂面试
|
||||
---
|
||||
|
||||
|
||||
## MySQL 基础
|
||||
|
||||
### 关系型数据库介绍
|
||||
@ -125,24 +124,6 @@ MVCC 可以看作是行级锁的一个升级,可以有效减少加锁操作,
|
||||
|
||||
因此,对于咱们日常开发的业务系统来说,你几乎找不到什么理由再使用 MyISAM 作为自己的 MySQL 数据库的存储引擎。
|
||||
|
||||
## 锁机制与 InnoDB 锁算法
|
||||
|
||||
**MyISAM 和 InnoDB 存储引擎使用的锁:**
|
||||
|
||||
- MyISAM 采用表级锁(table-level locking)。
|
||||
- InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁
|
||||
|
||||
**表级锁和行级锁对比:**
|
||||
|
||||
- **表级锁:** MySQL 中锁定 **粒度最大** 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
|
||||
- **行级锁:** MySQL 中锁定 **粒度最小** 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
|
||||
|
||||
**InnoDB 存储引擎的锁的算法有三种:**
|
||||
|
||||
- Record lock:记录锁,单个行记录上的锁
|
||||
- Gap lock:间隙锁,锁定一个范围,不包括记录本身
|
||||
- Next-key lock:record+gap 临键锁,锁定一个范围,包含记录本身
|
||||
|
||||
## 查询缓存
|
||||
|
||||
执行查询语句的时候,会先查询缓存。不过,MySQL 8.0 版本后移除,因为这个功能不太实用
|
||||
@ -261,6 +242,14 @@ SQL 标准定义了四个隔离级别:
|
||||
| REPEATABLE-READ | × | × | √ |
|
||||
| SERIALIZABLE | × | × | × |
|
||||
|
||||
### MySQL 的隔离级别是基于锁实现的吗?
|
||||
|
||||
MySQL 的隔离级别基于锁和 MVCC 机制共同实现的。
|
||||
|
||||
SERIALIZABLE 隔离级别,是通过锁来实现的。除了 SERIALIZABLE 隔离级别,其他的隔离级别都是基于 MVCC 实现。
|
||||
|
||||
不过, SERIALIZABLE 之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读。
|
||||
|
||||
### MySQL 的默认隔离级别是什么?
|
||||
|
||||
MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看,MySQL 8.0 该命令改为`SELECT @@transaction_isolation;`
|
||||
@ -276,7 +265,10 @@ mysql> SELECT @@tx_isolation;
|
||||
|
||||
~~这里需要注意的是:与 SQL 标准不同的地方在于 InnoDB 存储引擎在 **REPEATABLE-READ(可重读)** 事务隔离级别下使用的是 Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说 InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)** 已经可以完全保证事务的隔离性要求,即达到了 SQL 标准的 **SERIALIZABLE(可串行化)** 隔离级别。~~
|
||||
|
||||
🐛 问题更正:**MySQL InnoDB 的 REPEATABLE-READ(可重读)并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁读使用到的机制就是 Next-Key Locks。**
|
||||
🐛 问题更正:MySQL 在 REPEATABLE READ 隔离级别下,是可以解决幻读问题发生的,主要有下面两种情况:
|
||||
|
||||
- **快照读** :这种情况下是可以解决幻读的,它是由 MVCC 机制来解决的。
|
||||
- **当前读** : 这种情况下并不保证避免幻读,需要应用使用加锁读来保证,这个加锁读使用到的机制就是 Next-Key Lock(间隙锁)。
|
||||
|
||||
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 **READ-COMMITTED(读取提交内容)** ,但是你要知道的是 InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)** 并不会有任何性能损失。
|
||||
|
||||
@ -286,7 +278,26 @@ InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到 **SERIALI
|
||||
|
||||
> InnoDB 存储引擎提供了对 XA 事务的支持,并通过 XA 事务来支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源(transactional resources)参与到一个全局的事务中。事务资源通常是关系型数据库系统,但也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对于事务原有的 ACID 要求又有了提高。另外,在使用分布式事务时,InnoDB 存储引擎的事务隔离级别必须设置为 SERIALIZABLE。
|
||||
|
||||
## 锁机制与 InnoDB 锁算法
|
||||
|
||||
**MyISAM 和 InnoDB 存储引擎使用的锁:**
|
||||
|
||||
- MyISAM 采用表级锁(table-level locking)。
|
||||
- InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁
|
||||
|
||||
**表级锁和行级锁对比:**
|
||||
|
||||
- **表级锁:** MySQL 中锁定 **粒度最大** 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
|
||||
- **行级锁:** MySQL 中锁定 **粒度最小** 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
|
||||
|
||||
**InnoDB 存储引擎的锁的算法有三种:**
|
||||
|
||||
- Record lock:记录锁,单个行记录上的锁
|
||||
- Gap lock:间隙锁,锁定一个范围,不包括记录本身
|
||||
- Next-key lock:record+gap 临键锁,锁定一个范围,包含记录本身
|
||||
|
||||
## 参考
|
||||
|
||||
- 《高性能 MySQL》
|
||||
- https://www.omnisci.com/technical-glossary/relational-database
|
||||
- Relational Database:https://www.omnisci.com/technical-glossary/relational-database
|
||||
- 技术分享 | 隔离级别:正确理解幻读:https://opensource.actionsky.com/20210818-mysql/
|
||||
|
@ -30,6 +30,10 @@ title: JavaGuide(Java学习&&面试指南)
|
||||
|
||||
<a href="https://t.1yb.co/GXLF"><img src="https://img-blog.csdnimg.cn/2f61f3e2d1f2427da977340919e41616.png" style="margin: 0 auto;width:850px" /></a>
|
||||
|
||||
## Star 趋势
|
||||
|
||||

|
||||
|
||||
## 联系我
|
||||
|
||||
想要参与项目维护或者学习交流的话,欢迎添加我的微信:“**JavaGuide1996**” 备注“**Github**”即可!
|
||||
|
@ -11,7 +11,7 @@ tag:
|
||||
|
||||
**代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。**
|
||||
|
||||
举个例子:你找了小红来帮你问话,小红就可以看作是代理你的代理对象,代理的行为(方法)是问话。
|
||||
举个例子:新娘找来了自己的姨妈来代替自己处理新郎的提问,新娘收到的提问都是经过姨妈处理过滤之后的。姨妈在这里就可以看作是代理你的代理对象,代理的行为(方法)是接收和回复新郎的提问。
|
||||
|
||||

|
||||
|
||||
|
@ -87,7 +87,7 @@ Class alunbarClass2 = o.getClass();
|
||||
**4. 通过类加载器`xxxClassLoader.loadClass()`传入类路径获取:**
|
||||
|
||||
```java
|
||||
Class clazz = ClassLoader.loadClass("cn.javaguide.TargetObject");
|
||||
ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
|
||||
```
|
||||
|
||||
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行
|
||||
|
@ -276,15 +276,18 @@ public interface TransactionStatus{
|
||||
举个例子:我们在 A 类的`aMethod()`方法中调用了 B 类的 `bMethod()` 方法。这个时候就涉及到业务层方法之间互相调用的事务问题。如果我们的 `bMethod()`如果发生异常需要回滚,如何配置事务传播行为才能让 `aMethod()`也跟着回滚呢?这个时候就需要事务传播行为的知识了,如果你不知道的话一定要好好看一下。
|
||||
|
||||
```java
|
||||
@Service
|
||||
Class A {
|
||||
@Autowired
|
||||
B b;
|
||||
@Transactional(propagation = Propagation.xxx)
|
||||
public void aMethod {
|
||||
//do something
|
||||
B b = new B();
|
||||
b.bMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
Class B {
|
||||
@Transactional(propagation = Propagation.xxx)
|
||||
public void bMethod {
|
||||
@ -357,15 +360,17 @@ public enum Propagation {
|
||||
举个例子:如果我们上面的`aMethod()`和`bMethod()`使用的都是`PROPAGATION_REQUIRED`传播行为的话,两者使用的就是同一个事务,只要其中一个方法回滚,整个事务均回滚。
|
||||
|
||||
```java
|
||||
@Service
|
||||
Class A {
|
||||
@Autowired
|
||||
B b;
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void aMethod {
|
||||
//do something
|
||||
B b = new B();
|
||||
b.bMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
Class B {
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void bMethod {
|
||||
@ -381,15 +386,18 @@ Class B {
|
||||
举个例子:如果我们上面的`bMethod()`使用`PROPAGATION_REQUIRES_NEW`事务传播行为修饰,`aMethod`还是用`PROPAGATION_REQUIRED`修饰的话。如果`aMethod()`发生异常回滚,`bMethod()`不会跟着回滚,因为 `bMethod()`开启了独立的事务。但是,如果 `bMethod()`抛出了未被捕获的异常并且这个异常满足事务回滚规则的话,`aMethod()`同样也会回滚,因为这个异常被 `aMethod()`的事务管理机制检测到了。
|
||||
|
||||
```java
|
||||
@Service
|
||||
Class A {
|
||||
@Autowired
|
||||
B b;
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void aMethod {
|
||||
//do something
|
||||
B b = new B();
|
||||
b.bMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
Class B {
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void bMethod {
|
||||
@ -408,15 +416,18 @@ Class B {
|
||||
这里还是简单举个例子:如果 `bMethod()` 回滚的话,`aMethod()`也会回滚。
|
||||
|
||||
```java
|
||||
@Service
|
||||
Class A {
|
||||
@Autowired
|
||||
B b;
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void aMethod {
|
||||
//do something
|
||||
B b = new B();
|
||||
b.bMethod();
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
Class B {
|
||||
@Transactional(propagation = Propagation.NESTED)
|
||||
public void bMethod {
|
||||
|
Loading…
x
Reference in New Issue
Block a user