81 lines
7.4 KiB
XML
Executable File
81 lines
7.4 KiB
XML
Executable File
<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="542" viewBox="0 0 680 542" role="img" aria-labelledby="diagram-title diagram-description">
|
|
<title id="diagram-title">EAGER 2차 조회는 반환 전에, LAZY highlights 조회는 매핑 접근 뒤에 실행된다</title>
|
|
<desc id="diagram-description">세 참가자를 왼쪽부터 loadFeed DTO 매핑, Hibernate, PostgreSQL 순으로 읽는다. loadFeed가 findAllBy 파생 쿼리를 호출하면 Hibernate가 PostgreSQL에서 feed_items를 먼저 조회한다. 이어 fetch join되지 않은 EAGER user와 page를 별도의 2차 SELECT로 채우고, 반환 시점까지 로딩된 FeedItem을 loadFeed에 돌려준다. 이후 DTO 매핑이 getHighlights()에 접근하면 Hibernate가 해당 아이템의 highlights 컬렉션 SELECT를 실행한다.</desc>
|
|
<metadata>{"techviz":{"spec_version":"1.1","id":"eager-lazy-query-sequence","profile":"sequence"},"source_context":{"document":"/home/donghyeon/workspace/ai-tool/topic-arrange/n+1liner/n+1liner.md","document_sha256":"1bb38964ca2a849690f5355646c1aa988111b4cd4e1055c6cb05cf7e5fc35cde","anchor":{"kind":"marker","value":"eager-lazy-query-sequence","line":324}},"evidence_policy":"Each factual element cites source lines or is marked assumption.","diagram_only":true}</metadata>
|
|
<defs>
|
|
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" />
|
|
</marker>
|
|
<style>
|
|
:root { color-scheme: light; }
|
|
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
|
.canvas { fill: #ffffff; }
|
|
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
|
|
.group-label-bg { fill: #ffffff; }
|
|
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
|
|
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
|
|
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
|
|
.edge.style-dotted { stroke-dasharray: 2 5; }
|
|
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.edge.emphasis-muted { stroke: #9ca3af; }
|
|
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
|
|
.edge-label-bg { fill: #ffffff; }
|
|
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
|
|
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
|
|
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
|
|
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
|
|
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
|
|
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
|
|
.node-shape.assumption { stroke-dasharray: 4 4; }
|
|
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
|
|
.controller-led { fill: #4b5563; }
|
|
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
|
|
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
|
|
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
|
|
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
|
|
.node-detail { font-size: 11px; fill: #374151; }
|
|
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
|
|
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
|
|
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
|
|
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
|
|
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
|
|
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
|
|
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
|
|
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
|
|
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
|
|
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
|
|
</style>
|
|
</defs>
|
|
<rect class="canvas" width="680" height="542" />
|
|
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="322-322,449-451" x="45.0" y="35.0" width="150.0" height="64.0" rx="7" />
|
|
<text class="node-label" x="120.0" y="65.0">loadFeed DTO 매핑</text>
|
|
<line class="lifeline" x1="120.0" y1="99.0" x2="120.0" y2="512.0" />
|
|
<rect class="node-shape kind-participant emphasis-primary role-participant" data-evidence="320-322" x="255.0" y="35.0" width="150.0" height="64.0" rx="7" />
|
|
<text class="node-label" x="330.0" y="65.0">Hibernate</text>
|
|
<line class="lifeline" x1="330.0" y1="99.0" x2="330.0" y2="512.0" />
|
|
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="417-422,447-447" x="465.0" y="45.7" width="150.0" height="42.7" /><ellipse class="node-shape kind-participant emphasis-normal role-participant" cx="540.0" cy="45.7" rx="75.0" ry="10.7" /><path class="storage-bottom" d="M 465.0 88.3 A 75.0 10.7 0 0 0 615.0 88.3" />
|
|
<text class="node-label" x="540.0" y="65.0">PostgreSQL</text>
|
|
<line class="lifeline" x1="540.0" y1="99.0" x2="540.0" y2="512.0" />
|
|
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,140.0 330.0,140.0" data-evidence="320-320" />
|
|
<rect class="edge-label-bg" x="159.1" y="114.0" width="131.9" height="22" rx="3" />
|
|
<text class="edge-label" x="225.0" y="129.0">1. findAllBy(...)</text>
|
|
<polyline class="edge kind-data style-solid emphasis-primary" points="330.0,202.0 540.0,202.0" data-evidence="320-320" />
|
|
<rect class="edge-label-bg" x="359.0" y="176.0" width="152.0" height="22" rx="3" />
|
|
<text class="edge-label" x="435.0" y="191.0">2. SELECT feed_items</text>
|
|
<polyline class="edge kind-data style-solid emphasis-normal" points="330.0,264.0 540.0,264.0" data-evidence="318-321" />
|
|
<rect class="edge-label-bg" x="318.8" y="238.0" width="232.4" height="22" rx="3" />
|
|
<text class="edge-label" x="435.0" y="253.0">3. SELECT user / page · EAGER 2차</text>
|
|
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="330.0,326.0 120.0,326.0" data-evidence="318-320" />
|
|
<rect class="edge-label-bg" x="122.2" y="300.0" width="205.6" height="22" rx="3" />
|
|
<text class="edge-label" x="225.0" y="315.0">4. EAGER 연관이 채워진 FeedItem 반환</text>
|
|
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,388.0 330.0,388.0" data-evidence="322-322,449-451" />
|
|
<rect class="edge-label-bg" x="128.9" y="362.0" width="192.2" height="22" rx="3" />
|
|
<text class="edge-label" x="225.0" y="377.0">5. 매핑 중 getHighlights() 접근</text>
|
|
<polyline class="edge kind-data style-solid emphasis-primary" points="330.0,450.0 540.0,450.0" data-evidence="322-322,429-430" />
|
|
<rect class="edge-label-bg" x="281.9" y="424.0" width="306.1" height="22" rx="3" />
|
|
<text class="edge-label" x="435.0" y="439.0">6. SELECT highlights WHERE feed_item_id = ?</text>
|
|
</svg>
|