<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yeseo_52.log</title>
        <link>https://velog.io/</link>
        <description>미림마이스터고 재학중인 고3 개발자 정예서입니다.</description>
        <lastBuildDate>Fri, 11 Sep 2026 06:51:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yeseo_52.log</title>
            <url>https://velog.velcdn.com/images/yeseo_052/profile/b5a1ab9a-fda0-4eb2-8716-e678f79c3c27/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yeseo_52.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yeseo_052" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[MSSQL T-SQL 정리 (프로시저 ~ IF EXISTS)]]></title>
            <link>https://velog.io/@yeseo_052/MSSQL-T-SQL-%EC%A0%95%EB%A6%AC-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-IF-EXISTS</link>
            <guid>https://velog.io/@yeseo_052/MSSQL-T-SQL-%EC%A0%95%EB%A6%AC-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-IF-EXISTS</guid>
            <pubDate>Fri, 11 Sep 2026 06:51:55 GMT</pubDate>
            <description><![CDATA[<h2 id="프로시저-stored-procedure">프로시저 (Stored Procedure)</h2>
<p>여러 쿼리를 하나로 묶어서 DB에 저장해두고, 이름으로 불러 실행하는 기능.</p>
<pre><code class="language-sql">CREATE PROCEDURE USER_INSERT
    @USERNAME NVARCHAR(40),
    @PHONENUMBER NVARCHAR(40),
    @ADDRESSINFO NVARCHAR(2000)
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO TBL_USER (USERNO, USERNAME, PHONENUMBER, ADDRESSINFO)
    VALUES (NEXT VALUE FOR USERSEQ, @USERNAME, @PHONENUMBER, @ADDRESSINFO);
END;

-- 실행
EXEC USER_INSERT N&#39;홍길동&#39;, N&#39;0101234567&#39;, N&#39;서울시 AAA아파트&#39;;</code></pre>
<ul>
<li><code>CREATE PROCEDURE</code> : 로직을 DB에 등록 (한 번만)</li>
<li><code>EXEC</code> : 등록된 로직을 실행 (여러 번 가능)</li>
<li><code>OUTPUT</code> 파라미터를 붙이면 프로시저 내부에서 계산한 값을 호출한 쪽으로 반환 가능</li>
</ul>
<pre><code class="language-sql">CREATE PROCEDURE USER_SELECT
    @USERNAME NVARCHAR(40),
    @USERCOUNT INT OUTPUT
AS
BEGIN
    SELECT @USERCOUNT = COUNT(*) FROM TBL_USER;
END;

DECLARE @total int;
EXEC USER_SELECT N&#39;홍길동&#39;, @total OUTPUT;
SELECT @total;</code></pre>
<p>VIEW와 다른 점: VIEW는 SELECT 결과를 저장한 &quot;가상 테이블&quot; (조회 전용, 파라미터 불가), 프로시저는 파라미터를 받아 INSERT/UPDATE/DELETE까지 자유롭게 실행하는 로직 단위.</p>
<h2 id="변수선언">변수선언</h2>
<pre><code class="language-sql">DECLARE @변수명 데이터타입;
SET @변수명 = 값;
SELECT @변수명 = 컬럼 FROM 테이블;</code></pre>
<p>프로시저 안에서 값을 계산해두고 여러 번 재사용할 때 사용.</p>
<pre><code class="language-sql">CREATE PROCEDURE RESULTDAY_INSERT (@INFO NVARCHAR(200))
AS
BEGIN
    DECLARE @NEXT_RESULTNO INT, @PRICESUM INT;

    SELECT @NEXT_RESULTNO = ISNULL(MAX(RESULTNO)+1, 0) FROM TBL_RESULTDAY;
    SELECT @PRICESUM = SUM(PRICE) FROM TBL_ORDER;

    INSERT INTO TBL_RESULTDAY (RESULTNO, PRICESUM, RESULTDAY)
    VALUES (@NEXT_RESULTNO, @PRICESUM, GETDATE());
END;</code></pre>
<h2 id="예외처리-try-catch--트랜잭션">예외처리 (TRY-CATCH) + 트랜잭션</h2>
<p>문제: 쿼리 여러 개 실행 중 하나가 실패하면 앞부분만 반영되고 뒷부분은 빠지는 반쪽 저장 상태 발생.</p>
<p>해결: TRY-CATCH + TRANSACTION으로 감싸서 전부 성공 아니면 전부 취소.</p>
<pre><code class="language-sql">BEGIN TRY
    BEGIN TRANSACTION;

    INSERT INTO ...;
    INSERT INTO ...;

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    SELECT ERROR_MESSAGE() AS ErrorMessage;
END CATCH;</code></pre>
<ul>
<li><code>BEGIN TRY</code> 안에서 에러가 나면 즉시 <code>CATCH</code>로 이동</li>
<li><code>COMMIT</code> : 전부 성공 시 확정 반영</li>
<li><code>ROLLBACK</code> : 하나라도 실패 시 지금까지 실행된 것까지 전부 취소</li>
<li>여러 쿼리가 하나의 작업 단위일 때만 트랜잭션 필요, 단일 쿼리면 생략 가능</li>
</ul>
<h2 id="반복문-while">반복문 (WHILE)</h2>
<pre><code class="language-sql">DECLARE @i int;
SET @i = 0;

WHILE (@i &lt; 5)
BEGIN
    INSERT INTO TBL_USER (USERNO, USERNAME, PHONENUMBER, ADDRESSINFO)
    VALUES (@i, N&#39;AAA&#39;, N&#39;0100000000&#39;, N&#39;서울시 AAA아파트&#39;);

    SET @i = @i + 1;
END</code></pre>
<p>카운터 변수를 반복문 안에서 증가시키지 않으면 무한루프 발생.</p>
<h2 id="조건문-if-case">조건문 (IF, CASE)</h2>
<p>IF문: 실행할 쿼리 자체를 조건에 따라 선택.</p>
<pre><code class="language-sql">IF @MODE = 1
BEGIN
    SELECT * FROM TBL_ORDER;
END
ELSE IF (@MODE &gt; 1 AND @MODE &lt;= 3)
BEGIN
    UPDATE TBL_ORDER SET PRICE = PRICE + 300 WHERE USERNO = 2;
END
ELSE
BEGIN
    DELETE FROM TBL_ORDER WHERE PRICE = 1500;
END</code></pre>
<p>CASE문: SELECT 결과의 컬럼 값을 조건에 따라 다르게 표현.</p>
<pre><code class="language-sql">SELECT USERNO, PRODUCTNAME,
    CASE WHEN PRICE &gt; 5000 THEN N&#39;VVIP고객&#39;
         WHEN PRICE &gt; 2000 THEN N&#39;VIP손님&#39;
         WHEN PRICE &gt; 1000 THEN N&#39;A손님&#39;
         ELSE N&#39;일반손님&#39;
    END AS GRADE
FROM TBL_ORDER;</code></pre>
<h2 id="사용자-정의-함수">사용자 정의 함수</h2>
<p>프로시저와 달리 값 하나를 계산해서 반환하고, SELECT문 안에서 바로 사용 가능.</p>
<pre><code class="language-sql">CREATE FUNCTION textcall (@userno int)
RETURNS int
AS
BEGIN
    DECLARE @result int;
    SELECT @result = SUM(price) FROM TBL_ORDER WHERE USERNO = @userno;
    RETURN @result;
END

-- 사용
SELECT dbo.textcall(1);</code></pre>
<table>
<thead>
<tr>
<th></th>
<th>PROCEDURE</th>
<th>FUNCTION</th>
</tr>
</thead>
<tbody><tr>
<td>실행</td>
<td>EXEC</td>
<td>SELECT dbo.함수명()</td>
</tr>
<tr>
<td>반환</td>
<td>OUTPUT으로 여러 개 가능</td>
<td>RETURN으로 값 하나만</td>
</tr>
<tr>
<td>용도</td>
<td>여러 작업 실행</td>
<td>값 계산</td>
</tr>
</tbody></table>
<h2 id="begin--end">BEGIN ~ END</h2>
<p>여러 줄의 코드를 하나의 블록으로 묶는 짝꿍 키워드. 다른 언어의 <code>{ }</code>와 동일한 역할. 프로시저, 함수, IF, WHILE, TRY/CATCH 어디서나 사용.</p>
<h2 id="데이터베이스-상식">데이터베이스 상식</h2>
<p>WHERE절에 PK나 UNIQUE 컬럼을 조건으로 쓰거나 먼저 작성하면 인덱스를 활용해 속도가 빨라짐.</p>
<pre><code class="language-sql">SELECT * FROM TBL_USER WHERE USERNO = 1;  -- PK 조건, 좋음</code></pre>
<h2 id="임시테이블">임시테이블</h2>
<p>테이블명 앞에 <code>#</code>을 붙이면 임시테이블. 프로시저(BEGIN~END) 안에서만 존재하고 실행이 끝나면 자동 삭제됨. 반복되는 SELECT 결과를 임시로 저장해두고 재사용하면 불필요한 재조회를 줄여 성능 개선 가능.</p>
<pre><code class="language-sql">CREATE TABLE #USERINFO
(
    UserNo int,
    Name VARCHAR(100)
)

INSERT INTO #USERINFO (UserNo, Name)
SELECT 123, &#39;김아름&#39;
UNION SELECT 125, &#39;김길동&#39;;

SELECT * FROM #USERINFO WHERE UserNo = 123;</code></pre>
<h2 id="if-exists">IF EXISTS</h2>
<p>데이터 존재 여부에 따라 UPDATE 또는 INSERT를 분기하는 패턴에서 사용. MSSQL 전용 기능.</p>
<pre><code class="language-sql">IF EXISTS (SELECT PRODUCTNO FROM PRODUCT WHERE PRODUCTNAME = @INFO)
BEGIN
    UPDATE PRODUCT SET PRODUCTNAME = @INFO + &#39;a&#39;;
END
ELSE
BEGIN
    INSERT INTO PRODUCT (PRODUCTNO, PRODUCTNAME) VALUES (5, &#39;a&#39;);
END</code></pre>
<p>변수에 담아서 IF로 비교하는 방식보다 간결하고, 있으면 수정·없으면 추가 패턴에서 실무에 자주 쓰임.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[.NET Core] Data Protection 암호화 & Claim 기반 인증/인가 정리]]></title>
            <link>https://velog.io/@yeseo_052/.NET-Core-Data-Protection-%EC%95%94%ED%98%B8%ED%99%94-Claim-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@yeseo_052/.NET-Core-Data-Protection-%EC%95%94%ED%98%B8%ED%99%94-Claim-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 08 Sep 2026 07:28:04 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="1-data-protection이란">1. Data Protection이란?</h2>
<p>.NET Core의 <strong>Data Protection</strong>은 키 관리를 통해 애플리케이션의 민감한 데이터를 보호할 수 있도록 도와주는 기능입니다. 사용자 정보를 암호화/복호화할 때, 그리고 비밀번호를 안전하게 저장할 때 이 모듈을 사용합니다.</p>
<h3 id="1-1-키-저장-구조">1-1. 키 저장 구조</h3>
<p>Data Protection을 사용하면 아래 경로에 키 파일이 저장됩니다.</p>
<pre><code>D:\DataProtector\
  └─ key-79b34994-9a62-4481-8149-19ecf7c01bce.xml</code></pre><p>GUID 형식의 xml 파일 하나에 아래 정보가 포함되어 있습니다.</p>
<ul>
<li>Key Id, Version</li>
<li>키 생성일 / 활성화일 / 만료일</li>
<li>암호화 유형, 암호 알고리즘 유형</li>
<li>암호키 길이, 해시 알고리즘 유형</li>
</ul>
<h3 id="1-2-aes-vs-sha">1-2. AES vs SHA</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>풀네임</th>
<th>방식</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>AES</strong></td>
<td>Advanced Encryption Standard</td>
<td>Two-way (암호화 ↔ 복호화)</td>
<td>보안성이 뛰어난 대칭키 암호화 방식. 256bit 권장</td>
</tr>
<tr>
<td><strong>SHA</strong></td>
<td>Secure Hash Algorithm</td>
<td>One-way (암호화만, 복호화 불가)</td>
<td>원본 복원이 불가능한 해시 방식. 비밀번호 저장 등에 사용</td>
</tr>
</tbody></table>
<h3 id="1-3-cng-알고리즘">1-3. CNG 알고리즘</h3>
<p><strong>CNG(Cryptography API: Next Generation)</strong>는 이름 그대로 차세대 암호화 API로, Data Protection에서 아래와 같은 모드를 선택해서 사용할 수 있습니다.</p>
<ul>
<li><strong>CBC (Cipher Block Chaining)</strong> — <code>Enums.CryptoType.CngCbc</code></li>
<li><strong>GCM (Galois/Counter Mode)</strong> — 인증까지 함께 처리 가능한 모드</li>
</ul>
<p>암호화 유형(CngCbc / CngGcm 등)에 따라 요구되는 조건이 다르며, 대표적으로 아래 조건을 만족해야 합니다.</p>
<ul>
<li>키 길이(Key.Length): 128bit 이상</li>
<li>사이즈(size): 64bit 이상</li>
</ul>
<blockquote>
<p>참고로 이 기능은 .NET Core 1.0에서는 지원되지 않고, .NET Core 2.0부터 관리(managed)되기 시작했습니다.</p>
</blockquote>
<h3 id="1-4-실제-사용-코드">1-4. 실제 사용 코드</h3>
<pre><code class="language-csharp">aes.EnUserInfo = _protector.Protect(userInfo);       // 암호화
aes.DecUserInfo = _protector.Unprotect(aes.EncUserInfo); // 복호화</code></pre>
<p>암호화 유형에 따라 지정해야 하는 값이 달라지기 때문에, 어떤 CNG 모드를 쓸지 먼저 정하고 그에 맞는 옵션을 설정해야 합니다.</p>
<hr>
<h2 id="2-claim-기반-인증authentication--인가authorization">2. Claim 기반 인증(Authentication) &amp; 인가(Authorization)</h2>
<h3 id="2-1-인증-vs-인가">2-1. 인증 vs 인가</h3>
<ul>
<li><strong>인증(Authentication)</strong> = &quot;이 사람이 누구인지&quot; 확인하는 것 (신원보증)</li>
<li><strong>인가(Authorization)</strong> = 인증된 사람이 &quot;무엇을 할 수 있는지&quot; 결정하는 것 (허가승인)</li>
</ul>
<h3 id="2-2-핵심-개념">2-2. 핵심 개념</h3>
<table>
<thead>
<tr>
<th>용어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>ClaimsPrincipal</code></td>
<td>로그인한 사용자 본인(Principal)</td>
</tr>
<tr>
<td><code>ClaimsIdentity</code></td>
<td>사용자의 신원(Identity) 정보</td>
</tr>
<tr>
<td><code>Authorize(Roles)</code></td>
<td>특정 역할(Role)을 가진 사용자만 접근을 허용하는 인가 처리</td>
</tr>
<tr>
<td><code>ClaimTypes.Role</code></td>
<td>사용자의 권한(역할) 정보</td>
</tr>
</tbody></table>
<h3 id="2-3-claimtype별-용도">2-3. ClaimType별 용도</h3>
<p>로그인 성공 시 사용자 정보를 Claim 형태로 만들어 쿠키에 담아두는데, ClaimType마다 역할이 다릅니다.</p>
<table>
<thead>
<tr>
<th>ClaimType</th>
<th>매핑되는 값</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><code>ClaimTypes.Name</code></td>
<td>UserId</td>
<td><code>_context.User.Identity.Name</code>으로 현재 로그인한 사용자 식별</td>
</tr>
<tr>
<td><code>ClaimTypes.Role</code></td>
<td>RoleId</td>
<td><code>[Authorize(Roles = &quot;0, 0, 0&quot;)]</code>처럼 접근 권한 제어에 사용</td>
</tr>
<tr>
<td><code>ClaimTypes.UserData</code></td>
<td>사용자 정의 데이터</td>
<td>표준 타입에 없는 값(RoleName, RolePriority, UserName, UserEmail 등) 저장</td>
</tr>
</tbody></table>
<p><code>Name</code>과 <code>Role</code>은 .NET이 인가 로직에서 직접 인식하는 표준 슬롯이고, <code>UserData</code>는 화면 표시나 별도 로직에서 참조할 부가 정보를 담는 자유 슬롯이라는 점이 핵심입니다.</p>
<h3 id="2-4-로그인-처리-코드">2-4. 로그인 처리 코드</h3>
<pre><code class="language-csharp">var identity = new ClaimsIdentity(
    claims: new[] { new Claim(type: ClaimTypes.Name, value: userId) },
    authenticationType: CookieAuthenticationDefaults.AuthenticationScheme
);

await _context.SignInAsync(
    scheme: CookieAuthenticationDefaults.AuthenticationScheme,
    principal: new ClaimsPrincipal(identity: identity),
    properties: null
);</code></pre>
<ul>
<li>신원보증만 필요하면 <code>app.UseAuthentication();</code></li>
<li>신원보증 + 인가까지 필요하면 위처럼 <code>SignInAsync</code>로 Claim을 담아 로그인 처리</li>
</ul>
<hr>
<h2 id="3-password-hasher-비밀번호-해싱">3. Password Hasher (비밀번호 해싱)</h2>
<h3 id="3-1-salt란">3-1. Salt란?</h3>
<p>같은 비밀번호라도 해시값이 매번 다르게 나오도록 섞어주는 무작위 값입니다. Salt가 없으면 같은 비밀번호를 쓰는 두 사용자의 해시값이 동일해져서 레인보우 테이블 공격에 취약해집니다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><strong>GUID Salt</strong></td>
<td>사용자 정보의 복잡성을 위해 사용 (고유성 확보)</td>
</tr>
<tr>
<td><strong>RNG Salt</strong> (Random Number Generator)</td>
<td>비밀번호 해시 생성 시 Salt 자체의 복잡성을 위해 사용 (예측 불가능한 무작위성 확보)</td>
</tr>
</tbody></table>
<h3 id="3-2-iterations-반복-횟수">3-2. Iterations (반복 횟수)</h3>
<p>비밀번호 해싱 시 같은 연산을 반복하는 횟수로, 보통 10000 / 25000 / 45000 같은 값을 사용합니다.</p>
<ul>
<li>반복 횟수가 많을수록 해시 계산 시간이 늘어나 <strong>무차별 대입 공격에 걸리는 시간이 크게 늘어남</strong></li>
<li>다만 서버 부하도 함께 커지므로, 보안성과 성능 사이 균형점을 고려해서 값을 정해야 함</li>
</ul>
<hr>
<h2 id="정리">정리</h2>
<p>오늘은 .NET Core에서 데이터를 안전하게 다루는 두 축을 학습했습니다.</p>
<ol>
<li><strong>Data Protection</strong>: 데이터 자체를 암호화/복호화하는 방법 (AES, CNG 모드)</li>
<li><strong>Claim 인증/인가</strong>: 로그인한 사용자가 누구인지, 무엇을 할 수 있는지 판단하는 방법</li>
<li><strong>Password Hasher</strong>: 비밀번호를 안전하게 저장하기 위한 Salt와 Iterations 개념</li>
</ol>
<p>다음에는 이 개념들이 실제 프로젝트 코드에서 어떻게 조합되어 쓰이는지 더 파봐야겠습니다.&gt;&lt;</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 오늘의 .NET CORE]]></title>
            <link>https://velog.io/@yeseo_052/TIL-%EC%98%A4%EB%8A%98%EC%9D%98-.NET-CORE</link>
            <guid>https://velog.io/@yeseo_052/TIL-%EC%98%A4%EB%8A%98%EC%9D%98-.NET-CORE</guid>
            <pubDate>Mon, 07 Sep 2026 08:56:41 GMT</pubDate>
            <description><![CDATA[<h1 id="net-core-migration-삽질기---ef-core-dbcontext-여러-개-다루기">.NET Core Migration 삽질기 - EF Core, DbContext 여러 개 다루기</h1>
<p>오래된 강의(2017~2019년) 따라서 .NET Core 프로젝트 세팅하다가 만난 에러들 정리. 강의는 EF Core 초기 버전 + .NET Framework 시절 문법이라, 지금(.NET 8, EF Core 8) 기준으로 옮기면서 겪은 문제들을 기록해둔다.</p>
<h2 id="1-dbcontext가-여러-개일-때----context-필수">1. DbContext가 여러 개일 때 - <code>-Context</code> 필수</h2>
<p>프로젝트에 <code>CodeFirstDbContext</code>, <code>DBFirstDbContext</code> 두 개를 등록해두면, 마이그레이션 명령어를 칠 때마다 아래 에러가 뜬다.</p>
<pre><code>More than one DbContext was found. Specify which one to use.
Use the &#39;-Context&#39; parameter for PowerShell commands...</code></pre><p>해결은 간단하다. <code>Add-Migration</code>, <code>Update-Database</code> 어떤 명령어든 <code>-Context</code>를 명시해주면 됨.</p>
<pre><code class="language-powershell">Add-Migration AddingUserTable -Context CodeFirstDbContext -Project NetCore.Services
Update-Database -Context CodeFirstDbContext -Project NetCore.Services</code></pre>
<h2 id="2-마이그레이션-파일이-엉뚱한-프로젝트에-생성될-때">2. 마이그레이션 파일이 엉뚱한 프로젝트에 생성될 때</h2>
<p><code>-Project NetCore.Migrations</code>로 지정했는데, 실제로는 <code>NetCore.Services</code>에 마이그레이션 폴더가 생기는 현상을 겪었다.</p>
<pre><code>Your target project &#39;NetCore.Migrations&#39; doesn&#39;t match your migrations assembly &#39;NetCore.Services&#39;.</code></pre><p>원인은 <code>Program.cs</code>에서 <code>MigrationsAssembly(&quot;NetCore.Migrations&quot;)</code>를 지정해도, 프로젝트 안에 <code>IDesignTimeDbContextFactory</code>를 구현한 클래스가 있으면 <strong>EF 툴이 Program.cs를 무시하고 그 팩토리를 최우선으로 사용</strong>한다는 것.</p>
<pre><code class="language-csharp">public class CodeFirstDBContextFactory : IDesignTimeDbContextFactory&lt;CodeFirstDbContext&gt;
{
    public CodeFirstDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder = new DbContextOptionsBuilder&lt;CodeFirstDbContext&gt;();
        optionsBuilder.UseSqlServer(
            connectionString,
            mig =&gt; mig.MigrationsAssembly(&quot;NetCore.Migrations&quot;)); // 여기 추가해야 함
        return new CodeFirstDbContext(optionsBuilder.Options);
    }
}</code></pre>
<p>팩토리가 있는 경우엔 <strong>팩토리 안의 <code>UseSqlServer</code> 옵션에도 똑같이 <code>MigrationsAssembly</code>를 지정</strong>해줘야 원하는 프로젝트로 마이그레이션 파일이 떨어진다. Program.cs 설정만 믿고 있으면 계속 삽질하게 됨.</p>
<h2 id="3-design-time-factory가-중복되면-생기는-문제">3. Design-time factory가 중복되면 생기는 문제</h2>
<p>프로젝트 두 곳에 각각 <code>IDesignTimeDbContextFactory</code>를 구현한 클래스가 있으면, EF 툴이 어느 걸 써야 할지 애매해지면서 계속 엉뚱한 프로젝트를 잡는다. <strong>팩토리는 딱 하나만 유지</strong>하는 게 정신건강에 이롭다.</p>
<h2 id="4-sql-server-연결-시-ssl-인증서-에러">4. SQL Server 연결 시 SSL 인증서 에러</h2>
<p>로컬 SQL Server(Express)에 접속할 때마다 나던 에러.</p>
<pre><code>서버에 연결했지만 로그인하는 동안 오류가 발생했습니다.
(provider: SSL 공급자, error: 0 - 신뢰되지 않은 기관에서 인증서 체인을 발급했습니다.)</code></pre><p>최근 SQL Server가 기본적으로 암호화 연결을 요구하도록 바뀌었는데, 로컬 개발용 서버엔 정식 SSL 인증서가 없어서 나는 에러다. 연결 문자열에 옵션 하나만 추가하면 해결된다.</p>
<pre><code>Server=localhost\SQLEXPRESS;Database=CodeFirstDB;User Id=coreuser;Password=corepwd;Encrypt=Optional;TrustServerCertificate=True;</code></pre><p>SSMS로 접속할 때도 마찬가지로 연결 창에서 <strong>&quot;서버 인증서 신뢰&quot;</strong> 체크박스를 켜주면 된다.</p>
<h2 id="5-startupcs-vs-programcs-net-8-minimal-hosting">5. Startup.cs vs Program.cs (.NET 8 minimal hosting)</h2>
<p>강의는 <code>Startup.cs</code>에 <code>ConfigureServices</code> / <code>Configure</code>를 나눠 쓰는 옛날 방식인데, .NET 8은 <code>Program.cs</code> 하나로 통합된 minimal hosting 방식을 쓴다. 대응 관계는 이렇게 정리하면 편하다.</p>
<table>
<thead>
<tr>
<th>Startup.cs</th>
<th>Program.cs</th>
</tr>
</thead>
<tbody><tr>
<td><code>ConfigureServices(IServiceCollection services)</code> 안의 코드</td>
<td><code>builder.Services.XXX()</code> (<code>builder.Build()</code> 이전)</td>
</tr>
<tr>
<td><code>Configure(IApplicationBuilder app, ...)</code> 안의 코드</td>
<td><code>app.XXX()</code> (<code>builder.Build()</code> 이후)</td>
</tr>
<tr>
<td><code>Configuration.GetConnectionString(...)</code></td>
<td><code>builder.Configuration.GetConnectionString(...)</code></td>
</tr>
</tbody></table>
<p>강의에서 <code>Startup.cs</code> 코드가 나오면, &quot;이게 서비스 등록이냐 미들웨어 파이프라인이냐&quot;만 구분해서 위/아래 절반으로 나눠 옮기면 됨.</p>
<h2 id="6-builderbuild-이후에-builderservices-건드리면-안-됨">6. <code>builder.Build()</code> 이후에 <code>builder.Services</code> 건드리면 안 됨</h2>
<p>무심코 코드 복붙하다가 <code>var app = builder.Build();</code> 아래에 <code>builder.Services.AddDbContext(...)</code>를 또 넣어서 에러 났었다. <code>Build()</code> 시점 이후로는 서비스 컨테이너가 이미 확정된 상태라, 그 이후엔 절대 <code>builder.Services</code>를 추가로 건드리면 안 된다.</p>
<h2 id="7-fromsql-→-fromsqlraw--fromsqlinterpolated">7. FromSql → FromSqlRaw / FromSqlInterpolated</h2>
<p>EF Core 3.0부터 <code>FromSql(string sql)</code>이라는 메서드 자체가 사라졌다. 2017~2019년 강의 코드엔 그대로 남아있어서 컴파일 에러가 남.</p>
<pre><code class="language-csharp">// 옛날 (지금은 존재하지 않는 메서드)
_context.Users.FromSql(&quot;SELECT * FROM User&quot;)

// 지금 - 변수 없는 순수 SQL 문자열
_context.Users.FromSqlRaw(&quot;SELECT * FROM User&quot;)

// 지금 - SQL 안에 변수가 들어가는 경우 (SQL Injection 방지용 파라미터화)
_context.Users.FromSqlInterpolated($&quot;SELECT * FROM User WHERE UserId = {userId}&quot;)</code></pre>
<p>이름만 바뀐 게 아니라, <code>Interpolated</code> 계열은 문자열 보간을 자동으로 파라미터화해서 SQL Injection을 막아주는 안전장치가 추가된 거다. 변수가 없으면 <code>Raw</code>, 있으면 <code>Interpolated</code> 쓰면 됨.</p>
<h2 id="8-생성자-이름은-클래스-이름과-정확히-같아야-함">8. 생성자 이름은 클래스 이름과 정확히 같아야 함</h2>
<p>복붙하다가 흔히 나는 실수. <code>DBFirstDbContext</code> 클래스인데 생성자 이름이 <code>CodeFirstDbContext</code>로 남아있으면 컴파일러가 &quot;메서드에는 반환 형식이 있어야 합니다&quot;라는, 원인 파악하기 애매한 에러를 던진다.</p>
<pre><code class="language-csharp">public class DBFirstDbContext : DbContext
{
    // 클래스 이름이랑 다르면 생성자가 아니라 이상한 메서드로 인식됨
    public CodeFirstDbContext(DbContextOptions&lt;CodeFirstDbContext&gt; options) : base(options) { } // ❌

    public DBFirstDbContext(DbContextOptions&lt;DBFirstDbContext&gt; options) : base(options) { } // ✅
}</code></pre>
<h2 id="9-public-클래스는-인터페이스도-public이어야-함">9. public 클래스는 인터페이스도 public이어야 함</h2>
<pre><code>CS0060: 일관성 없는 액세스 가능성: &#39;IUser&#39; 기본 클래스가 &#39;UserService&#39; 클래스보다 액세스하기 어렵습니다.</code></pre><p><code>public class UserService : IUser</code>인데 <code>interface IUser</code>가 <code>public</code>이 아니면 나는 에러. C#은 public 클래스가 구현/상속하는 타입도 최소한 같은 수준으로 공개되어 있어야 한다는 규칙이 있다. <code>interface IUser</code> → <code>public interface IUser</code>로 고치면 해결.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/yeseo_052/post/93759ee7-5ab0-4cce-b732-2c57d22a1960/image.png" alt=""></p>
<p>오늘 삽질 요약하면, 결국 대부분 &quot;강의는 5~7년 전 버전, 지금은 최신 버전&quot;이라는 시차에서 오는 문제였다. 에러 메시지를 찬찬히 읽으면 대부분 원인이 메시지 안에 다 적혀있다는 것도 새삼 느낌.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL  C# .Net Core]]></title>
            <link>https://velog.io/@yeseo_052/TIL-C-.Net-Core</link>
            <guid>https://velog.io/@yeseo_052/TIL-C-.Net-Core</guid>
            <pubDate>Tue, 01 Sep 2026 07:55:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/b51eb54b-271a-4426-94e2-de031c44d896/image.png" alt="">
먼저 C#이란 프로그래밍 &quot;언어&quot; 자체이고,
.NET은 그 C#이라는 언어가 돌아가는 &#39;플랫폼/런타임&#39;이다.
그렇다면 <strong>Core이란</strong>?
Core은 .NET 플랫폼 위에서 &quot;웹 애플리케이션(웹사이트, API 등)&quot;을 만들기 위한 프레임워크 입니다!</p>
<pre><code>C# (언어)
  → .NET (플랫폼/런타임, 예전엔 .NET Core라고 불림)
    → ASP.NET Core (그 위에서 웹 앱/API 만드는 프레임워크)</code></pre><p>짧고, 간단하게 설명하자면 이렇다!</p>
<h2 id="1단계-개념-이해">1단계: 개념 이해</h2>
<h4 id="인터페이스interface">인터페이스(Interface)</h4>
<p><strong>Interface</strong>에 대해 알아보자!
먼저 이 예시코드를 보며 이해긔긔!!!</p>
<pre><code>public interface IUserService
{
    void CreateUser(string name);
}

public class UserService : IUserService
{
    public void CreateUser(string name) { /* 실제 DB 저장 로직 */ }
}</code></pre><p>_이 클래스는 이런 기능을 반드시 가지고 있어야 한다_이다. </p>
<p>이 코드를 보면서 제일 궁금했던 부분은 UserService, IUserService의 사이에 있는 <strong>:</strong> 이다.
&quot; : &quot;는 쉽게 설명하자면 <strong>implements를</strong> 의미한다.</p>
<p><strong>상속(inheritance):</strong> 부모 클래스의 실제 동작(코드)까지 물려받음
<strong>구현(interface/implements):</strong> 인터페이스가 정해둔 &quot;규칙(메서드 이름만)&quot;만 따르고, 실제 코드는 직접 다 채워야 함</p>
<blockquote>
<p>: 기호를 C#에서는 상속(extends)과 구현(implements) 둘 다에 씁니다. 자바처럼 나눠 쓰지 않아요.</p>
</blockquote>
<p>컨트롤러는 IUserService라는 &quot;약속&quot;만 알고 있고, 
실제 구현체(UserService)가 뭔지는 몰라도 됩니다. 나중에 UserService를 다른 걸로 바꿔도 컨트롤러 코드는 안 건드려도 돼요. → 이게 <strong>DI(의존성 주입)</strong>의 기초가 됩니다.</p>
<p>인터페이스는 &quot;이런 메서드가 있어야 한다&quot;고 강제만 하고, 실제로 어떻게 동작할지는 구현하는 클래스가 알아서 채워요 :)</p>
<h4 id="2-asyncawait">2. async/await</h4>
<p>async/await는 시간이 걸리는 작업(DB 조회, API 호출 등)을 기다리는 동안 서버가 놀지 않고 다른 요청을 처리하게 해주는 문법이다.</p>
<pre><code>//예시 소스
public async Task&lt;User&gt; GetUserAsync(int id)
{
    var user = await _dbContext.Users.FindAsync(id);  
    return user;
}</code></pre><p>Task<User>는 &quot;User가 나중에 도착할 거야&quot;라는 포장 상자이다.</p>
<h5 id="이해하기-쉽게-설명하자면-user로-반환한-값을-포장-상자-안에-넣어-저장이-되는-것이다">이해하기 쉽게 설명하자면, user로 반환한 값을 포장 상자 안에 넣어 저장이 되는 것이다.</h5>
<p>  <strong>async</strong>: 이 메서드는 비동기로 동작한다고 표시
  <strong>await</strong>는 &quot;DB가 응답 줄 때까지 여기서 기다릴게 근데 기다리는 동안 서버는 다른 손님(요청) 받아도 돼&quot;라는 뜻이다.</p>
