Files

191 lines
9.2 KiB
HTML
Raw Permalink Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事务管理学习 - Spring Boot</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: white; padding: 30px 20px; text-align: center; margin-bottom: 20px; border-radius: 10px; }
.header h1 { font-size: 2em; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; }
.nav a:hover, .nav a.active { background: #fa709a; color: white; }
.card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.card h3 { color: #fa709a; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.acid-box { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin: 20px 0; }
.acid-item { background: #f8f9fa; padding: 20px; border-radius: 10px; text-align: center; border-top: 4px solid; }
.acid-a { border-color: #e74c3c; }
.acid-c { border-color: #3498db; }
.acid-i { border-color: #2ecc71; }
.acid-d { border-color: #9b59b6; }
.acid-item h4 { font-size: 2em; margin-bottom: 10px; }
.btn { padding: 10px 20px; background: #fa709a; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #e85a8a; }
.btn-danger { background: #e74c3c; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; margin-top: 10px; font-family: monospace; font-size: 0.9em; overflow-x: auto; max-height: 400px; overflow-y: auto; }
.propagation-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px; }
.prop-box { background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #fa709a; }
.prop-box h4 { color: #fa709a; margin-bottom: 8px; }
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
th { background: #f8f9fa; font-weight: 600; }
tr:hover { background: #f8f9fa; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔄 事务管理</h1>
<p>声明式事务 - @Transactional</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="ioc.html">📦 IoC</a>
<a href="aop.html">🔪 AOP</a>
<a href="mybatis.html">💾 MyBatis</a>
<a href="transaction.html" class="active">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="api.html">🔌 API</a>
</div>
<div class="card">
<h3>📚 ACID 特性</h3>
<div class="acid-box">
<div class="acid-item acid-a">
<h4>A</h4>
<p><strong>Atomicity</strong></p>
<p>原子性</p>
<p style="font-size:0.9em;color:#666;">事务是不可分割的工作单位</p>
</div>
<div class="acid-item acid-c">
<h4>C</h4>
<p><strong>Consistency</strong></p>
<p>一致性</p>
<p style="font-size:0.9em;color:#666;">数据库状态保持一致</p>
</div>
<div class="acid-item acid-i">
<h4>I</h4>
<p><strong>Isolation</strong></p>
<p>隔离性</p>
<p style="font-size:0.9em;color:#666;">事务之间相互隔离</p>
</div>
<div class="acid-item acid-d">
<h4>D</h4>
<p><strong>Durability</strong></p>
<p>持久性</p>
<p style="font-size:0.9em;color:#666;">提交后永久保存</p>
</div>
</div>
</div>
<div class="card">
<h3>🚀 传播行为 (Propagation)</h3>
<div class="propagation-grid">
<div class="prop-box">
<h4>REQUIRED (默认)</h4>
<p>有事务则加入,无则新建</p>
<p style="font-size:0.85em;color:#666;">最常用,适合大多数业务方法</p>
</div>
<div class="prop-box">
<h4>REQUIRES_NEW</h4>
<p>总是新建事务,挂起当前事务</p>
<p style="font-size:0.85em;color:#666;">适合日志记录、独立子任务</p>
</div>
<div class="prop-box">
<h4>SUPPORTS</h4>
<p>有事务则加入,无则以非事务运行</p>
<p style="font-size:0.85em;color:#666;">适合查询方法</p>
</div>
<div class="prop-box">
<h4>NOT_SUPPORTED</h4>
<p>以非事务运行,挂起当前事务</p>
<p style="font-size:0.85em;color:#666;">不需要事务的操作</p>
</div>
<div class="prop-box">
<h4>MANDATORY</h4>
<p>必须在事务中运行,否则抛异常</p>
<p style="font-size:0.85em;color:#666;">强制要求事务</p>
</div>
<div class="prop-box">
<h4>NEVER</h4>
<p>不能在事务中运行,否则抛异常</p>
<p style="font-size:0.85em;color:#666;">确保无事务</p>
</div>
</div>
<button class="btn" onclick="loadPropagation()">查看详细说明</button>
<div id="propResult" class="result"></div>
</div>
<div class="card">
<h3>🔒 隔离级别 (Isolation)</h3>
<table>
<tr><th>级别</th><th>脏读</th><th>不可重复读</th><th>幻读</th><th>说明</th></tr>
<tr><td>READ_UNCOMMITTED</td><td></td><td></td><td></td><td>读未提交,性能最高</td></tr>
<tr><td>READ_COMMITTED</td><td></td><td></td><td></td><td>读已提交Oracle默认</td></tr>
<tr><td>REPEATABLE_READ</td><td></td><td></td><td></td><td>可重复读MySQL默认</td></tr>
<tr><td>SERIALIZABLE</td><td></td><td></td><td></td><td>串行化,性能最低</td></tr>
</table>
<p style="margin-top:10px;color:#666;">✅ = 防止该问题 | ❌ = 可能出现该问题</p>
<button class="btn" onclick="loadIsolation()">查看详细说明</button>
<div id="isoResult" class="result"></div>
</div>
<div class="card">
<h3>🧪 事务回滚演示</h3>
<p>创建订单时触发异常,观察事务回滚效果</p>
<button class="btn" onclick="loadRollback()">查看回滚规则</button>
<div id="rollbackResult" class="result"></div>
</div>
</div>
<script>
async function loadPropagation() {
const result = document.getElementById('propResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/transaction/propagation');
const data = await res.json();
result.innerHTML = `<strong>传播行为详解</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadIsolation() {
const result = document.getElementById('isoResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/transaction/isolation');
const data = await res.json();
result.innerHTML = `<strong>隔离级别详解</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadRollback() {
const result = document.getElementById('rollbackResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/transaction/rollback');
const data = await res.json();
result.innerHTML = `<strong>回滚规则</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
</script>
</body>
</html>