Files
likingcode c04235c655 feat: Spring Boot 学习脚手架 v2.0
- 新增 IoC 容器学习模块
- 新增 AOP 切面编程学习模块
- 新增 MyBatis 集成学习模块
- 新增事务管理学习模块
- 新增用户/产品/订单 CRUD
- 新增 7 个交互式学习页面
- 集成性能监控切面
2026-03-07 08:37:40 +00:00

176 lines
9.4 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MyBatis 学习 - 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, #4facfe 0%, #00f2fe 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: #4facfe; 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: #4facfe; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.compare-box { padding: 20px; border-radius: 10px; }
.mybatis-box { background: #e3f2fd; border: 2px solid #4facfe; }
.jpa-box { background: #f3e5f5; border: 2px solid #9c27b0; }
.btn { padding: 10px 20px; background: #4facfe; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #3d9be8; }
.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; }
.code-block { background: #f4f4f4; padding: 15px; border-radius: 5px; font-family: monospace; font-size: 0.9em; overflow-x: auto; margin: 10px 0; }
.cache-box { background: #fff3e0; border-left: 4px solid #ff9800; padding: 15px; margin: 10px 0; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>💾 MyBatis 学习</h1>
<p>半自动 ORM 框架 - SQL 与 Java 对象的映射</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" class="active">💾 MyBatis</a>
<a href="transaction.html">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="api.html">🔌 API</a>
</div>
<div class="card">
<h3>📊 MyBatis vs JPA 对比</h3>
<div class="comparison">
<div class="compare-box mybatis-box">
<h4>MyBatis</h4>
<p><strong>优点:</strong></p>
<ul>
<li>✅ SQL 灵活可控</li>
<li>✅ 性能优化方便</li>
<li>✅ 复杂查询友好</li>
<li>✅ 易于 DBA 协作</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>❌ SQL 与代码耦合</li>
<li>❌ 数据库迁移成本高</li>
<li>❌ 需要手写 SQL</li>
</ul>
<p><strong>适用:</strong>复杂查询、性能要求高</p>
</div>
<div class="compare-box jpa-box">
<h4>JPA/Hibernate</h4>
<p><strong>优点:</strong></p>
<ul>
<li>✅ 面向对象</li>
<li>✅ 数据库无关</li>
<li>✅ 开发效率高</li>
<li>✅ 自动维护</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>❌ 复杂查询困难</li>
<li>❌ 性能调优复杂</li>
<li>❌ 学习曲线陡</li>
</ul>
<p><strong>适用:</strong>标准 CRUD、快速开发</p>
</div>
</div>
</div>
<div class="card">
<h3>🚀 快速体验</h3>
<button class="btn" onclick="loadConfig()">查看 MyBatis 配置</button>
<button class="btn" onclick="loadConcepts()">核心概念</button>
<button class="btn" onclick="loadVsJpa()">详细对比</button>
<div id="result" class="result"></div>
</div>
<div class="card">
<h3>💡 缓存机制</h3>
<div class="cache-box">
<h4>一级缓存 (SqlSession 级别)</h4>
<p>默认开启,同一 SqlSession 内相同查询只执行一次 SQL</p>
<div class="code-block">// 第一次查询 - 执行 SQL<br>User u1 = mapper.findById(1L);<br>// 第二次查询 - 命中缓存,不执行 SQL<br>User u2 = mapper.findById(1L);</div>
</div>
<div class="cache-box">
<h4>二级缓存 (Mapper 级别)</h4>
<p>需配置 @CacheNamespace多个 SqlSession 共享</p>
<div class="code-block">@Mapper<br>@CacheNamespace<br>public interface UserMapper { ... }</div>
</div>
<p>💡 <strong>验证方式:</strong>查看控制台 SQL 日志,缓存命中时不打印 SQL</p>
</div>
<div class="card">
<h3>📝 常用注解</h3>
<table style="width:100%;border-collapse:collapse;">
<tr style="background:#f8f9fa;"><th style="padding:10px;text-align:left;">注解</th><th style="padding:10px;text-align:left;">用途</th></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Mapper</td><td style="padding:10px;border-bottom:1px solid #eee;">标记为 MyBatis Mapper 接口</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Select</td><td style="padding:10px;border-bottom:1px solid #eee;">查询 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Insert</td><td style="padding:10px;border-bottom:1px solid #eee;">插入 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Update</td><td style="padding:10px;border-bottom:1px solid #eee;">更新 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Delete</td><td style="padding:10px;border-bottom:1px solid #eee;">删除 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Param</td><td style="padding:10px;border-bottom:1px solid #eee;">参数命名</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Options</td><td style="padding:10px;border-bottom:1px solid #eee;">额外选项如返回自增ID</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@CacheNamespace</td><td style="padding:10px;border-bottom:1px solid #eee;">启用二级缓存</td></tr>
</table>
</div>
<div class="card">
<h3>🔧 动态 SQL 示例</h3>
<div class="code-block">&lt;select id="findUsers"&gt;<br> SELECT * FROM users<br> &lt;where&gt;<br> &lt;if test="name != null"&gt;<br> AND name LIKE CONCAT('%', #{name}, '%')<br> &lt;/if&gt;<br> &lt;if test="email != null"&gt;<br> AND email = #{email}<br> &lt;/if&gt;<br> &lt;/where&gt;<br>&lt;/select&gt;</div>
</div>
</div>
<script>
async function loadConfig() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/config');
const data = await res.json();
result.innerHTML = `<strong>MyBatis 配置</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadConcepts() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/concepts');
const data = await res.json();
result.innerHTML = `<strong>核心概念</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadVsJpa() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/vs-jpa');
const data = await res.json();
result.innerHTML = `<strong>MyBatis vs JPA</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
</script>
</body>
</html>