<h4 id="3-linq">3. LINQ</h4>
<p>  한 줄 정의: 컬렉션(List, DB 데이터 등)을 SQL처럼 필터링/조회하는 문법.</p>
<pre><code>List&lt;int&gt; numbers = new List&lt;int&gt; { 1, 2, 3, 4, 5 };

var evens = numbers.Where(n =&gt; n % 2 == 0);       // 짝수만: [2, 4]
var first = numbers.FirstOrDefault(n =&gt; n &gt; 3);    // 3보다 큰 첫 값: 4
var doubled = numbers.Select(n =&gt; n * 2);          // 각 값 2배: [2,4,6,8,10]</code></pre><h6 id="db를-할-때도">DB를 할 때도</h6>
<pre><code>var user = await _dbContext.Users.FirstOrDefaultAsync(u =&gt; u.Email == email);</code></pre><p>  <strong>Where</strong>: 조건에 맞는 것만 골라내기(필터링)
<strong>FirstOrDefault</strong>: 조건에 맞는 첫 번째 값 하나만 가져오기 (없으면 null 또는 기본값 반환)
<strong>Select</strong>: &quot;검색&quot;이라기보다는 모양을 바꿔서 뽑아내기(변환)</p>
<h4 id="4-di">4. DI</h4>
<pre><code>  //예시소스
builder.Services.AddScoped&lt;IUserService, UserService&gt;();

