Files
test-repo/docs/.vitepress/theme/components/appendix/cache-design/CachePatternComparisonDemo.vue
T
sanbuphy d174ceea32 feat(docs): enhance interactive demos and improve documentation
- Add new interactive components for frontend routing, browser rendering pipeline, and database transactions
- Improve existing demos with better visuals, explanations, and examples
- Update documentation structure and content for better clarity
- Add new utility scripts and update package.json with new commands
- Fix formatting and alignment in documentation tables
2026-02-13 22:10:03 +08:00

408 lines
9.8 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
<template>
<div class="cache-pattern-comparison-demo">
<div class="demo-header">
<span class="icon">🔄</span>
<span class="title">缓存读写模式</span>
<span class="subtitle">Cache-Aside vs Read-Through vs Write-Behind</span>
</div>
<div class="intro-text">
想象你在<span class="highlight">厨房</span>做菜Cache-aside 就像自己决定什么时候从冰箱拿菜
Read-Through 像有个助手你说要什么他就帮你拿Write-Behind 像先记在购物清单上之后再去买
</div>
<div class="pattern-tabs">
<button
v-for="pattern in patterns"
:key="pattern.id"
class="tab-btn"
:class="{ active: activePattern === pattern.id }"
@click="activePattern = pattern.id"
>
<span class="tab-icon">{{ pattern.icon }}</span>
<span class="tab-name">{{ pattern.name }}</span>
</button>
</div>
<div class="pattern-content">
<div v-if="activePattern === 'cache-aside'" class="pattern-detail">
<div class="pattern-header">
<h3>Cache-Aside (旁路缓存)</h3>
<p class="pattern-desc">最常用的模式应用代码直接控制缓存</p>
</div>
<div class="flow-diagram">
<div class="flow-step read">
<div class="step-icon">📖</div>
<div class="step-content">
<strong>读取</strong>先查缓存 没有就查数据库 写入缓存
</div>
</div>
<div class="flow-step write">
<div class="step-icon"></div>
<div class="step-content">
<strong>更新</strong>先更新数据库 <span class="highlight">删除</span>缓存不是更新
</div>
</div>
</div>
<div class="pros-cons">
<div class="pros">
<div class="list-title"> 优点</div>
<div class="list-item">灵活可精细控制</div>
<div class="list-item">适合大多数场景</div>
</div>
<div class="cons">
<div class="list-title"> 缺点</div>
<div class="list-item">代码复杂度较高</div>
<div class="list-item">需要手动维护一致性</div>
</div>
</div>
</div>
<div v-if="activePattern === 'read-through'" class="pattern-detail">
<div class="pattern-header">
<h3>Read-Through (读穿透)</h3>
<p class="pattern-desc">缓存库负责从数据库加载数据</p>
</div>
<div class="flow-diagram">
<div class="flow-step">
<div class="step-icon">📖</div>
<div class="step-content">
<strong>读取</strong>应用只调 cache.get()缓存库负责查数据库
</div>
</div>
<div class="flow-step">
<div class="step-icon"></div>
<div class="step-content">
<strong>写入</strong>通常与 Write-Through 配合同步写缓存和数据库
</div>
</div>
</div>
<div class="pros-cons">
<div class="pros">
<div class="list-title"> 优点</div>
<div class="list-item">代码简洁</div>
<div class="list-item">一致性更好</div>
</div>
<div class="cons">
<div class="list-title"> 缺点</div>
<div class="list-item">需要专门的缓存库</div>
<div class="list-item">灵活性较低</div>
</div>
</div>
</div>
<div v-if="activePattern === 'write-behind'" class="pattern-detail">
<div class="pattern-header">
<h3>Write-Behind (异步写回)</h3>
<p class="pattern-desc">写入时只写缓存异步批量写数据库</p>
</div>
<div class="flow-diagram">
<div class="flow-step">
<div class="step-icon"></div>
<div class="step-content">
<strong>写入</strong>立即写缓存 异步批量写数据库
</div>
</div>
<div class="flow-step">
<div class="step-icon"></div>
<div class="step-content">
<strong>风险</strong>缓存崩溃会导致数据丢失
</div>
</div>
</div>
<div class="pros-cons">
<div class="pros">
<div class="list-title"> 优点</div>
<div class="list-item">写入极快</div>
<div class="list-item">适合写多场景</div>
</div>
<div class="cons">
<div class="list-title"> 缺点</div>
<div class="list-item">可能丢失数据</div>
<div class="list-item">一致性差</div>
</div>
</div>
</div>
</div>
<div class="comparison-table">
<div class="table-title">三种模式对比</div>
<table>
<thead>
<tr>
<th>模式</th>
<th>复杂度</th>
<th>性能</th>
<th>一致性</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr :class="{ active: activePattern === 'cache-aside' }">
<td>Cache-Aside</td>
<td></td>
<td></td>
<td></td>
<td>大多数场景</td>
</tr>
<tr :class="{ active: activePattern === 'read-through' }">
<td>Read-Through</td>
<td></td>
<td></td>
<td></td>
<td>读多写少</td>
</tr>
<tr :class="{ active: activePattern === 'write-behind' }">
<td>Write-Behind</td>
<td></td>
<td>极高</td>
<td></td>
<td>写多可丢失</td>
</tr>
</tbody>
</table>
</div>
<div class="info-box">
<span class="icon">💡</span>
<strong>选择建议</strong>90% 的场景用 Cache-Aside如果追求代码简洁用 Read-Through如果是秒杀点赞这种"能丢数据"的场景才用 Write-Behind
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const activePattern = ref('cache-aside')
const patterns = [
{ id: 'cache-aside', name: 'Cache-Aside', icon: '🔧' },
{ id: 'read-through', name: 'Read-Through', icon: '📖' },
{ id: 'write-behind', name: 'Write-Behind', icon: '⚡' }
]
</script>
<style scoped>
.cache-pattern-comparison-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon { font-size: 1.25rem; }
.demo-header .title { font-weight: bold; font-size: 1rem; }
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.85rem; margin-left: 0.5rem; }
.intro-text {
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.6;
margin-bottom: 1rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.intro-text .highlight {
color: var(--vp-c-brand-1);
font-weight: 500;
}
.pattern-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.tab-btn {
flex: 1;
min-width: 140px;
padding: 0.75rem 1rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.tab-btn:hover {
border-color: var(--vp-c-brand);
}
.tab-btn.active {
background: var(--vp-c-brand);
color: white;
border-color: var(--vp-c-brand);
}
.tab-icon {
font-size: 1.2rem;
}
.tab-name {
font-size: 0.9rem;
}
.pattern-content {
min-height: 300px;
}
.pattern-detail {
display: flex;
flex-direction: column;
gap: 1rem;
}
.pattern-header {
padding: 1rem;
background: var(--vp-c-bg);
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
}
.pattern-header h3 {
margin: 0 0 0.5rem 0;
font-size: 1.1rem;
}
.pattern-desc {
margin: 0;
color: var(--vp-c-text-2);
font-size: 0.9rem;
}
.flow-diagram {
display: flex;
flex-direction: column;
gap: 0.75rem;
padding: 1rem;
background: var(--vp-c-bg);
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
}
.flow-step {
display: flex;
gap: 0.75rem;
align-items: flex-start;
}
.step-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.step-content {
flex: 1;
font-size: 0.9rem;
line-height: 1.5;
}
.step-content .highlight {
color: var(--vp-c-brand-1);
font-weight: 600;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.pros, .cons {
padding: 1rem;
border-radius: 8px;
}
.pros {
background: #f0fdf4;
border: 1px solid #bbf7d0;
}
.cons {
background: #fef2f2;
border: 1px solid #fecaca;
}
.list-title {
font-weight: 600;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
.list-item {
font-size: 0.85rem;
margin-bottom: 0.35rem;
line-height: 1.4;
}
.comparison-table {
background: var(--vp-c-bg);
padding: 1rem;
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
margin-bottom: 1rem;
}
.table-title {
font-weight: 600;
margin-bottom: 0.75rem;
font-size: 0.95rem;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 0.5rem;
text-align: left;
border: 1px solid var(--vp-c-divider);
font-size: 0.85rem;
}
th {
background: var(--vp-c-bg-soft);
font-weight: 600;
}
tr.active {
background: #eff6ff;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
line-height: 1.4;
color: var(--vp-c-text-2);
}
.info-box .icon {
margin-right: 0.25rem;
}
</style>