一、死锁原理与检测机制
1. 死锁产生原理
sql
复制
下载
-- 死锁产生的四个必要条件(Coffman条件):
-- 1. 互斥条件 (Mutual Exclusion)
-- 2. 持有并等待 (Hold and Wait)
-- 3. 不可剥夺 (No Preemption)
-- 4. 循环等待 (Circular Wait)
-- 示例:典型的死锁场景
-- 事务T1: 事务T2:
-- BEGIN; BEGIN;
-- UPDATE users SET ... UPDATE products SET ...
-- WHERE id = 1; WHERE id = 100;
--
-- UPDATE products SET ... UPDATE users SET ...
-- WHERE id = 100; WHERE id = 1;
-- COMMIT; COMMIT;
2. 数据库死锁检测实现
java
复制
下载
/**
* 死锁检测算法实现
*/
public class DeadlockDetector {
/**
* 等待图(Wait-For Graph)算法
* 将事务和锁等待关系建模为有向图
*/
public static class WaitForGraph {
// 节点:事务
// 边:T1 -> T2 表示 T1 等待 T2 释放锁
private final Map<String, Set<String>> graph = new ConcurrentHashMap<>();
private final Object lock = new Object();
/**
* 添加等待关系
* @param waiter 等待的事务
* @param holder 持有锁的事务
*/
public void addWaitFor(String waiter, String holder) {
synchronized (lock) {
graph.computeIfAbsent(waiter, k -> new HashSet<>()).add(holder);
System.out.printf("Wait-for edge added: %s -> %s%n", waiter, holder);
// 检查是否产生死锁
if (hasCycle(waiter)) {
System.out.println("⚠️ Deadlock detected!");
resolveDeadlock(waiter);
}
}
}
/**
* 移除等待关系
*/
public void removeWaitFor(String waiter, String holder) {
synchronized (lock) {
Set<String> holders = graph.get(waiter);
if (holders != null) {
holders.remove(holder);
if (holders.isEmpty()) {
graph.remove(waiter);
}
}
}
}
/**
* 检测环路(深度优先搜索)
*/
private boolean hasCycle(String startNode) {
Set<String> visited = new HashSet<>();
Set<String> recursionStack = new HashSet<>();
return dfs(startNode, visited, recursionStack);
}
private boolean dfs(String node, Set<String> visited, Set<String> recursionStack) {
if (recursionStack.contains(node)) {
return true; // 发现环路
}
if (visited.contains(node)) {
return false;
}
visited.add(node);
recursionStack.add(node);
Set<String> neighbors = graph.get(node);
if (neighbors != null) {
for (String neighbor : neighbors) {
if (dfs(neighbor, visited, recursionStack)) {
return true;
}
}
}
recursionStack.remove(node);
return false;
}
/**
* 查找环路中的所有事务
*/
private List<String> findCycle(String startNode) {
Map<String, String> parent = new HashMap<>();
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
queue.offer(startNode);
visited.add(startNode);
while (!queue.isEmpty()) {
String current = queue.poll();
Set<String> neighbors = graph.get(current);
if (neighbors != null) {
for (String neighbor : neighbors) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
parent.put(neighbor, current);
queue.offer(neighbor);
} else if (neighbor.equals(startNode)) {
// 找到环路
return buildCyclePath(parent, current, startNode);
}
}
}
}
return Collections.emptyList();
}
/**
* 构建环路路径
*/
private List<String> buildCyclePath(Map<String, String> parent, String end, String start) {
List<String> cycle = new ArrayList<>();
String current = end;
while (current != null) {
cycle.add(current);
if (current.equals(start)) {
break;
}
current = parent.get(current);
}
Collections.reverse(cycle);
cycle.add(start); // 闭合环路
return cycle;
}
/**
* 解决死锁
*/
private void resolveDeadlock(String victimCandidate) {
// 查找完整的环路
List<String> cycle = findCycle(victimCandidate);
if (cycle.isEmpty()) {
System.out.println("No cycle found, false positive");
return;
}
System.out.println("Deadlock cycle: " + String.join(" -> ", cycle));
// 选择牺牲者(通常选择代价最小的事务)
String victim = selectVictim(cycle);
System.out.println("Selected victim: " + victim);
// 回滚牺牲者事务
rollbackTransaction(victim);
// 清理等待图
cleanupAfterRollback(victim);
}
/**
* 选择牺牲者策略
*/
private String selectVictim(List<String> cycle) {
// 策略1: 选择最近开始的事务(最少工作丢失)
// 策略2: 选择持有锁最少的事务
// 策略3: 基于事务优先级
// 策略4: 随机选择(简单但公平)
Random random = new Random();
return cycle.get(random.nextInt(cycle.size()));
}
private void rollbackTransaction(String transactionId) {
System.out.println("Rolling back transaction: " + transactionId);
// 实际实现中,这里会调用数据库的回滚机制
// 例如:发送 ROLLBACK 命令
}
private void cleanupAfterRollback(String transactionId) {
// 移除所有与该事务相关的边
synchronized (lock) {
// 移除该事务等待的边
graph.remove(transactionId);
// 移除其他事务等待该事务的边
graph.values().forEach(holders -> holders.remove(transactionId));
// 清理空的条目
graph.entrySet().removeIf(entry -> entry.getValue().isEmpty());
}
}
/**
* 可视化等待图
*/
public void visualizeGraph() {
System.out.println("\n=== Wait-For Graph ===");
graph.forEach((waiter, holders) -> {
holders.forEach(holder -> {
System.out.printf(" %s -> %s%n", waiter, holder);
});
});
System.out.println("=====================\n");
}
}
/**
* 超时检测算法
*/
public static class TimeoutDetector {
private final Map<String, Long> transactionStartTimes = new ConcurrentHashMap<>();
private final long timeoutThreshold; // 毫秒
public TimeoutDetector(long timeoutThreshold) {
this.timeoutThreshold = timeoutThreshold;
}
public void startTransaction(String txId) {
transactionStartTimes.put(txId, System.currentTimeMillis());
}
public void endTransaction(String txId) {
transactionStartTimes.remove(txId);
}
public void checkTimeouts() {
long currentTime = System.currentTimeMillis();
transactionStartTimes.entrySet().removeIf(entry -> {
long duration = currentTime - entry.getValue();
if (duration > timeoutThreshold) {
System.out.printf("Transaction %s timed out after %dms%n",
entry.getKey(), duration);
rollbackTransaction(entry.getKey());
return true;
}
return false;
});
}
private void rollbackTransaction(String txId) {
System.out.println("Rolling back timed out transaction: " + txId);
}
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
二、数据库自动死锁检测实现
1. MySQL 死锁检测与处理
sql
复制
下载
-- MySQL 死锁相关配置和监控
SHOW VARIABLES LIKE '%deadlock%';
-- innodb_deadlock_detect: ON(默认开启死锁检测)
-- innodb_lock_wait_timeout: 50(默认50秒)
-- 查看死锁日志
SHOW ENGINE INNODB STATUS\G
-- 在输出中查找 "LATEST DETECTED DEADLOCK" 部分
-- 死锁信息表(MySQL 8.0+)
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;
-- 死锁检测和处理的存储过程
DELIMITER $$
CREATE PROCEDURE monitor_and_handle_deadlocks()
BEGIN
DECLARE deadlock_count INT DEFAULT 0;
DECLARE victim_transaction VARCHAR(100);
DECLARE done INT DEFAULT FALSE;
-- 创建临时表存储死锁信息
CREATE TEMPORARY TABLE IF NOT EXISTS temp_deadlocks (
deadlock_id INT AUTO_INCREMENT PRIMARY KEY,
transaction_id VARCHAR(100),
waiting_query TEXT,
blocking_query TEXT,
detected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 模拟死锁检测(实际中会解析 SHOW ENGINE INNODB STATUS)
-- 这里简化为检查锁等待超时
SELECT COUNT(*) INTO deadlock_count
FROM information_schema.INNODB_TRX trx1
JOIN information_schema.INNODB_LOCKS lock1 ON trx1.trx_id = lock1.lock_trx_id
JOIN information_schema.INNODB_LOCKS lock2 ON lock1.lock_table = lock2.lock_table
AND lock1.lock_index = lock2.lock_index
AND lock1.lock_trx_id != lock2.lock_trx_id
WHERE TIMESTAMPDIFF(SECOND, trx1.trx_started, NOW()) > 30; -- 30秒超时
IF deadlock_count > 0 THEN
-- 记录死锁信息
INSERT INTO temp_deadlocks (transaction_id, waiting_query, blocking_query)
SELECT trx1.trx_id, trx1.trx_query, trx2.trx_query
FROM information_schema.INNODB_TRX trx1
JOIN information_schema.INNODB_LOCKS lock1 ON trx1.trx_id = lock1.lock_trx_id
JOIN information_schema.INNODB_LOCKS lock2 ON lock1.lock_table = lock2.lock_table
JOIN information_schema.INNODB_TRX trx2 ON lock2.lock_trx_id = trx2.trx_id
WHERE TIMESTAMPDIFF(SECOND, trx1.trx_started, NOW()) > 30
LIMIT 1;
-- 选择牺牲者(选择开始时间最晚的)
SELECT transaction_id INTO victim_transaction
FROM temp_deadlocks
ORDER BY detected_at DESC
LIMIT 1;
-- 这里实际需要调用 KILL 命令
-- SET @kill_stmt = CONCAT('KILL ', victim_transaction);
-- PREPARE kill_cmd FROM @kill_stmt;
-- EXECUTE kill_cmd;
-- 记录到死锁日志表
INSERT INTO deadlock_logs (victim_transaction, deadlock_info, resolved_at)
VALUES (victim_transaction,
CONCAT('Deadlock resolved automatically at ', NOW()),
NOW());
SELECT CONCAT('Deadlock resolved, victim: ', victim_transaction) AS result;
ELSE
SELECT 'No deadlock detected' AS result;
END IF;
DROP TEMPORARY TABLE IF EXISTS temp_deadlocks;
END$$
DELIMITER ;
-- 创建死锁日志表
CREATE TABLE IF NOT EXISTS deadlock_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
victim_transaction VARCHAR(100),
deadlock_info TEXT,
resolved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_resolved_at (resolved_at)
);
-- 创建事件定期运行死锁检测
CREATE EVENT IF NOT EXISTS auto_deadlock_detector
ON SCHEDULE EVERY 10 SECOND
DO
CALL monitor_and_handle_deadlocks();
-- 查看当前锁等待情况
SELECT
r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query,
TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_time_seconds
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id;
2. PostgreSQL 死锁处理
sql
复制
下载
-- PostgreSQL 死锁检测配置
SHOW deadlock_timeout; -- 默认 1s
-- PostgreSQL 每 deadlock_timeout 毫秒检查一次死锁
-- 查看当前锁信息
SELECT
locktype,
database,
relation::regclass,
page,
tuple,
virtualxid,
transactionid,
classid,
objid,
objsubid,
virtualtransaction,
pid,
mode,
granted
FROM pg_locks
WHERE NOT granted;
-- 死锁检测查询
SELECT
w1.pid AS waiting_pid,
w1.usename AS waiting_user,
w1.query AS waiting_query,
w2.pid AS blocking_pid,
w2.usename AS blocking_user,
w2.query AS blocking_query,
w1.wait_event_type,
w1.wait_event,
age(now(), w1.query_start) AS waiting_duration
FROM pg_stat_activity w1
JOIN pg_locks l1 ON w1.pid = l1.pid AND NOT l1.granted
JOIN pg_locks l2 ON l1.relation = l2.relation AND l1.locktype = l2.locktype
JOIN pg_stat_activity w2 ON w2.pid = l2.pid AND l2.granted
WHERE w1.wait_event_type = 'Lock';
-- 自动死锁处理函数
CREATE OR REPLACE FUNCTION handle_deadlocks()
RETURNS void AS $$
DECLARE
deadlock_record RECORD;
victim_pid INT;
BEGIN
-- 查找可能的死锁(长时间等待)
FOR deadlock_record IN
SELECT
waiting.pid AS waiting_pid,
blocking.pid AS blocking_pid,
age(now(), waiting.query_start) AS wait_time,
waiting.query AS waiting_query,
blocking.query AS blocking_query
FROM pg_stat_activity waiting
JOIN pg_locks wl ON waiting.pid = wl.pid AND NOT wl.granted
JOIN pg_locks bl ON wl.relation = bl.relation
AND wl.locktype = bl.locktype
AND wl.pid != bl.pid
JOIN pg_stat_activity blocking ON blocking.pid = bl.pid AND bl.granted
WHERE waiting.wait_event_type = 'Lock'
AND age(now(), waiting.query_start) > INTERVAL '30 seconds'
LIMIT 1
LOOP
-- 记录死锁信息
INSERT INTO deadlock_history (
waiting_pid,
blocking_pid,
wait_time,
waiting_query,
blocking_query,
resolved_at
) VALUES (
deadlock_record.waiting_pid,
deadlock_record.blocking_pid,
deadlock_record.wait_time,
deadlock_record.waiting_query,
deadlock_record.blocking_query,
now()
);
-- 选择牺牲者(等待时间最长的)
victim_pid := deadlock_record.waiting_pid;
-- 终止进程(实际生产环境要谨慎)
PERFORM pg_terminate_backend(victim_pid);
RAISE NOTICE 'Deadlock resolved: terminated pid %', victim_pid;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- 创建死锁历史表
CREATE TABLE IF NOT EXISTS deadlock_history (
id SERIAL PRIMARY KEY,
waiting_pid INT,
blocking_pid INT,
wait_time INTERVAL,
waiting_query TEXT,
blocking_query TEXT,
resolved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 创建自动执行的函数
SELECT cron.schedule(
'deadlock-detector', -- 任务名
'* * * * *', -- 每分钟执行
$$SELECT handle_deadlocks()$$
);
3. 应用层死锁检测与处理
java
复制
下载
/**
* 应用层死锁检测管理器
*/
public class ApplicationDeadlockManager {
/**
* 分布式死锁检测器
*/
public static class DistributedDeadlockDetector {
private final Map<String, TransactionLockInfo> lockTable = new ConcurrentHashMap<>();
private final ScheduledExecutorService detectorScheduler;
private final long checkInterval;
public DistributedDeadlockDetector(long checkInterval) {
this.checkInterval = checkInterval;
this.detectorScheduler = Executors.newSingleThreadScheduledExecutor();
startDetection();
}
/**
* 事务锁信息
*/
static class TransactionLockInfo {
String transactionId;
String resourceId;
LockType lockType;
long timestamp;
String appNodeId;
Set<String> waitingFor = new HashSet<>();
enum LockType {
SHARED, EXCLUSIVE
}
}
/**
* 注册事务获取锁
*/
public void acquireLock(String txId, String resourceId,
TransactionLockInfo.LockType lockType) {
TransactionLockInfo lockInfo = new TransactionLockInfo();
lockInfo.transactionId = txId;
lockInfo.resourceId = resourceId;
lockInfo.lockType = lockType;
lockInfo.timestamp = System.currentTimeMillis();
lockInfo.appNodeId = getNodeId();
lockTable.put(txId + ":" + resourceId, lockInfo);
// 检查锁冲突
checkLockConflict(txId, resourceId, lockType);
}
/**
* 注册事务等待锁
*/
public void waitForLock(String waiterTxId, String resourceId,
String holderTxId) {
String key = waiterTxId + ":" + resourceId;
TransactionLockInfo info = lockTable.get(key);
if (info != null) {
info.waitingFor.add(holderTxId);
// 构建全局等待图
buildGlobalWaitForGraph();
}
}
/**
* 构建全局等待图(跨节点)
*/
private void buildGlobalWaitForGraph() {
// 收集所有节点的锁信息
Map<String, Set<String>> globalGraph = new HashMap<>();
// 本地锁信息
lockTable.forEach((key, info) -> {
if (!info.waitingFor.isEmpty()) {
globalGraph.put(info.transactionId, new HashSet<>(info.waitingFor));
}
});
// TODO: 从其他节点获取锁信息
// 这里简化实现,实际需要跨节点通信
// 检测死锁
detectDeadlockFromGraph(globalGraph);
}
/**
* 从图中检测死锁
*/
private void detectDeadlockFromGraph(Map<String, Set<String>> graph) {
Set<String> visited = new HashSet<>();
for (String node : graph.keySet()) {
if (!visited.contains(node)) {
Set<String> path = new HashSet<>();
if (hasCycleDFS(node, graph, visited, path)) {
// 发现死锁
resolveDistributedDeadlock(path);
return;
}
}
}
}
private boolean hasCycleDFS(String node, Map<String, Set<String>> graph,
Set<String> visited, Set<String> path) {
if (path.contains(node)) {
return true;
}
if (visited.contains(node)) {
return false;
}
visited.add(node);
path.add(node);
Set<String> neighbors = graph.get(node);
if (neighbors != null) {
for (String neighbor : neighbors) {
if (hasCycleDFS(neighbor, graph, visited, path)) {
return true;
}
}
}
path.remove(node);
return false;
}
/**
* 解决分布式死锁
*/
private void resolveDistributedDeadlock(Set<String> cycleTransactions) {
System.out.println("Distributed deadlock detected in cycle: " + cycleTransactions);
// 选择牺牲者策略
String victim = selectVictim(cycleTransactions);
// 通知相关节点回滚事务
rollbackTransaction(victim);
// 清理锁表
cleanupAfterRollback(victim);
}
private String selectVictim(Set<String> candidates) {
// 策略:选择最年轻的事务
long youngestTime = Long.MAX_VALUE;
String youngestTx = null;
for (String txId : candidates) {
// 简化实现,实际需要获取事务开始时间
if (txId.hashCode() < youngestTime) {
youngestTime = txId.hashCode();
youngestTx = txId;
}
}
return youngestTx;
}
private void rollbackTransaction(String txId) {
System.out.println("Rolling back distributed transaction: " + txId);
// 实际实现中需要通知所有参与节点
}
private void startDetection() {
detectorScheduler.scheduleAtFixedRate(() -> {
try {
checkForTimeouts();
checkForDeadlocks();
} catch (Exception e) {
System.err.println("Deadlock detection error: " + e.getMessage());
}
}, checkInterval, checkInterval, TimeUnit.MILLISECONDS);
}
private void checkForTimeouts() {
long currentTime = System.currentTimeMillis();
long timeoutThreshold = 30000; // 30秒
lockTable.entrySet().removeIf(entry -> {
TransactionLockInfo info = entry.getValue();
long age = currentTime - info.timestamp;
if (age > timeoutThreshold) {
System.out.println("Transaction timeout: " + info.transactionId);
rollbackTransaction(info.transactionId);
return true;
}
return false;
});
}
private void checkForDeadlocks() {
buildGlobalWaitForGraph();
}
private String getNodeId() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
return "unknown";
}
}
private void checkLockConflict(String txId, String resourceId,
TransactionLockInfo.LockType lockType) {
// 检查是否有其他事务持有冲突的锁
for (TransactionLockInfo existing : lockTable.values()) {
if (existing.resourceId.equals(resourceId) &&
!existing.transactionId.equals(txId)) {
boolean conflict = false;
if (lockType == TransactionLockInfo.LockType.EXCLUSIVE) {
// 排他锁与任何锁都冲突
conflict = true;
} else if (lockType == TransactionLockInfo.LockType.SHARED &&
existing.lockType == TransactionLockInfo.LockType.EXCLUSIVE) {
// 共享锁与排他锁冲突
conflict = true;
}
if (conflict) {
// 注册等待关系
waitForLock(txId, resourceId, existing.transactionId);
break;
}
}
}
}
private void cleanupAfterRollback(String txId) {
// 移除该事务的所有锁
lockTable.entrySet().removeIf(entry ->
entry.getValue().transactionId.equals(txId)
);
// 移除其他事务对该事务的等待
lockTable.values().forEach(info ->
info.waitingFor.remove(txId)
);
}
public void shutdown() {
detectorScheduler.shutdown();
try {
if (!detectorScheduler.awaitTermination(5, TimeUnit.SECONDS)) {
detectorScheduler.shutdownNow();
}
} catch (InterruptedException e) {
detectorScheduler.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
/**
* 基于数据库的死锁监控器
*/
public static class DatabaseDeadlockMonitor {
private final DataSource dataSource;
private final ScheduledExecutorService monitorScheduler;
private final DeadlockHandler deadlockHandler;
public DatabaseDeadlockMonitor(DataSource dataSource, DeadlockHandler handler) {
this.dataSource = dataSource;
this.deadlockHandler = handler;
this.monitorScheduler = Executors.newSingleThreadScheduledExecutor();
}
public interface DeadlockHandler {
void onDeadlockDetected(String victimTransaction, String deadlockInfo);
}
/**
* 开始监控
*/
public void startMonitoring(long interval, TimeUnit unit) {
monitorScheduler.scheduleAtFixedRate(() -> {
try {
checkForDeadlocks();
} catch (Exception e) {
System.err.println("Deadlock monitoring error: " + e.getMessage());
}
}, 0, interval, unit);
}
/**
* 检查死锁
*/
private void checkForDeadlocks() throws SQLException {
String databaseType = getDatabaseType();
switch (databaseType.toLowerCase()) {
case "mysql":
checkMySQLDeadlocks();
break;
case "postgresql":
checkPostgreSQLDeadlocks();
break;
case "oracle":
checkOracleDeadlocks();
break;
default:
checkGenericDeadlocks();
}
}
/**
* MySQL 死锁检查
*/
private void checkMySQLDeadlocks() throws SQLException {
// 检查锁等待超时
String sql = """
SELECT
r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_query,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query,
TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_seconds
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id
WHERE TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) > 30
""";
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
String waitingTx = rs.getString("waiting_trx_id");
String blockingTx = rs.getString("blocking_trx_id");
int waitSeconds = rs.getInt("wait_seconds");
if (waitSeconds > 60) { // 超过60秒,认为是死锁
String deadlockInfo = String.format(
"Long lock wait detected: %s waiting for %s for %d seconds",
waitingTx, blockingTx, waitSeconds
);
deadlockHandler.onDeadlockDetected(waitingTx, deadlockInfo);
}
}
}
}
/**
* 获取数据库类型
*/
private String getDatabaseType() throws SQLException {
try (Connection conn = dataSource.getConnection()) {
return conn.getMetaData().getDatabaseProductName();
}
}
/**
* 通用的死锁检查
*/
private void checkGenericDeadlocks() throws SQLException {
// 通过查询长时间运行的事务来检测可能的死锁
String sql = """
SELECT
tx_id,
start_time,
current_timestamp - start_time AS duration,
query_text
FROM sys.transactions
WHERE state = 'ACTIVE'
AND current_timestamp - start_time > INTERVAL '30 seconds'
ORDER BY duration DESC
""";
// 注意:这是一个通用模板,实际SQL需要根据具体数据库调整
System.out.println("Generic deadlock check would run here");
}
/**
* 杀死死锁事务
*/
public void killDeadlockedTransaction(String transactionId) throws SQLException {
String dbType = getDatabaseType();
String killSql;
switch (dbType.toLowerCase()) {
case "mysql":
killSql = "KILL " + transactionId;
break;
case "postgresql":
killSql = "SELECT pg_terminate_backend(" + transactionId + ")";
break;
default:
throw new UnsupportedOperationException(
"Kill operation not supported for " + dbType
);
}
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute(killSql);
System.out.println("Killed transaction: " + transactionId);
}
}
public void shutdown() {
monitorScheduler.shutdown();
}
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
三、自动回滚机制实现
1. 智能回滚策略
java
复制
下载
/**
* 智能回滚管理器
*/
public class SmartRollbackManager {
/**
* 回滚策略枚举
*/
public enum RollbackStrategy {
ROLLBACK_FULL, // 完全回滚
ROLLBACK_PARTIAL, // 部分回滚到保存点
ROLLBACK_AND_RETRY, // 回滚后重试
COMPENSATING_ACTION, // 补偿操作
DELAYED_ROLLBACK // 延迟回滚(等待依赖事务)
}
/**
* 回滚决策器
*/
public static class RollbackDecisionEngine {
/**
* 决定最佳回滚策略
*/
public RollbackDecision decideRollbackStrategy(
TransactionContext context,
DeadlockInfo deadlockInfo) {
RollbackDecision decision = new RollbackDecision();
// 因素1: 事务执行时间
long executionTime = System.currentTimeMillis() - context.getStartTime();
if (executionTime < 1000) {
// 短事务,完全回滚代价小
decision.strategy = RollbackStrategy.ROLLBACK_FULL;
decision.priority = RollbackPriority.HIGH;
} else if (executionTime < 5000) {
// 中等事务,检查是否有保存点
if (context.hasSavepoint()) {
decision.strategy = RollbackStrategy.ROLLBACK_PARTIAL;
decision.savepointName = context.getLastSavepoint();
} else {
decision.strategy = RollbackStrategy.ROLLBACK_FULL;
}
decision.priority = RollbackPriority.MEDIUM;
} else {
// 长事务,尝试补偿操作
decision.strategy = RollbackStrategy.COMPENSATING_ACTION;
decision.priority = RollbackPriority.LOW;
}
// 因素2: 事务类型
if (context.getTransactionType() == TransactionType.READ_ONLY) {
decision.strategy = RollbackStrategy.ROLLBACK_FULL;
decision.priority = RollbackPriority.HIGH;
} else if (context.getTransactionType() == TransactionType.CRITICAL) {
// 关键事务,尝试重试
decision.strategy = RollbackStrategy.ROLLBACK_AND_RETRY;
decision.retryCount = 3;
decision.retryDelay = 100;
decision.priority = RollbackPriority.CRITICAL;
}
// 因素3: 死锁中的角色
if (deadlockInfo.isCyclic()) {
// 在循环死锁中,选择代价最小的事务
if (calculateTransactionCost(context) <
calculateAverageCost(deadlockInfo)) {
decision.strategy = RollbackStrategy.ROLLBACK_FULL;
decision.priority = RollbackPriority.HIGH;
}
}
return decision;
}
private long calculateTransactionCost(TransactionContext context) {
// 计算事务回滚代价
long cost = 0;
// 已修改的行数
cost += context.getModifiedRows() * 10;
// 执行时间
cost += (System.currentTimeMillis() - context.getStartTime()) / 100;
// 事务重要性权重
cost *= context.getPriority().getWeight();
return cost;
}
private long calculateAverageCost(DeadlockInfo deadlockInfo) {
// 计算平均代价
return deadlockInfo.getInvolvedTransactions().stream()
.mapToLong(this::calculateTransactionCost)
.average()
.orElse(0);
}
}
/**
* 回滚执行器
*/
public static class RollbackExecutor {
private final DataSource dataSource;
private final Map<String, CompensatingAction> compensatingActions;
public RollbackExecutor(DataSource dataSource) {
this.dataSource = dataSource;
this.compensatingActions = new HashMap<>();
registerDefaultActions();
}
/**
* 执行回滚
*/
public boolean executeRollback(String transactionId,
RollbackDecision decision) throws SQLException {
System.out.printf("Executing rollback for %s with strategy: %s%n",
transactionId, decision.strategy);
switch (decision.strategy) {
case ROLLBACK_FULL:
return executeFullRollback(transactionId);
case ROLLBACK_PARTIAL:
return executePartialRollback(transactionId, decision.savepointName);
case ROLLBACK_AND_RETRY:
return executeRollbackAndRetry(transactionId, decision);
case COMPENSATING_ACTION:
return executeCompensatingAction(transactionId, decision);
case DELAYED_ROLLBACK:
return executeDelayedRollback(transactionId, decision);
default:
return executeFullRollback(transactionId);
}
}
/**
* 完全回滚
*/
private boolean executeFullRollback(String transactionId) throws SQLException {
// 对于MySQL,需要获取连接并执行ROLLBACK
// 这里简化实现
try (Connection conn = dataSource.getConnection()) {
// 如果知道具体的连接,可以针对该连接执行ROLLBACK
// 否则需要其他机制
return true;
}
}
/**
* 部分回滚到保存点
*/
private boolean executePartialRollback(String transactionId, String savepoint)
throws SQLException {
String sql = "ROLLBACK TO SAVEPOINT " + savepoint;
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
return stmt.execute(sql);
}
}
/**
* 回滚并重试
*/
private boolean executeRollbackAndRetry(String transactionId,
RollbackDecision decision) {
int retryCount = 0;
boolean success = false;
while (retryCount < decision.retryCount && !success) {
try {
// 回滚
executeFullRollback(transactionId);
// 等待重试延迟
if (decision.retryDelay > 0) {
Thread.sleep(decision.retryDelay);
}
// 重新执行事务逻辑
success = retryTransaction(transactionId);
} catch (Exception e) {
System.err.println("Retry failed: " + e.getMessage());
retryCount++;
// 指数退避
decision.retryDelay *= 2;
}
}
return success;
}
/**
* 补偿操作
*/
private boolean executeCompensatingAction(String transactionId,
RollbackDecision decision) {
// 查找注册的补偿操作
CompensatingAction action = compensatingActions.get(transactionId);
if (action != null) {
try {
return action.compensate();
} catch (Exception e) {
System.err.println("Compensating action failed: " + e.getMessage());
// 回退到完全回滚
try {
return executeFullRollback(transactionId);
} catch (SQLException ex) {
return false;
}
}
}
return false;
}
/**
* 延迟回滚
*/
private boolean executeDelayedRollback(String transactionId,
RollbackDecision decision) {
// 创建延迟任务
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(() -> {
try {
executeFullRollback(transactionId);
} catch (SQLException e) {
System.err.println("Delayed rollback failed: " + e.getMessage());
}
}, decision.delaySeconds, TimeUnit.SECONDS);
return true;
}
/**
* 重试事务
*/
private boolean retryTransaction(String transactionId) {
// 这里应该调用原始的业务逻辑
System.out.println("Retrying transaction: " + transactionId);
return true;
}
/**
* 注册补偿操作
*/
public void registerCompensatingAction(String transactionType,
CompensatingAction action) {
compensatingActions.put(transactionType, action);
}
private void registerDefaultActions() {
// 注册默认的补偿操作
compensatingActions.put("ORDER_CREATE", new OrderCreateCompensator());
compensatingActions.put("PAYMENT_PROCESS", new PaymentProcessCompensator());
}
/**
* 补偿操作接口
*/
public interface CompensatingAction {
boolean compensate() throws Exception;
}
/**
* 订单创建补偿器
*/
static class OrderCreateCompensator implements CompensatingAction {
@Override
public boolean compensate() throws Exception {
// 如果订单创建失败,可能需要:
// 1. 释放库存预留
// 2. 退款(如果已支付)
// 3. 发送通知
System.out.println("Executing order creation compensation");
return true;
}
}
/**
* 支付处理补偿器
*/
static class PaymentProcessCompensator implements CompensatingAction {
@Override
public boolean compensate() throws Exception {
// 如果支付处理失败,可能需要:
// 1. 撤销支付请求
// 2. 更新订单状态
// 3. 记录审计日志
System.out.println("Executing payment process compensation");
return true;
}
}
}
/**
* 回滚决策
*/
static class RollbackDecision {
RollbackStrategy strategy;
RollbackPriority priority;
String savepointName;
int retryCount;
long retryDelay;
int delaySeconds;
}
enum RollbackPriority {
LOW(1), MEDIUM(3), HIGH(5), CRITICAL(10);
private final int weight;
RollbackPriority(int weight) {
this.weight = weight;
}
public int getWeight() {
return weight;
}
}
/**
* 事务上下文
*/
static class TransactionContext {
private String transactionId;
private long startTime;
private TransactionType transactionType;
private int modifiedRows;
private RollbackPriority priority;
private List<String> savepoints = new ArrayList<>();
// getters and setters
public boolean hasSavepoint() {
return !savepoints.isEmpty();
}
public String getLastSavepoint() {
return savepoints.isEmpty() ? null : savepoints.get(savepoints.size() - 1);
}
}
enum TransactionType {
READ_ONLY, READ_WRITE, CRITICAL, BATCH
}
/**
* 死锁信息
*/
static class DeadlockInfo {
private boolean cyclic;
private List<TransactionContext> involvedTransactions = new ArrayList<>();
// getters and setters
}
}
2. 基于保存点的细粒度回滚
java
复制
下载
/**
* 保存点管理器
*/
public class SavepointManager {
private final Map<String, List<Savepoint>> transactionSavepoints = new ConcurrentHashMap<>();
private final DataSource dataSource;
public SavepointManager(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* 创建保存点
*/
public String createSavepoint(String transactionId, String name) throws SQLException {
Savepoint savepoint = new Savepoint();
savepoint.name = name;
savepoint.createdAt = System.currentTimeMillis();
savepoint.sqlState = captureSqlState(transactionId);
transactionSavepoints
.computeIfAbsent(transactionId, k -> new ArrayList<>())
.add(savepoint);
// 在数据库中创建保存点
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute("SAVEPOINT " + name);
}
return name;
}
/**
* 回滚到指定保存点
*/
public boolean rollbackToSavepoint(String transactionId, String savepointName)
throws SQLException {
List<Savepoint> savepoints = transactionSavepoints.get(transactionId);
if (savepoints == null) {
return false;
}
// 找到保存点
Savepoint target = null;
for (Savepoint sp : savepoints) {
if (sp.name.equals(savepointName)) {
target = sp;
break;
}
}
if (target == null) {
return false;
}
// 执行数据库回滚
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute("ROLLBACK TO SAVEPOINT " + savepointName);
}
// 清理后续的保存点
int index = savepoints.indexOf(target);
if (index >= 0) {
savepoints.subList(index + 1, savepoints.size()).clear();
}
return true;
}
/**
* 捕获SQL状态
*/
private String captureSqlState(String transactionId) {
// 捕获当前事务的SQL执行状态
// 可以包括:已执行的SQL语句、修改的行、锁状态等
return "SQL_STATE_" + transactionId + "_" + System.currentTimeMillis();
}
/**
* 保存点信息
*/
static class Savepoint {
String name;
long createdAt;
String sqlState;
Map<String, Object> metadata = new HashMap<>();
}
/**
* 自动保存点策略
*/
public static class AutoSavepointStrategy {
private final SavepointManager savepointManager;
private final int operationsBetweenSavepoints;
private final long timeBetweenSavepoints; // 毫秒
public AutoSavepointStrategy(SavepointManager manager,
int opsBetween, long timeBetween) {
this.savepointManager = manager;
this.operationsBetweenSavepoints = opsBetween;
this.timeBetweenSavepoints = timeBetween;
}
/**
* 监控事务并自动创建保存点
*/
public void monitorTransaction(String transactionId) {
Thread monitorThread = new Thread(() -> {
int operationCount = 0;
long lastSavepointTime = System.currentTimeMillis();
try {
while (!Thread.currentThread().isInterrupted()) {
// 检查操作计数
if (operationCount >= operationsBetweenSavepoints) {
createAutoSavepoint(transactionId, "auto_ops_" + operationCount);
operationCount = 0;
}
// 检查时间间隔
long currentTime = System.currentTimeMillis();
if (currentTime - lastSavepointTime >= timeBetweenSavepoints) {
createAutoSavepoint(transactionId, "auto_time_" + currentTime);
lastSavepointTime = currentTime;
}
// 监控事务状态
if (!isTransactionActive(transactionId)) {
break;
}
Thread.sleep(1000); // 每秒检查一次
}
} catch (Exception e) {
System.err.println("Auto-savepoint monitoring error: " + e.getMessage());
}
});
monitorThread.setDaemon(true);
monitorThread.start();
}
private void createAutoSavepoint(String transactionId, String name) {
try {
savepointManager.createSavepoint(transactionId, name);
System.out.println("Auto-created savepoint: " + name + " for " + transactionId);
} catch (SQLException e) {
System.err.println("Failed to create auto-savepoint: " + e.getMessage());
}
}
private boolean isTransactionActive(String transactionId) {
// 检查事务是否仍然活跃
// 简化实现
return true;
}
}
}
四、死锁预防与优化策略
1. 应用层死锁预防
java
复制
下载
/**
* 死锁预防策略
*/
public class DeadlockPreventionStrategies {
/**
* 锁顺序管理器(预防循环等待)
*/
public static class LockOrderManager {
private static final ThreadLocal<Set<String>> acquiredLocks =
ThreadLocal.withInitial(HashSet::new);
private static final Object globalLock = new Object();
private static final Map<String, Integer> resourceOrder = new ConcurrentHashMap<>();
private static int nextOrder = 0;
/**
* 按固定顺序获取锁
*/
public static void acquireInOrder(String... resourceIds) {
// 按资源ID排序(确保全局一致)
List<String> sortedResources = Arrays.stream(resourceIds)
.sorted(Comparator.comparing(LockOrderManager::getResourceOrder))
.collect(Collectors.toList());
// 按顺序获取锁
for (String resource : sortedResources) {
acquireLock(resource);
}
}
private static int getResourceOrder(String resourceId) {
synchronized (globalLock) {
return resourceOrder.computeIfAbsent(resourceId, k -> nextOrder++);
}
}
private static void acquireLock(String resourceId) {
// 模拟获取锁
Set<String> locks = acquiredLocks.get();
if (locks.contains(resourceId)) {
throw new IllegalStateException("Lock already acquired: " + resourceId);
}
// 检查是否违反顺序
int currentOrder = getResourceOrder(resourceId);
for (String lock : locks) {
int lockOrder = getResourceOrder(lock);
if (currentOrder < lockOrder) {
throw new IllegalStateException(
String.format("Lock order violation: %s(%d) before %s(%d)",
resourceId, currentOrder, lock, lockOrder)
);
}
}
locks.add(resourceId);
System.out.println("Acquired lock: " + resourceId);
}
/**
* 释放所有锁
*/
public static void releaseAll() {
acquiredLocks.get().clear();
acquiredLocks.remove();
}
}
/**
* 锁超时机制
*/
public static class LockWithTimeout {
private final Map<String, LockInfo> lockTable = new ConcurrentHashMap<>();
private final ScheduledExecutorService timeoutScheduler;
public LockWithTimeout() {
this.timeoutScheduler = Executors.newSingleThreadScheduledExecutor();
startTimeoutChecker();
}
/**
* 尝试获取锁(带超时)
*/
public boolean tryAcquire(String lockKey, long timeout, TimeUnit unit)
throws InterruptedException {
long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
while (System.currentTimeMillis() < deadline) {
synchronized (lockTable) {
if (!lockTable.containsKey(lockKey)) {
// 获取锁
LockInfo info = new LockInfo();
info.owner = Thread.currentThread().getName();
info.acquiredAt = System.currentTimeMillis();
info.timeout = unit.toMillis(timeout);
lockTable.put(lockKey, info);
System.out.println("Lock acquired: " + lockKey + " by " + info.owner);
return true;
}
// 检查锁是否超时
LockInfo existing = lockTable.get(lockKey);
if (System.currentTimeMillis() - existing.acquiredAt > existing.timeout) {
// 锁超时,强制释放
System.out.println("Lock timeout: " + lockKey + ", force releasing");
lockTable.remove(lockKey);
continue;
}
}
// 等待一段时间后重试
Thread.sleep(100);
}
return false;
}
/**
* 释放锁
*/
public void release(String lockKey) {
synchronized (lockTable) {
LockInfo info = lockTable.get(lockKey);
if (info != null && info.owner.equals(Thread.currentThread().getName())) {
lockTable.remove(lockKey);
System.out.println("Lock released: " + lockKey);
}
}
}
private void startTimeoutChecker() {
timeoutScheduler.scheduleAtFixedRate(() -> {
long currentTime = System.currentTimeMillis();
synchronized (lockTable) {
lockTable.entrySet().removeIf(entry -> {
LockInfo info = entry.getValue();
boolean expired = currentTime - info.acquiredAt > info.timeout;
if (expired) {
System.out.println("Timeout checker removed lock: " + entry.getKey());
}
return expired;
});
}
}, 1, 1, TimeUnit.SECONDS);
}
static class LockInfo {
String owner;
long acquiredAt;
long timeout;
}
public void shutdown() {
timeoutScheduler.shutdown();
}
}
/**
* 事务重试机制
*/
public static class TransactionRetryManager {
/**
* 带退避的重试执行
*/
public static <T> T executeWithRetry(Callable<T> task,
int maxRetries,
RetryStrategy strategy) throws Exception {
int attempt = 0;
Exception lastException = null;
while (attempt <= maxRetries) {
try {
return task.call();
} catch (SQLException e) {
lastException = e;
// 检查是否死锁相关错误
if (isDeadlockError(e)) {
System.out.println("Deadlock detected, retrying...");
// 计算退避时间
long backoff = strategy.calculateBackoff(attempt);
if (backoff > 0) {
Thread.sleep(backoff);
}
attempt++;
continue;
}
// 非死锁错误,直接抛出
throw e;
}
}
throw new Exception("Max retries exceeded", lastException);
}
private static boolean isDeadlockError(SQLException e) {
String sqlState = e.getSQLState();
int errorCode = e.getErrorCode();
// MySQL死锁错误代码
if (errorCode == 1213 || "40001".equals(sqlState)) {
return true;
}
// PostgreSQL死锁错误
if ("40P01".equals(sqlState)) {
return true;
}
// 其他数据库...
return false;
}
/**
* 重试策略
*/
public interface RetryStrategy {
long calculateBackoff(int attempt);
}
/**
* 指数退避策略
*/
public static class ExponentialBackoffStrategy implements RetryStrategy {
private final long initialDelay;
private final long maxDelay;
private final double multiplier;
public ExponentialBackoffStrategy(long initialDelay, long maxDelay, double multiplier) {
this.initialDelay = initialDelay;
this.maxDelay = maxDelay;
this.multiplier = multiplier;
}
@Override
public long calculateBackoff(int attempt) {
long delay = (long) (initialDelay * Math.pow(multiplier, attempt));
return Math.min(delay, maxDelay);
}
}
/**
* 固定延迟策略
*/
public static class FixedDelayStrategy implements RetryStrategy {
private final long delay;
public FixedDelayStrategy(long delay) {
this.delay = delay;
}
@Override
public long calculateBackoff(int attempt) {
return delay;
}
}
}
}
2. 数据库优化配置
sql
复制
下载
-- MySQL 死锁优化配置
SET GLOBAL innodb_lock_wait_timeout = 30; -- 减少锁等待超时
SET GLOBAL innodb_deadlock_detect = ON; -- 确保死锁检测开启
SET GLOBAL innodb_print_all_deadlocks = ON; -- 记录所有死锁到错误日志
-- 优化事务隔离级别(根据业务需求选择)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 减少事务持有时间
SET SESSION autocommit = 1; -- 自动提交小事务
-- 索引优化(减少锁冲突)
-- 确保查询使用索引,避免全表扫描
CREATE INDEX idx_user_id ON orders(user_id);
CREATE INDEX idx_product_id ON order_items(product_id);
-- PostgreSQL 优化配置
SET deadlock_timeout = '1s'; -- 设置合适的死锁检测间隔
SET lock_timeout = '30s'; -- 设置锁等待超时
-- 监控和调优配置
-- 开启详细日志记录
ALTER SYSTEM SET log_lock_waits = ON;
ALTER SYSTEM SET log_min_duration_statement = '1s';
-- 查询优化:使用 FOR UPDATE SKIP LOCKED 避免锁等待
SELECT * FROM orders
WHERE status = 'PENDING'
FOR UPDATE SKIP LOCKED
LIMIT 10;
-- 使用更细粒度的锁
BEGIN;
SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 行级锁,不是表锁
-- 处理业务逻辑
COMMIT;
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
五、监控与告警系统
1. 死锁监控平台
java
复制
下载
/**
* 死锁监控平台
*/
public class DeadlockMonitoringPlatform {
/**
* 监控指标收集器
*/
public static class MetricsCollector {
private final MeterRegistry meterRegistry;
private final Map<String, Counter> deadlockCounters = new ConcurrentHashMap<>();
private final Map<String, Timer> transactionTimers = new ConcurrentHashMap<>();
public MetricsCollector() {
this.meterRegistry = new SimpleMeterRegistry();
// 注册关键指标
Metrics.globalRegistry.add(meterRegistry);
}
/**
* 记录死锁事件
*/
public void recordDeadlock(String database, String transactionType) {
Counter counter = deadlockCounters.computeIfAbsent(
database + "." + transactionType,
key -> Counter.builder("database.deadlocks")
.tag("database", database)
.tag("type", transactionType)
.register(meterRegistry)
);
counter.increment();
// 触发告警
if (counter.count() > 10) { // 阈值
sendAlert("High deadlock rate detected for " + transactionType +
" in " + database);
}
}
/**
* 记录事务执行时间
*/
public Timer.Sample startTransactionTimer() {
return Timer.start(meterRegistry);
}
public void stopTransactionTimer(Timer.Sample sample, String transactionName) {
Timer timer = transactionTimers.computeIfAbsent(
transactionName,
key -> Timer.builder("database.transaction.duration")
.tag("name", transactionName)
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry)
);
sample.stop(timer);
}
/**
* 获取监控报告
*/
public MonitoringReport generateReport() {
MonitoringReport report = new MonitoringReport();
// 收集死锁统计
deadlockCounters.forEach((key, counter) -> {
report.addDeadlockStat(key, counter.count());
});
// 收集事务性能统计
transactionTimers.forEach((name, timer) -> {
timer.takeSnapshot().percentileValues().forEach(value -> {
report.addTransactionPercentile(name, value.percentile(), value.value());
});
});
return report;
}
private void sendAlert(String message) {
System.out.println("ALERT: " + message);
// 实际实现:发送到监控系统(如Prometheus Alertmanager)
}
}
/**
* 实时监控仪表板
*/
public static class RealTimeDashboard {
private final WebSocketHandler webSocketHandler;
private final MetricsCollector metricsCollector;
private final ScheduledExecutorService updateScheduler;
public RealTimeDashboard(MetricsCollector collector) {
this.metricsCollector = collector;
this.webSocketHandler = new WebSocketHandler();
this.updateScheduler = Executors.newSingleThreadScheduledExecutor();
startDashboardUpdates();
}
/**
* 启动仪表板更新
*/
private void startDashboardUpdates() {
updateScheduler.scheduleAtFixedRate(() -> {
try {
MonitoringReport report = metricsCollector.generateReport();
webSocketHandler.broadcastUpdate(report);
} catch (Exception e) {
System.err.println("Dashboard update error: " + e.getMessage());
}
}, 0, 5, TimeUnit.SECONDS); // 每5秒更新一次
}
/**
* 生成HTML仪表板
*/
public String generateDashboardHTML() {
return """
<!DOCTYPE html>
<html>
<head>
<title>Database Deadlock Monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.chart-container { background: white; padding: 20px; border-radius: 8px; }
.alert-panel { grid-column: 1 / -1; }
</style>
</head>
<body>
<div class="dashboard">
<div class="chart-container">
<h3>Deadlock Statistics</h3>
<canvas id="deadlockChart"></canvas>
</div>
<div class="chart-container">
<h3>Transaction Performance</h3>
<canvas id="transactionChart"></canvas>
</div>
<div class="alert-panel">
<h3>Recent Alerts</h3>
<div id="alertList"></div>
</div>
</div>
<script>
const ws = new WebSocket('ws://localhost:8080/deadlock-monitor');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
updateCharts(data);
};
function updateCharts(report) {
// 更新图表逻辑
}
</script>
</body>
</html>
""";
}
static class WebSocketHandler {
public void broadcastUpdate(MonitoringReport report) {
// 广播更新到所有连接的客户端
}
}
}
/**
* 监控报告
*/
static class MonitoringReport {
private Map<String, Double> deadlockStats = new HashMap<>();
private Map<String, Map<Double, Double>> transactionPercentiles = new HashMap<>();
public void addDeadlockStat(String key, double count) {
deadlockStats.put(key, count);
}
public void addTransactionPercentile(String name, double percentile, double value) {
transactionPercentiles
.computeIfAbsent(name, k -> new HashMap<>())
.put(percentile, value);
}
}
}
六、总结与最佳实践
关键原则:
-
预防优于检测:通过良好的设计避免死锁
-
快速失败:设置合理的超时时间
-
优雅降级:死锁发生时采取合适的恢复策略
-
持续监控:实时监控死锁情况并告警
最佳实践检查表:
✅ 设计阶段
-
统一锁获取顺序
-
减少事务持有时间
-
合理设置事务隔离级别
-
使用索引优化查询
✅ 开发阶段
-
实现重试机制(带退避)
-
使用保存点进行细粒度回滚
-
实现补偿事务机制
-
添加完善的日志记录
✅ 配置阶段
-
设置合适的锁等待超时
-
开启死锁检测和日志
-
配置监控和告警
-
定期优化数据库统计信息
✅ 运维阶段
-
监控死锁频率和模式
-
定期分析死锁日志
-
根据监控数据优化配置
-
建立应急预案
各数据库建议:
MySQL:
-
开启
innodb_deadlock_detect -
设置
innodb_lock_wait_timeout = 30 -
监控
SHOW ENGINE INNODB STATUS -
使用行级锁而非表级锁
PostgreSQL:
-
设置
deadlock_timeout = 1s -
使用
FOR UPDATE SKIP LOCKED -
监控
pg_locks和pg_stat_activity -
合理使用保存点
Oracle:
-
使用
DBMS_LOCK管理应用层锁 -
监控
V$LOCK和V$SESSION -
设置合适的
UNDO_RETENTION
通过综合运用检测、预防、恢复和监控策略,可以显著降低死锁对系统的影响,提高数据库的稳定性和可用性。