// 컨트롤러에서는 그냥 받아서 씀
public class UserController : ControllerBase
{
    private readonly IUserService _userService;

    public UserController(IUserService userService) {
        _userService = userService;
    }
}</code></pre><h6 id="의-소스-중에서">의 소스 중에서</h6>
<pre><code>builder.Services.AddScoped&lt;IUserService, UserService&gt;();</code></pre><blockquote>
<p>IUserService라는 계약서가 필요할 때는 UserService라는 실제 구현체를 갖다 써라!
 AddScoped는 &quot;이 객체를 웹 요청 하나당 1개씩 새로 만들어서 써라&quot;는 규칙(생명주기)을 정하는 것.</p>
</blockquote>
<p>public UserController(IUserService userService)<br>  --&gt; &quot;나 IUserService 필요해요!&quot; 라고 요청</p>
<p>이렇게 생성자에 써두기만 해도 ASP.NET Core가 알아서 &quot;아까 등록해둔 UserService를 여기 꽂아줄게&quot;라고 자동으로 넣어준다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 12세 이하인 여자 환자 목록 출력하기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-12%EC%84%B8-%EC%9D%B4%ED%95%98%EC%9D%B8-%EC%97%AC%EC%9E%90-%ED%99%98%EC%9E%90-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-12%EC%84%B8-%EC%9D%B4%ED%95%98%EC%9D%B8-%EC%97%AC%EC%9E%90-%ED%99%98%EC%9E%90-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0-Level-1</guid>
            <pubDate>Tue, 01 Sep 2026 07:14:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/8f233ad8-091a-4c3a-bc24-9e3b0f0c5177/image.png" alt=""></p>
