1 脏读,不可重复读,幻读 ,mysql5.7以后默认隔离级别是什么?
2 什么是qps,tps,并发量,pv,uv
3 什么是接口幂等性问题,如何解决?
1 脏读,不可重复读,幻读 ,mysql5.7以后默认隔离级别是什么?
脏读(Dirty Read),不可重复读(Non-Repeatable Read),和幻读(Phantom Read)是数据库中事务隔离级别引发的问题,它们描述了不同类型的并发读取问题。
### 1. 脏读(Dirty Read):
**定义:** 脏读是指一个事务读取了另一个事务未提交的数据。如果事务 A 修改了一行数据,而事务 B 读取了这个未提交的修改,如果事务 A 回滚,那么事务 B 读取到的数据就是无效的。
**例子:**
1. 事务 A 开始,更新了某行数据但还未提交。
2. 事务 B 读取了这行数据。
3. 事务 A 回滚。
4. 事务 B 读取到的数据是无效的,因为事务 A 的更新被撤销了。
### 2. 不可重复读(Non-Repeatable Read):
**定义:** 不可重复读是指在一个事务内,同一查询在不同时间点返回了不同的结果。
这是因为在两次查询之间,另一个事务修改了相同的数据。
**例子:**
1. 事务 A 开始,读取某行数据。
2. 事务 B 开始,更新或删除了这行数据并提交。
3. 事务 A 再次读取相同的数据,但结果已经不同了。
### 3. 幻读(Phantom Read):
**定义:** 幻读是指在一个事务内,同一查询在不同时间点返回了不同数量的行。
这是因为在两次查询之间,另一个事务插入或删除了数据,导致查询结果不一致。
**例子:**
1. 事务 A 开始,根据某个条件查询了一批数据。
2. 事务 B 开始,插入了符合条件的新数据,并提交。
3. 事务 A 再次查询相同条件下的数据,结果行数不同了。
### 事务隔离级别:
- **读未提交(Read Uncommitted):** 允许脏读、不可重复读和幻读。
- **读已提交(Read Committed):** 防止脏读,但允许不可重复读和幻读。
- **可重复读(Repeatable Read):** 防止脏读和不可重复读,但允许幻读。
- **串行化(Serializable):** 防止脏读、不可重复读和幻读,是最高隔离级别。
选择合适的隔离级别取决于应用的需求和性能要求。更高的隔离级别通常伴随着更多的锁和性能开销。
在 MySQL 中,有四种事务隔离级别,分别是:
- **读未提交(Read Uncommitted):** 允许事务读取尚未提交的更改。这可能导致脏读、不可重复读和幻读。
- **读已提交(Read Committed):** 允许事务读取已经提交的更改。
避免了脏读,但仍可能有不可重复读和幻读。
- **可重复读(Repeatable Read):** 对相同字段的多次读取是一致的,除非事务本身进行写操作。
避免了脏读和不可重复读,但仍可能有幻读。
- **串行化(Serializable):** 最高的隔离级别,通过对读和写加锁来防止所有并发问题,包括脏读、不可重复读和幻读。
MySQL 5.7 默认的隔离级别是 **可重复读**。
2 什么是qps,tps,并发量,pv,uv
**QPS(Queries Per Second):** 表示每秒查询次数,通常用于衡量系统的查询处理能力。
**TPS(Transactions Per Second):** 表示每秒事务处理的数量,通常用于衡量系统的事务处理能力。
**并发量(Concurrency):** 表示系统同时处理的请求数量。高并发指系统能够同时处理大量请求。
**PV(Page Views):** 表示页面浏览量,即网站在一段时间内被访问的总次数。
**UV(Unique Visitors):** 表示独立访客数量,即在一段时间内访问网站的不同访客数量。
2.1 模拟 QPS 和并发量
import time
import threading
from queue import Queue
# 模拟查询的函数
def query():
# 模拟查询需要的时间
time.sleep(0.1)
# 模拟 QPS 和并发量
def simulate_qps_and_concurrency(qps, concurrency):
# 使用队列模拟并发请求
request_queue = Queue()
# 启动并发线程
def worker():
while True:
request = request_queue.get()
query() # 执行查询
request_queue.task_done()
for _ in range(concurrency):
t = threading.Thread(target=worker)
t.daemon = True
t.start()
# 模拟 QPS
start_time = time.time()
for _ in range(qps):
request_queue.put("query")
# 等待所有查询完成
request_queue.join()
# 计算消耗的时间
elapsed_time = time.time() - start_time
print(f"QPS: {qps}, Concurrency: {concurrency}, Elapsed Time: {elapsed_time:.2f} seconds")
# 测试
simulate_qps_and_concurrency(qps=10, concurrency=5)
3 什么是接口幂等性问题,如何解决?
- **问题描述:**
接口幂等性是指同一请求的重复执行不会产生不同的效果,即无论调用一次还是多次,系统的状态都是一致的。
- **解决方案:**
1. **唯一标识符:** 为每个请求生成一个唯一标识符,通过这个标识符来判断请求是否已经被处理。
2. **幂等接口设计:** 接口本身应该设计成幂等的,即多次调用不会产生额外的影响。
3. **使用 Token:** 在请求中包含一个令牌,服务器验证令牌的有效性,避免重复执行。
4. **数据库乐观锁:** 在数据库层面使用乐观锁机制,确保同一数据项在同一时间只能被处理一次。
保证接口的幂等性对于处理因网络问题、重试或其他原因导致的重复请求是非常重要的。
3.1 通过添加唯一标识符保证接口的幂等性
import uuid
class IdempotentApi:
def __init__(self):
self.processed_requests = set()
def process_request(self, request_id):
if request_id in self.processed_requests:
print(f"Request {request_id} has already been processed. Ignoring.")
return
# 模拟处理请求的业务逻辑
print(f"Processing request {request_id}...")
# ...
# 标记请求已经处理
self.processed_requests.add(request_id)
print(f"Request {request_id} processed successfully.")
# 创建一个 IdempotentApi 实例
api = IdempotentApi()
# 模拟重复调用
request_id = str(uuid.uuid4())
api.process_request(request_id)
api.process_request(request_id)