<pre><code>SELECT PT_NAME,PT_NO,GEND_CD,AGE, COALESCE(TLNO,&quot;NONE&quot;) AS TLNO FROM PATIENT WHERE AGE&lt;=12 AND GEND_CD=&#39;W&#39; ORDER BY AGE DESC, PT_NAME ASC;</code></pre><p>여기 조건을 딱 정리하자면</p>
<ol>
<li>12세 이하만(AGE&lt;=12)</li>
<li>여자환자(W)</li>
<li>환자이름, 환자번호, 성별 코드, 나이, 전화번호 조회</li>
<li>전화번호가 (null)값이라면 &#39;NONE&#39; 출력</li>
<li>우선순위 (1) 나이 내림차순 (AGE DESC), (2) 환자 이름 오름차순(PT_NAME ASC)</li>
</ol>
<p>여기서 가장 어려웠던 부분! Update나 insert 부분은 is not null이나 is null을 사용해서 null 값이 있는 부분을 판별하면 되는데, SELECT 문은 처음이었습니다. 그래서 다른 개발자 분들의 소스를 보고, 참고하여 작성했습니다! </p>
<h3 id="coalesce란">COALESCE란?</h3>
<p>영어 단어 coalesce는 원래 &quot;합쳐지다&quot;라는 뜻이며
데이터베이스에서는 NULL 값을 다른 대체 값으로 바꾸거나 여러 컬럼을 병합하여 유효한 값을 찾을 때 사용합니다!</p>
<p><em><del>요즘 코테 하면 level 2보다 1이 어려운 것 같아요,,,</del></em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 어린 동물 찾기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%96%B4%EB%A6%B0-%EB%8F%99%EB%AC%BC-%EC%B0%BE%EA%B8%B0-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%96%B4%EB%A6%B0-%EB%8F%99%EB%AC%BC-%EC%B0%BE%EA%B8%B0-Level-1</guid>
            <pubDate>Tue, 01 Sep 2026 07:05:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/93cff5ab-714b-4469-99f2-5660896c7ecd/image.png" alt=""></p>
<pre><code>SELECT ANIMAL_ID, NAME FROM ANIMAL_INS WHERE INTAKE_CONDITION != &#39;Aged&#39; ORDER BY ANIMAL_ID ASC;</code></pre><p>젊은 동물을 어떻게 판별하지? 했는데 db 설계도를 먼저 코드 실행으로 알아보니 INTAKE_CONDITION에 &#39;Aged&#39;가 젊지 않은 동물을 표현하는 것 같아 INTAKE_CONDITION에 Aged라면? 그거 빼고! 라는 출력을 넣었고, 이때 결과는 아이디 순이라는 말은
정렬 즉,</p>
<blockquote>
<p>ORDER BY</p>
</blockquote>
<p>를 사용하라는 것이기 때문에, ANIMAL_ID 오름차순으로 정렬했습니다!</p>
<pre><code>피드백 ture. 허용합니다. :)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 조건에 맞는 아이템들의 가격의 총합 구하기 - (Level 2)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%9D%B8%EA%B8%B0%EC%9E%88%EB%8A%94-%EC%95%84%EC%9D%B4%EC%8A%A4%ED%81%AC%EB%A6%BC-Level-1-eejeit2v</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%9D%B8%EA%B8%B0%EC%9E%88%EB%8A%94-%EC%95%84%EC%9D%B4%EC%8A%A4%ED%81%AC%EB%A6%BC-Level-1-eejeit2v</guid>
            <pubDate>Tue, 01 Sep 2026 06:57:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/23487454-f273-42c4-85be-06607eceec59/image.png" alt=""></p>
<pre><code>select sum(PRICE) as TOTAL_PRICE FROM ITEM_INFO WHERE RARITY=&#39;LEGEND&#39;;</code></pre><p>sum으로 총합을 구하고 이떄 컬렴명은 &#39;TOTAL_PRICE&#39;이기 때문에, AS로 컬럼명을 수정한다. 또한 테이블에서 희귀도가 &#39;LEGEND&#39;만 조회하라고 했기 때문에 WHERE문에 RARITY가 &#39;LEGEND&#39;것 만 출력한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 인기있는 아이스크림 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%9D%B8%EA%B8%B0%EC%9E%88%EB%8A%94-%EC%95%84%EC%9D%B4%EC%8A%A4%ED%81%AC%EB%A6%BC-Level-1-4jh8j9z7</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%9D%B8%EA%B8%B0%EC%9E%88%EB%8A%94-%EC%95%84%EC%9D%B4%EC%8A%A4%ED%81%AC%EB%A6%BC-Level-1-4jh8j9z7</guid>
            <pubDate>Sun, 30 Aug 2026 22:59:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/6fb93be8-7c42-40d3-a788-67fba16bf39b/image.png" alt="">
<img src="https://velog.velcdn.com/images/yeseo_052/post/46dc0a0c-d3ce-422a-8fcc-53690613333d/image.png" alt=""></p>
<h3 id="정답">정답</h3>
<pre><code>SELECT FLAVOR FROM FIRST_HALF ORDER BY TOTAL_ORDER DESC, SHIPMENT_ID ASC;</code></pre><p>총주문량(TOTAL_ORDER)은 내림차순으로 DESC,
출하번호(SHIPMENT_ID)은 오름차순 ASC으로 정렬된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL VIEW(뷰)]]></title>
            <link>https://velog.io/@yeseo_052/TIL-VIEW%EB%B7%B0</link>
            <guid>https://velog.io/@yeseo_052/TIL-VIEW%EB%B7%B0</guid>
            <pubDate>Wed, 26 Aug 2026 14:56:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/7475bb3e-7336-469b-a3f5-deb8c5276c10/image.png" alt=""></p>
<h1 id="📚-수행평가-범위-정리">📚 수행평가 범위 정리</h1>
<hr>
<h1 id="ⅰ-view뷰-⭐⭐⭐⭐⭐">Ⅰ. VIEW(뷰) ⭐⭐⭐⭐⭐</h1>
<h2 id="1-view란">1. View란?</h2>
<p><strong>View = SELECT문의 결과를 테이블처럼 사용할 수 있도록 만든 가상의 테이블</strong></p>
<ul>
<li>실제 데이터를 저장하지 않음</li>
<li>기존 테이블을 기반으로 만들어짐</li>
<li>실제로는 <strong>SELECT문을 저장</strong></li>
<li>기본 테이블의 데이터를 보여주는 <strong>창(window)</strong> 역할</li>
</ul>
<h3 id="핵심-암기">핵심 암기</h3>
<blockquote>
<p><strong>View는 실제 테이블이 아니라 SELECT 결과를 테이블처럼 사용하는 가상 테이블이다.</strong></p>
</blockquote>
<hr>
<h2 id="2-view-생성">2. View 생성</h2>
<pre><code class="language-sql">CREATE VIEW V_커피메뉴 AS
SELECT DRINK_ID AS 음료번호,
       DRINK_NAME AS 음료이름,
       PRICE AS 가격
FROM DRINK
WHERE CATEGORY = &#39;커피&#39;;</code></pre>
<h3 id="개념">개념</h3>
<pre><code class="language-text">CREATE VIEW → View 생성
AS → 뒤의 SELECT문을 View의 정의로 사용</code></pre>
<hr>
<h2 id="3-view-조회">3. View 조회</h2>
<pre><code class="language-sql">SELECT *
FROM V_커피메뉴;</code></pre>
<p>View를 만든 뒤에는 <strong>일반 테이블처럼 SELECT</strong>할 수 있음.</p>
<pre><code class="language-sql">SELECT *
FROM V_커피메뉴
WHERE 가격 &lt;= 3000;</code></pre>
<hr>
<h1 id="ⅱ-view의-특징-⭐⭐⭐⭐⭐">Ⅱ. View의 특징 ⭐⭐⭐⭐⭐</h1>
<p>PDF에서 강조하는 부분.</p>
<h3 id="①-실제-데이터를-저장하지-않음">① 실제 데이터를 저장하지 않음</h3>
<p>View에는 데이터를 복사해서 저장하는 것이 아니라 <strong>SELECT문이 저장됨.</strong></p>
<h3 id="②-select-결과를-테이블처럼-사용">② SELECT 결과를 테이블처럼 사용</h3>
<pre><code class="language-sql">SELECT *
FROM V_커피메뉴;</code></pre>
<h3 id="③-기본-테이블이-변경되면-view-결과도-변경">③ 기본 테이블이 변경되면 View 결과도 변경</h3>
<p>View가 <code>DRINK</code>를 기반으로 만들어졌다면 <code>DRINK</code>의 데이터가 바뀔 경우 View의 결과도 바뀜.</p>
<h3 id="④-기본-테이블-대신-view를-통해-조회-가능">④ 기본 테이블 대신 View를 통해 조회 가능</h3>
<p>필요한 데이터만 View로 만들어 사용자에게 제공할 수 있음.</p>
<h3 id="⑤-데이터-보안">⑤ 데이터 보안</h3>
<p>기본 테이블의 모든 정보를 보여주지 않고 <strong>원하는 컬럼이나 데이터만 View로 제공</strong>할 수 있음.</p>
<p>PDF에서는 View를 데이터 보안 측면에서 활용하고, 원하는 내용만 보여줄 수 있다고 설명함. </p>
<hr>
<h1 id="ⅲ-view의-장점-⭐⭐⭐⭐⭐">Ⅲ. View의 장점 ⭐⭐⭐⭐⭐</h1>
<h2 id="①-복잡한-질의를-단순하게-표현">① 복잡한 질의를 단순하게 표현</h2>
<p>복잡한 SQL을 View로 미리 만들어두면:</p>
<pre><code class="language-sql">SELECT *
FROM V_주문영수증;</code></pre>
<p>처럼 간단하게 사용할 수 있음.</p>
<p>PDF에서도 <strong>복잡한 SQL을 미리 정의하고 이후 간단한 SQL문으로 조회</strong>할 수 있다고 설명함. </p>
<hr>
<h2 id="②-특정-데이터만-사용자에게-보여줌">② 특정 데이터만 사용자에게 보여줌</h2>
<p>예:</p>
<pre><code class="language-sql">CREATE VIEW V_커피메뉴 AS
SELECT DRINK_ID, DRINK_NAME, PRICE
FROM DRINK
WHERE CATEGORY = &#39;커피&#39;;</code></pre>
<p>→ <code>DRINK</code>의 모든 정보를 보여주지 않고 <strong>커피 메뉴만 제공</strong></p>
<hr>
<h2 id="③-데이터-독립성">③ 데이터 독립성</h2>
<p>프로그램에서 복잡한 원본 테이블 구조를 직접 다루지 않고 View를 사용할 수 있음.</p>
<p>즉,</p>
<pre><code class="language-text">기본 테이블
↓
View
↓
프로그램</code></pre>
<p>형태로 사용할 수 있음.</p>
<p>PDF에서도 View의 장점으로 <strong>데이터 독립성</strong>을 제시함. </p>
<hr>
<h1 id="ⅳ-view의-단점-⭐⭐⭐">Ⅳ. View의 단점 ⭐⭐⭐</h1>
<p>PDF에서 나오는 핵심:</p>
<h3 id="①-모든-view가-갱신-가능한-것은-아님">① 모든 View가 갱신 가능한 것은 아님</h3>
<h3 id="②-기본-테이블보다-성능이-떨어질-수-있음">② 기본 테이블보다 성능이 떨어질 수 있음</h3>
<p>View를 사용할 때 DBMS가 View의 정의를 확인하고 기본 테이블을 조회하는 과정이 필요함. </p>
<hr>
<h1 id="ⅴ-갱신-불가능한-view-⭐⭐⭐⭐⭐">Ⅴ. 갱신 불가능한 View ⭐⭐⭐⭐⭐</h1>
<p><strong>어떤 View든 UPDATE가 되는 것은 아님.</strong></p>
<p>PDF에서 제시한 대표적인 갱신 불가능 조건:</p>
<pre><code class="language-text">① 집계 함수 SUM, AVG
② GROUP BY
③ JOIN
④ 기본키 없음</code></pre>
<h3 id="예시">예시</h3>
<pre><code class="language-sql">CREATE VIEW V_지점별매출 AS
SELECT C.CAFE_LOCATION,
       SUM(D.PRICE * O.QTY) AS 총매출
FROM CAFE C
JOIN DRINK D
ON C.CAFE_ID = D.CAFE_ID
JOIN ORDERS O
ON D.DRINK_ID = O.DRINK_ID
GROUP BY C.CAFE_LOCATION;</code></pre>
<p>이 View에는</p>
<pre><code class="language-text">SUM
JOIN
GROUP BY</code></pre>
<p>가 있기 때문에 갱신하기 어려움.</p>
<hr>
<h1 id="ⅵ-view-삭제-⭐⭐">Ⅵ. View 삭제 ⭐⭐</h1>
<pre><code class="language-sql">DROP VIEW V_커피메뉴;</code></pre>
<h3 id="중요">중요</h3>
<p><strong>View를 삭제해도 기본 테이블에는 영향을 주지 않음.</strong></p>
<p>즉,</p>
<pre><code class="language-text">DROP VIEW
↓
View만 삭제
↓
DRINK 테이블은 그대로</code></pre>
<hr>
<h1 id="ⅶ-시스템-카탈로그-⭐⭐⭐⭐⭐">Ⅶ. 시스템 카탈로그 ⭐⭐⭐⭐⭐</h1>
<h2 id="1-시스템-카탈로그란">1. 시스템 카탈로그란?</h2>
<p><strong>데이터베이스의 구조와 객체 정보를 저장하는 메타데이터</strong></p>
<h3 id="메타데이터">메타데이터</h3>
<blockquote>
<p><strong>데이터에 대한 데이터</strong></p>
</blockquote>
<p>예를 들어 실제 데이터가:</p>
<pre><code class="language-text">메가커피
메가리카노
2000원</code></pre>
<p>이라면 메타데이터는:</p>
<pre><code class="language-text">DRINK라는 테이블이 존재한다.
DRINK_ID라는 컬럼이 있다.
DRINK_ID의 자료형은 NUMBER다.</code></pre>
<p>같은 <strong>데이터베이스의 구조 정보</strong>임.</p>
<hr>
<h1 id="ⅷ-시스템-카탈로그에-저장되는-정보-⭐⭐⭐">Ⅷ. 시스템 카탈로그에 저장되는 정보 ⭐⭐⭐</h1>
<p>PDF 기준으로:</p>
<ul>
<li>테이블 정보</li>
<li>컬럼 정보</li>
<li>데이터 타입</li>
<li>인덱스</li>
<li>사용자 정보</li>
<li>접근 권한</li>
</ul>
<p>등을 저장함. </p>
<hr>
<h1 id="ⅸ-시스템-카탈로그의-역할-⭐⭐⭐⭐">Ⅸ. 시스템 카탈로그의 역할 ⭐⭐⭐⭐</h1>
<h3 id="①-데이터베이스-구조-관리">① 데이터베이스 구조 관리</h3>
<p>테이블, 컬럼, 데이터 타입 등의 구조 정보를 저장.</p>
<h3 id="②-사용자-권한-관리">② 사용자 권한 관리</h3>
<p>사용자마다 어떤 테이블을 조회하거나 수정할 수 있는지 관리.</p>
<h3 id="③-질의-최적화-지원">③ 질의 최적화 지원</h3>
<p>DBMS가 SQL을 실행할 때 테이블 구조나 인덱스 정보를 확인해서 질의 처리에 활용.</p>
<h3 id="④-데이터베이스-검색-지원">④ 데이터베이스 검색 지원</h3>
<p>테이블 등의 정보를 조회할 수 있음.</p>
<hr>
<h1 id="ⅹ-시스템-카탈로그의-특징-⭐⭐⭐⭐">Ⅹ. 시스템 카탈로그의 특징 ⭐⭐⭐⭐</h1>
<h3 id="①-db-내부에-존재하는-특수한-테이블">① DB 내부에 존재하는 특수한 테이블</h3>
<h3 id="②-dbms가-자동으로-관리">② DBMS가 자동으로 관리</h3>
<p>테이블을 만들거나 삭제하면 시스템 카탈로그도 자동으로 변경됨.</p>
<h3 id="③-사용자가-직접-수정할-수-없음">③ 사용자가 직접 수정할 수 없음</h3>
<p>데이터베이스 구조를 관리하는 중요한 정보이기 때문에 직접 수정할 수 없음.</p>
<hr>
<h1 id="ⅺ-시스템-카탈로그-조회-쿼리-⭐⭐⭐⭐⭐">Ⅺ. 시스템 카탈로그 조회 쿼리 ⭐⭐⭐⭐⭐</h1>
<h2 id="①-내가-만든-테이블-목록">① 내가 만든 테이블 목록</h2>
<pre><code class="language-sql">SELECT TABLE_NAME
FROM USER_TABLES;</code></pre>
<h3 id="개념-1">개념</h3>
<p><code>USER_TABLES</code></p>
<p>→ <strong>사용자가 만든 테이블 정보</strong></p>
<hr>
<h2 id="②-특정-테이블의-컬럼-정보">② 특정 테이블의 컬럼 정보</h2>
<pre><code class="language-sql">SELECT COLUMN_NAME,
       DATA_TYPE,
       DATA_LENGTH,
       NULLABLE
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = &#39;DRINK&#39;;</code></pre>
<h3 id="개념-2">개념</h3>
<p><code>USER_TAB_COLUMNS</code></p>
<p>→ <strong>테이블의 컬럼 구조 확인</strong></p>
<table>
<thead>
<tr>
<th>컬럼</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>COLUMN_NAME</code></td>
<td>컬럼 이름</td>
</tr>
<tr>
<td><code>DATA_TYPE</code></td>
<td>데이터 타입</td>
</tr>
<tr>
<td><code>DATA_LENGTH</code></td>
<td>데이터 길이</td>
</tr>
<tr>
<td><code>NULLABLE</code></td>
<td>NULL 허용 여부</td>
</tr>
</tbody></table>
<p>⚠️ <code>TABLE_NAME = &#39;DRINK&#39;</code>처럼 <strong>테이블 이름은 대문자</strong>로 작성.</p>
<hr>
<h2 id="③-제약조건-목록">③ 제약조건 목록</h2>
<pre><code class="language-sql">SELECT TABLE_NAME,
       CONSTRAINT_NAME,
       CONSTRAINT_TYPE
FROM USER_CONSTRAINTS
ORDER BY TABLE_NAME;</code></pre>
<h3 id="개념-3">개념</h3>
<p><code>USER_CONSTRAINTS</code></p>
<p>→ <strong>제약조건 정보 확인</strong></p>
<p>예:</p>
<pre><code class="language-text">PRIMARY KEY
FOREIGN KEY
CHECK</code></pre>
<hr>
<h2 id="④-view-목록">④ View 목록</h2>
<pre><code class="language-sql">SELECT VIEW_NAME
FROM USER_VIEWS;</code></pre>
<h3 id="개념-4">개념</h3>
<p><code>USER_VIEWS</code></p>
<p>→ <strong>내가 만든 View 목록 확인</strong></p>
<hr>
<h2 id="⑤-view의-실제-정의">⑤ View의 실제 정의</h2>
<pre><code class="language-sql">SELECT VIEW_NAME, TEXT
FROM USER_VIEWS
WHERE VIEW_NAME = &#39;V_지점별매출&#39;;</code></pre>
<h3 id="개념-5">개념</h3>
<p><code>TEXT</code></p>
<p>→ 해당 View를 만들 때 사용한 <strong>SELECT문 확인</strong></p>
<hr>
<h1 id="ⅻ-실습-sql에서-같이-나오는-기본-개념">Ⅻ. 실습 SQL에서 같이 나오는 기본 개념</h1>
<p>PDF가 직접적으로 다루는 핵심은 View와 시스템 카탈로그지만, 네 수행평가 실습에서는 그걸 만들기 위해 아래 SQL 개념도 사용하고 있음.</p>
<h2 id="select">SELECT</h2>
<pre><code class="language-sql">SELECT DRINK_NAME, CATEGORY, PRICE
FROM DRINK;</code></pre>
<p>→ 데이터 조회</p>
<h2 id="where">WHERE</h2>
<pre><code class="language-sql">WHERE PRICE &gt;= 4000</code></pre>
<p>→ 조건에 맞는 데이터 조회</p>
<h2 id="like">LIKE</h2>
<pre><code class="language-sql">WHERE DRINK_NAME LIKE &#39;%라떼%&#39;</code></pre>
<p>→ 특정 문자열 검색</p>
<h2 id="order-by">ORDER BY</h2>
<pre><code class="language-sql">ORDER BY PRICE DESC;</code></pre>
<p>→ 결과 정렬</p>
<h2 id="join">JOIN</h2>
<pre><code class="language-sql">JOIN DRINK D
ON C.CAFE_ID = D.CAFE_ID</code></pre>
<p>→ 여러 테이블 연결</p>
<h2 id="집계함수">집계함수</h2>
<pre><code class="language-sql">SUM()
AVG()
MAX()
MIN()
COUNT()</code></pre>
<p>→ 여러 데이터를 하나의 값으로 계산</p>
<h2 id="group-by">GROUP BY</h2>
<pre><code class="language-sql">GROUP BY C.CAFE_LOCATION</code></pre>
<p>→ 특정 기준으로 데이터를 그룹화</p>
<h2 id="having">HAVING</h2>
<pre><code class="language-sql">HAVING SUM(D.PRICE * O.QTY) &gt;= 5000</code></pre>
<p>→ 그룹화된 결과에 조건 적용</p>
<h2 id="서브쿼리">서브쿼리</h2>
<pre><code class="language-sql">WHERE PRICE = (
    SELECT MAX(PRICE)
    FROM DRINK
);</code></pre>
<p>→ SQL 안에 SQL을 넣어서 결과를 이용</p>
<hr>
<h1 id="🎯-진짜-수행평가용-핵심-구조">🎯 진짜 수행평가용 핵심 구조</h1>
<p>시험 전에 이 구조로 머릿속에 넣으면 돼.</p>
<pre><code class="language-text">[VIEW]
│
├─ 정의
│  └─ SELECT 결과를 테이블처럼 사용하는 가상 테이블
│
├─ 특징
│  ├─ 실제 데이터 저장 X
│  ├─ SELECT문 저장
│  ├─ 기본 테이블 변경 → View 결과 변경
│  └─ 필요한 데이터만 보여줄 수 있음
│
├─ 장점
│  ├─ 복잡한 질의 단순화
│  ├─ 데이터 보안
│  └─ 데이터 독립성
│
├─ 단점
│  ├─ 모든 View 갱신 가능 X
│  └─ 성능 저하 가능
│
├─ 갱신 불가능
│  ├─ SUM / AVG
│  ├─ GROUP BY
│  ├─ JOIN
│  └─ 기본키 없음
│
└─ SQL
   ├─ CREATE VIEW
   ├─ SELECT FROM VIEW
   └─ DROP VIEW


[시스템 카탈로그]
│
├─ 정의
│  └─ DB 구조와 객체 정보를 저장하는 메타데이터
│
├─ 저장 정보
│  ├─ 테이블
│  ├─ 컬럼
│  ├─ 데이터 타입
│  ├─ 인덱스
│  ├─ 사용자
│  └─ 권한
│
├─ 특징
│  ├─ DBMS가 자동 관리
│  └─ 사용자가 직접 수정 X
│
└─ SQL
   ├─ USER_TABLES
   ├─ USER_TAB_COLUMNS
   ├─ USER_CONSTRAINTS
   └─ USER_VIEWS</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 디스크 스케줄링]]></title>
            <link>https://velog.io/@yeseo_052/TIL-%EB%94%94%EC%8A%A4%ED%81%AC-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</link>
            <guid>https://velog.io/@yeseo_052/TIL-%EB%94%94%EC%8A%A4%ED%81%AC-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</guid>
            <pubDate>Sun, 23 Aug 2026 14:49:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/c8b2574b-0ce1-4162-b867-d772fcfdb3db/image.png" alt=""></p>
<h1 id="디스크-스케줄링-정리">디스크 스케줄링 정리</h1>
<p>오늘은 디스크 스케줄링의 대표적인 알고리즘인 <strong>FCFS, SSTF, SCAN, C-SCAN</strong>을 문제를 직접 풀면서 학습했다.</p>
<h2 id="1-fcfs-first-come-first-served">1. FCFS (First Come First Served)</h2>
<p>요청이 들어온 <strong>순서 그대로 처리</strong>하는 방식이다.</p>
<p>예를 들어 시작 위치가 53이고 Queue가 <code>25, 130, 10</code>이라면:</p>
<p><code>53 → 25 → 130 → 10</code></p>
<p>각 요청까지의 이동거리를 계산하여 총 헤드 이동 거리를 구한다.</p>
<blockquote>
<p><strong>핵심: Queue 순서 그대로</strong></p>
</blockquote>
<hr>
<h2 id="2-sstf-shortest-seek-time-first">2. SSTF (Shortest Seek Time First)</h2>
<p>현재 헤드 위치에서 <strong>가장 가까운 요청부터 처리</strong>하는 방식이다.</p>
<p>예를 들어 현재 위치가 53이라면 각 요청과의 거리를 비교해서 가장 가까운 요청을 선택한다.</p>
<p><code>53 → 55</code></p>
<p>이후 현재 위치가 55가 되었으므로 다시 남은 요청들과의 거리를 비교한다.</p>
<h3 id="⚠️-동률-주의">⚠️ 동률 주의</h3>
<p>현재 위치가 55이고 남은 요청이 <code>25, 85</code>라면:</p>
<ul>
<li>55 → 25 = 30</li>
<li>55 → 85 = 30</li>
</ul>
<p>둘의 거리가 같기 때문에 <strong>동률(tie)</strong>이 발생한다.</p>
<p>따라서 문제나 수업에서 <strong>동률 처리 기준</strong>을 제시했는지 확인해야 한다. 별도의 기준이 없다면 어느 쪽을 먼저 처리할지 답이 하나로 고정되지 않을 수 있다.
거리가 같을 때는 헤드의 물리적 무리를 줄이기 위해 기존 진행 방향을 유지하는 것이 기본 표준 규칙입니다..</p>
<blockquote>
<p><strong>핵심: 현재 위치에서 가장 가까운 요청을 선택 + 동률 처리 규칙 확인</strong></p>
</blockquote>
<hr>
<h2 id="3-scan">3. SCAN</h2>
<p>엘리베이터처럼 <strong>한 방향으로 이동하면서 요청을 처리하고, 디스크의 끝까지 이동한 후 방향을 바꾸는 방식</strong>이다.</p>
<p>예를 들어 53에서 시작하고 <strong>0 방향으로 먼저 이동</strong>한다면:</p>
<p><code>53 → 18 → 9 → 0 → 72 → 120 → ...</code></p>
<p>여기서 중요한 것은 <strong>요청 중 가장 작은 값인 9까지만 가는 것이 아니라 디스크의 끝인 0까지 이동한다는 것</strong>이다.</p>
<p>반대로 199 방향이라면 <strong>199까지 이동한 후 방향을 바꾼다.</strong></p>
<blockquote>
<p><strong>핵심: 한 방향 → 끝까지 → 방향 전환</strong></p>
</blockquote>
<hr>
<h2 id="4-c-scan">4. C-SCAN</h2>
<p>SCAN과 비슷하지만 <strong>한 방향으로만 요청을 처리</strong>한다.</p>
<p>예를 들어 53에서 <strong>0 방향</strong>으로 시작한다면:</p>
<p><code>53 → 18 → 9 → 0 → 199 → 185 → 150 → ...</code></p>
<p>0에 도착하면 방향을 바꾸어 처리하는 것이 아니라 <strong>반대쪽 끝인 199로 이동한 후 다시 같은 방향으로 처리</strong>한다.</p>
<blockquote>
<p><strong>핵심: 한 방향 → 끝까지 → 반대쪽 끝으로 이동 → 다시 같은 방향</strong></p>
</blockquote>
<hr>
<h2 id="5-네-가지-알고리즘-비교">5. 네 가지 알고리즘 비교</h2>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>핵심</th>
</tr>
</thead>
<tbody><tr>
<td><strong>FCFS</strong></td>
<td>요청 순서대로 처리</td>
</tr>
<tr>
<td><strong>SSTF</strong></td>
<td>현재 위치에서 가장 가까운 요청부터</td>
</tr>
<tr>
<td><strong>SCAN</strong></td>
<td>한 방향으로 끝까지 이동 후 방향 전환</td>
</tr>
<tr>
<td><strong>C-SCAN</strong></td>
<td>한 방향으로 끝까지 이동 후 반대쪽 끝으로 이동</td>
</tr>
</tbody></table>
<h3 id="오늘의-핵심">오늘의 핵심</h3>
<p>디스크 스케줄링 문제는 단순히 <strong>처리 순서만 찾는 것이 아니라 각 이동 거리를 계산하여 총 이동 거리까지 구하는 것</strong>이 중요하다.</p>
<p>특히 <strong>SCAN과 C-SCAN은 디스크의 끝(0 또는 199)을 반드시 고려</strong>해야 하며, <strong>SSTF에서 같은 거리가 나오는 경우 동률 처리 기준을 확인해야 한다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 흉부외과 또는 일반외과 의사 목록 출력하기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%ED%9D%89%EB%B6%80%EC%99%B8%EA%B3%BC-%EB%98%90%EB%8A%94-%EC%9D%BC%EB%B0%98%EC%99%B8%EA%B3%BC-%EC%9D%98%EC%82%AC-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%ED%9D%89%EB%B6%80%EC%99%B8%EA%B3%BC-%EB%98%90%EB%8A%94-%EC%9D%BC%EB%B0%98%EC%99%B8%EA%B3%BC-%EC%9D%98%EC%82%AC-%EB%AA%A9%EB%A1%9D-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0-Level-1</guid>
            <pubDate>Fri, 21 Aug 2026 02:21:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/ddbd2f85-31b5-4b23-9500-32b2e5ee6d7e/image.png" alt=""></p>
<p>정답 </p>
<pre><code>SELECT DR_NAME,DR_ID,MCDP_CD,HIRE_YMD FROM DOCTOR WHERE MCDP_CD=&#39;CS&#39; OR MCDP_CD=&#39;GS&#39; ORDER BY HIRE_YMD DESC, DR_NAME ASC;</code></pre><p>WHERE 절로 CS와 GS 둘 중 하나를 고르고,고용일자는 내림차순으로, 이름은 오름차순</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 상위 n개 레코드 - (Level 1)
]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%83%81%EC%9C%84-n%EA%B0%9C-%EB%A0%88%EC%BD%94%EB%93%9C-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%83%81%EC%9C%84-n%EA%B0%9C-%EB%A0%88%EC%BD%94%EB%93%9C-Level-1</guid>
            <pubDate>Thu, 20 Aug 2026 14:12:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/3db7edff-0b33-433a-a748-743d6911886a/image.png" alt=""></p>
<p>정답 </p>
<pre><code>SELECT NAME FROM ANIMAL_INS WHERE DATETIME=(SELECT MIN(DATETIME) FROM ANIMAL_INS);</code></pre><p>이번 문제에는 서브쿼리를 활용하면 더 빠르게 구현할 수 있을 것 같아 서브쿼리로 구현해보았습니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 가장 비싼 상품 구하 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EA%B0%80%EC%9E%A5-%EB%B9%84%EC%8B%BC-%EC%83%81%ED%92%88-%EA%B5%AC%ED%95%98-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EA%B0%80%EC%9E%A5-%EB%B9%84%EC%8B%BC-%EC%83%81%ED%92%88-%EA%B5%AC%ED%95%98-Level-1</guid>
            <pubDate>Tue, 11 Aug 2026 22:58:58 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/725abfe3-bffe-41f5-a955-5de796e90cbb/image.png" alt=""></p>
<p>코드 답</p>
<pre><code>SELECT MAX(PRICE) AS MAX_PRICE FROM PRODUCT;</code></pre><p>MAX로 가장 높은 판매가를 찾아내고, AS로 컬럼명을 수정한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 역순 정렬하기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-Level-1-u3yr8hy6</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-Level-1-u3yr8hy6</guid>
            <pubDate>Wed, 15 Jul 2026 23:44:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/7ab7453e-a3ed-40b9-b1ff-3cfd630e2a7e/image.png" alt=""></p>
<pre><code>SELECT COUNT(*) AS count FROM ANIMAL_INS;</code></pre><p>이미 동물 보호소에 들어온 동물들의 정보이기 때문에 릴레이션(테이블)의 
튜플(행)을 개수를 세도록 구현하였습니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 역순 정렬하기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-Level-1</guid>
            <pubDate>Mon, 13 Jul 2026 13:32:23 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/f00cd533-bddd-45ac-ab21-f78868aa41b0/image.png" alt=""></p>
<p>SQL 답</p>
<pre><code>SELECT ANIMAL_ID, NAME FROM ANIMAL_INS WHERE NAME LIKE &#39;%el%&#39; AND NAME LIKE &#39;%EL%&#39; AND ANIMAL_TYPE=&#39;Dog&#39; ORDER BY NAME, ANIMAL_ID;</code></pre><p>이름에 el이 들어있는 걸 LIKE으로 찾고 %el으로 하면 앞에 뭐가 오든 뒤에 el만 성립이 된다면 true. %el%으로 하면 el 문자 앞 뒤에 뭐가 오든 el만 있으면 성립이 된다. 하지만 LIKE는 대소문자를 구분하기 때문에 EL과 el을 넣었다. </p>
<p>그리고 동물의 타입은 dog이여야 하므로 Dog으로 저장되어있는 동물만 조회를 할 수 있게 구현하였습니다 :)</p>
<p>다른 분들의 풀이를 보면 LOWER(NAME)으로 LIKE를 한 번만 사용하는 가독성을 만들었지만 아직은 활용해보지 않았던 문법이라서 먼저 저의 방식대로 구현해보았습니다:) 감사합니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 역순 정렬하기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%97%AD%EC%88%9C-%EC%A0%95%EB%A0%AC%ED%95%98-Level-1</guid>
            <pubDate>Thu, 09 Jul 2026 23:47:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/d2dbfb16-483f-4054-a09d-ad4ceb83f9c4/image.png" alt=""></p>
<p>SQL 답</p>
<pre><code>-- 코드를 입력하세요
SELECT NAME,DATETIME FROM ANIMAL_INS ORDER BY ANIMAL_ID DESC;</code></pre><p>원하는 출력 NAME,DATETIME을 작성하고 ANIMAL_INS에서 ANIMAL_ID을 내림차순으로 정렬하게 만들면 역순이 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트][MySQL] 아픈 동물 찾기 - (Level 1)]]></title>
            <link>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%95%84%ED%94%88-%EB%8F%99%EB%AC%BC-%EC%B0%BE-Level-1</link>
            <guid>https://velog.io/@yeseo_052/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8MySQL-%EC%95%84%ED%94%88-%EB%8F%99%EB%AC%BC-%EC%B0%BE-Level-1</guid>
            <pubDate>Thu, 09 Jul 2026 23:17:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yeseo_052/post/c90abfd3-4b7b-47bf-9aff-69654a86b130/image.png" alt=""></p>
<p>SQL 답</p>
<pre><code>-- 코드를 입력하세요
SELECT ANIMAL_ID, NAME FROM ANIMAL_INS WHERE INTAKE_CONDITION LIKE &#39;Sick&#39;;</code></pre><p>원하는 출력 ANIMAL_ID, NAME을 ANIMAL_INS테이블에서 INTAKE_CONDITION Sick 아픈 동물만 출력하는 SQL 문을 만들었습니다 :)</p>
<blockquote>
<p>학교에서 MySQL 수업을 듣는데 코테로 실습을 해봤는데 
생각보다 쉬워서 놀랬다. AI 없이도 코딩할 수 있음에 뿌듯함을 느꼈습니다 &gt;&lt;</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 복귀작 DBP]]></title>
            <link>https://velog.io/@yeseo_052/TIL-%EB%B3%B5%EA%B7%80%EC%9E%91-DBP</link>
            <guid>https://velog.io/@yeseo_052/TIL-%EB%B3%B5%EA%B7%80%EC%9E%91-DBP</guid>
            <pubDate>Wed, 01 Jul 2026 12:43:20 GMT</pubDate>
            <description><![CDATA[<h2 id="테이블-생성">테이블 생성</h2>
<h3 id="primary-key-기본키">PRIMARY KEY (기본키)</h3>
<ul>
<li>중복 불가</li>
<li>NULL 불가</li>
<li>테이블에서 데이터를 구별하는 번호<pre><code>CREATE TABLE BOOK(
  BNO NUMBER PRIMARY KEY
);</code></pre><h3 id="foreign-key-외래키">FOREIGN KEY (외래키)</h3>
다른 테이블의 기본키를 참조<pre><code>BNO NUMBER,
FOREIGN KEY(BNO) REFERENCES BOOK(BNO)</code></pre>부모의 번호만 자식에서 사용할 수 있다.</li>
</ul>
<h3 id="on-delete-cascade">ON DELETE CASCADE</h3>
<p>&lt; 부모 삭제하면 자식도 같이 삭제 &gt;</p>
<pre><code>FOREIGN KEY(BNO)
REFERENCES BOOK(BNO)
ON DELETE CASCADE;</code></pre><h3 id="default">DEFAULT</h3>
<p>값을 안 넣으면 자동 입력</p>
<pre><code>RDATE DATE DEFAULT SYSDATE</code></pre><h3 id="unique">UNIQUE</h3>
<pre><code>SHOP_NAME VARCHAR2(50) UNIQUE</code></pre><p>Null은 가능하지만 중복은 금지</p>
<h2 id="테이블에-값-추가">테이블에 값 추가</h2>
<h3 id="insert">INSERT</h3>
<p>모든 컬럼 입력</p>
<pre><code>INSERT INTO BOOK
VALUES(1,&#39;SQL&#39;,&#39;홍길동&#39;,20000);</code></pre><p>일부 컬럼만</p>
<pre><code>INSERT INTO BOOK(BNO,TITLE)
VALUES(2,&#39;데이터베이스&#39;);</code></pre><h2 id="테이블-값-조회">테이블 값 조회</h2>
<pre><code>SELECT *
FROM BOOK;</code></pre><p>전체 조회가 아닌 원하는 값만 조회하고 싶다면 * =&gt; 대신 일부 컬럼을 작성</p>
<h2 id="where-조건">WHERE 조건</h2>
<p>같다 표현</p>
<pre><code>WHERE PRICE=10000</code></pre><p>크기 비교</p>
<pre><code>WHERE PRICE&gt;=20000</code></pre><h4 id="between">BETWEEN</h4>
<pre><code>WHERE PRICE
BETWEEN 10000 AND 20000</code></pre><p>범위 측정할 때 자주 사용</p>
<h4 id="in">IN</h4>
<p>여러개의 카테고리 중에 속하는 애들만 조회</p>
<pre><code>WHERE CATEGORY
IN(&#39;치킨&#39;,&#39;커피&#39;)</code></pre><h4 id="like">LIKE</h4>
<p>% &lt;- 앞뒤 뭐가 있든 상관 없음
__ &lt;-갯수가 정해져있음</p>
<h2 id="정렬">정렬</h2>
<h4 id="오름차순">오름차순</h4>
<p>ORDER BY PRICE ASC;</p>
<h4 id="내림차순">내림차순</h4>
<p>ORDER BY PRICE DESC;</p>
<h3 id="join">JOIN</h3>
<pre><code>SELECT R.SNAME,
       B.TITLE
FROM RENTAL R
JOIN BOOK B
ON R.BNO=B.BNO;</code></pre><h2 id="집계함수">집계함수</h2>
<ul>
<li>COUNT(개수)</li>
<li>SUM(합계)</li>
<li>AVG(평균)</li>
<li>MAX(최대)</li>
<li>MIN(최소)</li>
</ul>
<h4 id="group-by">GROUP BY</h4>
<p>같은 것끼리 묶기</p>
<pre><code>SELECT CATEGORY,
COUNT(*)
FROM SHOP
GROUP BY CATEGORY;</code></pre><h3 id="having">HAVING</h3>
<p>GROUP BY 이후 조건</p>
<pre><code>GROUP BY CATEGORY
HAVING COUNT(*)&gt;=2;</code></pre><p>**WHERE → 일반 조건</p>
<p>HAVING → 집계 조건**</p>
<h2 id="update-수정">UPDATE 수정</h2>
<pre><code>UPDATE BOOK
SET PRICE=15000
WHERE BNO=1;</code></pre><h2 id="delete">DELETE</h2>
<pre><code>DELETE
FROM BOOK
WHERE BNO=1;</code></pre><p>WHERE 안 쓰면 전부 삭제</p>
<h3 id="alter-table">ALTER TABLE</h3>
<p>테이블 수정</p>
<pre><code>ALTER TABLE MOVIE
MODIFY GENRE VARCHAR2(100);</code></pre><h3 id="서브쿼리">서브쿼리</h3>
<p>쿼리 안의 쿼리</p>
<pre><code>SELECT *
FROM BOOK
WHERE PRICE=
( SELECT MIN(PRICE) FROM BOOK );</code></pre><h3 id="fetch-first">FETCH FIRST</h3>
<p>상위 N개
ex) Top5 가져오기</p>
<pre><code>ORDER BY PRICE DESC
FETCH FIRST 5 ROWS ONLY;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[TIL Spring 최종정리]]></title>
            <link>https://velog.io/@yeseo_052/TIL-ti5h5qkl</link>
            <guid>https://velog.io/@yeseo_052/TIL-ti5h5qkl</guid>
            <pubDate>Wed, 29 Apr 2026 04:42:38 GMT</pubDate>
            <description><![CDATA[<p><strong>Spring Framework란?</strong></p>
<ol>
<li>자바 기반 응용 프로그램 개발 프레임워크</li>
<li>2003년 6월 Rod Johnson 발표</li>
<li>모든 Java 애플리케이션 개발 이용 ㄱㄴ</li>
<li>Java EE 기반 웹 애플리케이션 개발</li>
</ol>
<table>
<thead>
<tr>
<th></th>
<th>스프링프레임워크</th>
<th>스프링부트</th>
</tr>
</thead>
<tbody><tr>
<td>특징</td>
<td>IOC, DI, AOP</td>
<td>auto/내장서버</td>
</tr>
<tr>
<td>복잡도</td>
<td>설정 복잡</td>
<td>최소한의 설정</td>
</tr>
<tr>
<td>프젝go</td>
<td>수동으로 설정</td>
<td>initalizer 프젝 생성</td>
</tr>
<tr>
<td>배포</td>
<td>외부서버 배포</td>
<td>내장서버 인한 단독 실행 가능</td>
</tr>
</tbody></table>
<p>⇒ Spring Framework는 기반 기술, Spring Boot는 Spring을 더 쉽고 빠르게 쓰게 해주는 도구다. </p>
<hr>
<h4 id="spring-framework">Spring Framework</h4>
<ul>
<li><p>경량 컨테이너</p>
</li>
<li><p>POJO 방식</p>
</li>
<li><p><strong>IoC 지원 (제어의 역전) &lt;개념&gt;</strong></p>
<ul>
<li><p>객체생성이나 관리 그런 부분이 Spring이 다 해줌. 개발자는 그걸 요청하는 코딩만 하면 되는 것. (예전에는 객체생성이나 관리까지 개발자가 함)</p>
</li>
<li><p>제어의 역전</p>
</li>
<li><p>스프링 컨테이너 객체 생성</p>
</li>
<li><p>개발 효율성(up) 유지보수 용이</p>
</li>
<li><p>*&lt;주요 특징&gt;**</p>
<p>→ 객체 생성, 초기화 자동 관리</p>
<p>→ 의존 관계를 자동으로 연결 편리 제공</p>
<p>→ 유연한 구조로 설정 변경 용이</p>
<p>→ 낮은 결합도로 유지보수 용이</p>
<p>⇒IoC는 매니저(소속사)가 있다는 느낌 (직접스케줄관리X)</p>
</li>
</ul>
</li>
<li><p>DI 지원 (의존성 주입)</p>
<p>  <strong>1)</strong> 생성자 <strong>DI (Constructor DI)
  2) setterDI</strong></p>
</li>
<li><p>AOP 지원</p>
<p>  공통으로 들어가는 것을 (횡단관심)
  횡단관심은 : 공통기능 → spring이 관리함
  필요한 핵심 기능 (종단관심)
  종단관심: 핵심기능 → 개발자가 관리함.</p>
</li>
</ul>
<hr>
<h2 id="다형성">다형성</h2>
<p>자바에서의 모든 객체는 부모클 참조변수나 구현한 인터페이스 변수에 담을 수 있다. ⇒ 이러한 참조변수를 통해 메서드를 호출하면 오버라이딩된 메서드가 호출된다.</p>
<p>Spring Framework 장점</p>
<ul>
<li>코드량 감소</li>
<li>생산성 향상</li>
<li>유지보수 쉬움</li>
<li>의존성 관리 편함 (DI)</li>
<li>재사용성 높음</li>
</ul>
<hr>
<h2 id="빌드도구">빌드도구</h2>
<ul>
<li>소스코드를 컴파일부터 배포까지의 전 과정을 자동으로 실행시켜주는 도구*</li>
</ul>
<ol>
<li>빌드 자동화는 소프트웨어 개발의 효율성을 높이는 중요한 과정</li>
<li>필요한 라이브러리를 다운로드 </li>
<li>코드 컴파일, 자동으로 테스트 실행 후</li>
<li>실행 파일을 생성, 배포
5<strong>. Maven(pom.xml) / gradle (build.gradle)</strong></li>
</ol>
<p>스프링은 요리사 개발자는 사장넴</p>
<p><strong>spring application에 필요한 라이브러리: spring-context</strong></p>
<p>스프링의 maven 라이브러리들이 모아져 있는 곳에서 다운받아야함.</p>
<p><strong>Java에서 class 에서 활용되는 get set이 Spring에서는 getBean()이런 느낌으로 활용이 된다.</strong></p>
<hr>
<h3 id="maven-핵심-한-줄">Maven 핵심 한 줄</h3>
<p> XML 기반으로 프로젝트 빌드와 라이브러리를 자동 관리하는 도구</p>
<ul>
<li>자바 프로젝트 <strong>빌드 자동화 도구</strong></li>
<li><strong>XML</strong>로 설정을 관리한다</li>
<li>라이브러리를 <strong>자동으로 다운로드</strong>한다</li>
<li>프로젝트 <strong>라이프사이클 관리</strong> 가능</li>
<li><strong>Apache(아파치)</strong>에서 개발</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>Maven</th>
<th>Grable</th>
</tr>
</thead>
<tbody><tr>
<td>비유</td>
<td>공공기관 메뉴얼식 운명</td>
<td>스타트업식 자동화</td>
</tr>
<tr>
<td>특징</td>
<td>정해진 규칙</td>
<td>자유도 높음</td>
</tr>
<tr>
<td>설정</td>
<td>XML</td>
<td>Groovy/ Kotilin</td>
</tr>
<tr>
<td>속도</td>
<td>보통</td>
<td>빠름</td>
</tr>
</tbody></table>
<p><strong>IoC 컨테이너</strong> : 객체 생성과 의존성 관리를 수행하는 스프링의 핵심 구성 요소</p>
<ul>
<li><strong>IoC(Inversion of Control)</strong> : 객체 생성과 관리의 제어권이 개발자가 아닌 프레임워크에 있는 것</li>
<li>개발자가 객체를 직접 생성하지 않고, 프레임워크가 생성한 객체를 주입받아 사용한다.</li>
<li>스프링에서는 IoC 컨테이너가 객체 생성과 의존성 주입을 담당한다.</li>
</ul>
<p><strong>POJO Class</strong></p>
<ul>
<li>POJO (Plain Old Java Object) : 자바 모델이나, 기능, 프레임워크 등에 따르지 않고 홀로 독립적이며 단순한 기능만을 가진 객체들을 의미한다.</li>
<li>자바에서는 이러한 객체들을 Bean이라고 부른다.</li>
<li>단순히, 데이터의 저장기능만 있다.</li>
</ul>
<p>Spring Bean 객체 생성</p>
<ul>
<li>Spring에서는 사용할 Bean 객체를 configuration file에 정의를 하고, 필요할 때 객체를 가져와 사용하는 방법을 이용한다.</li>
<li>bean 태그 : 사용할 Bean을 정의하는 태그</li>
</ul>
<hr>
<p>인터페이스</p>
<ol>
<li>다형성(polymorphism) 
부모의 참조변수로 자식객체를 생성한다.</li>
</ol>
<ul>
<li>코드 수정이 용이하다.</li>
</ul>
<ol start="2">
<li>상수</li>
<li>추상메서드</li>
</ol>
<hr>
<p>MVC(Model,View,Controller)</p>
<ol>
<li>Model(모델): 데이터 (주로 데이터베이스에 있는 데이터)</li>
<li>View : 사용자에게 보여주는 것(UI)<pre><code>  - 템플릿 엔진을 사용해서 예쁘게 꾸며준다. (타임리프 사용)</code></pre></li>
<li>Controller : 실제 일을 하는 애 (비즈니스 로직 처리)</li>
</ol>
<p>*** dispatcher Servlet: 모든 요청을 받아서 적절한 controller에 보내는 애</p>
<p>MVC 장점 </p>
<p>분업화: 요리사(모델)가 바뀌어도 서빙 방식(컨트롤러)은 그대로 유지</p>
<p>유지보수: &quot;접시만 바꾸고 싶어(뷰 수정)&quot; 할 때 요리 방법(모델)을 건드릴 필요가 없음</p>
<p>유연성: 같은 요리(데이터)를 접시에도 담을 수 있고, 포장 박스(다양한 뷰)에도 담을 수 있음</p>
<hr>
<ul>
<li><strong>@SpringBootApplication:</strong> 컴포넌트 스캔 + 자동 설정을 포함한 핵심 어노테이션</li>
<li><strong>@Component:</strong> 컨테이너에 빈(Bean) 객체로 자동 등록</li>
<li><strong>@Autowired:</strong> 타입에 맞춰 의존성을 자동으로 주입<ul>
<li>기본형(@Value)은 아니고, <strong>참조형에만 적용됨</strong></li>
<li>타입을 보고 자동주입</li>
</ul>
</li>
<li><strong>@Qualifier(”이름”)</strong><ul>
<li>같은 클래스의 객체를 여러 개 만들 수 있다</li>
</ul>
</li>
<li><strong>static / templates:</strong> 정적 파일(JS, CSS)과 타임리프(HTML) 템플릿 보관 폴더</li>
</ul>
<hr>
<p>@SpringBootApplication</p>
<ol>
<li>@component-scan : 클래스들을 스캔해서 반으로 만들어서 컨테이너에 보관</li>
</ol>
<hr>
<p>사용자가 입력한 데이터를 받아오는 방법</p>
<ol>
<li>HttpsServletRequest</li>
<li>WebRequest</li>
<li>@RequestParam : 1개씩 변수를 받는다.</li>
<li>@PathVariable : restAPI에서 사용. 폴더가 아니라 데이터로 인식하고 싶을 때 사용한다.</li>
<li>@ModelAttribute :  + dto가 있어야 함(POJO 클래스 : 멤버변수+set/get만 있는 거) 
클래스의 멤버변수 이름 :  요청되는 변수명하고 반드시 일치해야함.</li>
</ol>
<p>@ResponseBody이란? 
return “abc”;
⇒ abc.html파일로 인식하는 것이 아니라, 단순 문자열로 인식하여 그대로 브라우저에 실행</p>
<hr>
<p>springboot 주요 파일</p>
<ul>
<li>static 폴더: 정적파일 보관(html, css,js, image)</li>
<li>templates: 타임리프 파일이 존재하는 폴더</li>
</ul>
<hr>
<p>@springbooApplication (1+2번을 포함하는 어노테이션)</p>
<ol>
<li><p>&lt;context:component-scan basePackgages=“kr.hs.study.beans”/&gt; 
kr.hs.study.beans패키지아래에 있는 클래스들을 스캔해서 어노테이션을 분석한 후, 객체 생성하고, 컨테이너에 보관해라!</p>
</li>
<li><p>프로젝트 실행에 필요한 기본적인 bean 들을 생성한 후, 객체에 보관해라</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL spring 정리]]></title>
            <link>https://velog.io/@yeseo_052/TIL-spring-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@yeseo_052/TIL-spring-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 27 Apr 2026 14:32:40 GMT</pubDate>
            <description><![CDATA[<p>Spring Framework란?</p>
<ol>
<li>자바 기반 응용 프로그램 개발 프레임워크</li>
<li>2003년 6월 Rod Johnson 발표</li>
<li>모든 Java 애플리케이션 개발 이용 ㄱㄴ</li>
<li>Java EE 기반 웹 애플리케이션 개발</li>
</ol>
<table>
<thead>
<tr>
<th></th>
<th>스프링프레임워크</th>
<th>스프링부트</th>
</tr>
</thead>
<tbody><tr>
<td>특징</td>
<td>IOC, DI, AOP</td>
<td>auto/내장서버</td>
</tr>
<tr>
<td>복잡도</td>
<td>설정 복잡</td>
<td>최소한의 설정</td>
</tr>
<tr>
<td>프젝go</td>
<td>수동으로 설정</td>
<td>initalizer 프젝 생성</td>
</tr>
<tr>
<td>배포</td>
<td>외부서버 배포</td>
<td>내장서버 인한 단독 실행 가능</td>
</tr>
</tbody></table>
<p>⇒ Spring Framework는 기반 기술, Spring Boot는 Spring을 더 쉽고 빠르게 쓰게 해주는 도구다. </p>
<h4 id="spring-framework">Spring Framework</h4>
<ul>
<li><p>경량 컨테이너</p>
</li>
<li><p>POJO 방식</p>
</li>
<li><p><strong>IoC 지원 (제어의 역전)</strong></p>
<ul>
<li><p>객체생성이나 관리 그런 부분이 Spring이 다 해줌. 개발자는 그걸 요청하는 코딩만 하면 되는 것. (예전에는 객체생성이나 관리까지 개발자가 함)</p>
</li>
<li><p>제어의 역전</p>
</li>
<li><p>스프링 컨테이너 객체 생성</p>
</li>
<li><p>개발 효율성(up) 유지보수 용이</p>
<p>&lt;주요 특징&gt;</p>
<p>→ 객체 생성, 초기화 자동 관리</p>
<p>→ 의존 관계를 자동으로 연결 편리 제공</p>
<p>→ 유연한 구조로 설정 변경 용이</p>
<p>→ 낮은 결합도로 유지보수 용이</p>
<p>⇒IoC는 매니저(소속사)가 있다는 느낌</p>
</li>
</ul>
</li>
<li><p>DI 지원</p>
</li>
<li><p>AOP 지원</p>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>