<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>snowlight-aemt.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 30 Oct 2023 12:12:59 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>snowlight-aemt.log</title>
            <url>https://velog.velcdn.com/images/snowlight-aemt/profile/920e11ca-a131-430a-9da4-6c3da3d9bae5/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. snowlight-aemt.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/snowlight-aemt" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Datagrid 설정]]></title>
            <link>https://velog.io/@snowlight-aemt/Datagrid-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@snowlight-aemt/Datagrid-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Mon, 30 Oct 2023 12:12:59 GMT</pubDate>
            <description><![CDATA[<h2 id="datagrid-에-옵션을-설정-정리">Datagrid 에 옵션을 설정 정리</h2>
<h3 id="datagrid-결과-조회-때-쿼리-밑에-조회를-하위-위치로-변경">Datagrid 결과 조회 때 쿼리 밑에 조회를 하위 위치로 변경.</h3>
<h4 id="in-editor-results">In Editor Results</h4>
<p>아래 이미지에 <code>playground</code> 오른쪽에 위치하는 <strong>버튼</strong>을 비활성화.
<img src="https://velog.velcdn.com/images/snowlight-aemt/post/92c2c6f0-0539-4b0c-a52c-9b667e0f9bbd/image.png" alt="in_editor">
<a href="https://www.jetbrains.com/help/datagrip/viewing-query-results.html#in_editor_results">https://www.jetbrains.com/help/datagrip/viewing-query-results.html#in_editor_results</a></p>
<hr>
<hr>
<hr>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Swagger 자바 버전 에러]]></title>
            <link>https://velog.io/@snowlight-aemt/Spring-Swagger-%EC%9E%90%EB%B0%94-%EB%B2%84%EC%A0%84-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@snowlight-aemt/Spring-Swagger-%EC%9E%90%EB%B0%94-%EB%B2%84%EC%A0%84-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Tue, 15 Aug 2023 05:21:02 GMT</pubDate>
            <description><![CDATA[<h2 id="이슈">이슈</h2>
<h3 id="스택">스택</h3>
<ul>
<li>spring boot 2.7.14</li>
<li>springdoc-openapi 2.2.0</li>
<li>java 11<h3 id="gradle-의존성">Gradle 의존성</h3>
<pre><code>plugins {
  id &#39;java&#39;
  id &#39;org.springframework.boot&#39; version &#39;2.7.14&#39;
  id &#39;io.spring.dependency-management&#39; version &#39;1.0.15.RELEASE&#39;
}
</code></pre></li>
</ul>
<p>dependencies {
    implementation &#39;org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0&#39;
}</p>
<pre><code>### 로그</code></pre><p>Caused by: java.lang.UnsupportedClassVersionError: 
org/springdoc/core/conditions/MultipleOpenApiSupportCondition has been compiled by a more recent version of the Java Runtime (class file version 61.0), 
this version of the Java Runtime only recognizes class file versions up to 55.0</p>
<pre><code>### 로그 확인
**class file version 61.0** 이상의 버전을 사용하지 않아서 생긴 이슈. (java se 17 = 61)

## 이슈 해결
**Springdoc Openapi** 라이브러리은 Spring boot 버전마다 정해진 라이브러리를 받아서 사용해야 한다.
Spring Boot 2 이하에 경우 springdoc-openapi v1.7.0 라이브러리 적용해야 정상적으로 기동할 수 있음.
</code></pre><p>plugins {
    id &#39;java&#39;
    id &#39;org.springframework.boot&#39; version &#39;2.7.14&#39;
    id &#39;io.spring.dependency-management&#39; version &#39;1.0.15.RELEASE&#39;
}</p>
<p>dependencies {
    implementation &#39;org.springdoc:springdoc-openapi-ui:1.7.0&#39;
}</p>
<pre><code>
**spring boot 2 버전 이하**
[Springdoc-openapi v1.7.0](https://springdoc.org/v1/)

**spring boot 3 버전 이상**
[Springdoc-openapi v2.2.0](https://springdoc.org)



### 참고 자료
자바 바이트코드 버전 https://javaalmanac.io/bytecode/versions/



</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[URL 목록 (공부)]]></title>
            <link>https://velog.io/@snowlight-aemt/URL-%EB%AA%A9%EB%A1%9D-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@snowlight-aemt/URL-%EB%AA%A9%EB%A1%9D-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Mon, 15 May 2023 14:30:17 GMT</pubDate>
            <description><![CDATA[<h1 id="transaction">Transaction</h1>
<p><a href="https://zzang9ha.tistory.com/381#:~:text=%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98%20%EA%B2%A9%EB%A6%AC%20%EC%88%98%EC%A4%80(Isolation%20level)%EC%9D%B4%EB%9E%80%20%EB%8F%99%EC%8B%9C%EC%97%90%20%EC%97%AC%EB%9F%AC%20%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98,%EB%A5%BC%20%EA%B2%B0%EC%A0%95%ED%95%98%EB%8A%94%20%EA%B2%83%EC%9E%85%EB%8B%88%EB%8B%A4.">Isolation Level</a>
<a href="https://techblog.woowahan.com/2664/">HikariCP Dead lock에서 벗어나기 (이론편)</a>
<a href="https://techblog.woowahan.com/2631/">MySQL을 이용한 분산락으로 여러 서버에 걸친 동시성 관리</a>
<a href="https://way-be-developer.tistory.com/291">mysql-deadlock</a>
<a href="https://devhooney.tistory.com/110">concurrency-issue</a>
<a href="https://hoing.io/archives/4182">mysql-real</a></p>
<h1 id="etc">ETC</h1>
<p><a href="https://zzang9ha.tistory.com/393">월간 코드리뷰</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transaction (작성 중)]]></title>
            <link>https://velog.io/@snowlight-aemt/Transaction</link>
            <guid>https://velog.io/@snowlight-aemt/Transaction</guid>
            <pubDate>Mon, 15 May 2023 14:25:42 GMT</pubDate>
            <description><![CDATA[<h2 id="격리-명령어-isolation">격리 명령어 (ISOLATION)</h2>
<p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html</a></p>
<pre><code class="language-sql">-- 세션 확인
SHOW FULL processlist;

-- 격리 레벨 설정
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 현재 레벨 확인
SHOW VARIABLES WHERE VARIABLE_NAME like &#39;%transaction_isolation%&#39;;</code></pre>
<h2 id="lock-조회">lock 조회</h2>
<p>8 버전 이전</p>
<pre><code class="language-sql"># LOCK을 걸고 있는 프로세스 정보
select * from information_schema.INNODB_TRX;

# 현재 LOCK이 걸려 대기중인 정보
# select * from information_schema.INNODB_LOCK_WAITS;
select * from performance_schema.data_lock_waits;

# LOCK을 건 정보
# select * from  information_schema.INNODB_LOCKS;
select A.LOCK_MODE, A.* from performance_schema.data_locks A;
show open tables where In_Use &gt; 0 ;</code></pre>
<p>8 버전 이후
<a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html</a></p>
<pre><code class="language-sql">select * from performance_schema.data_locks;
select * from performance_schema.metadata_locks;
select * from performance_schema.data_lock_waits;
select * from performance_schema.table_lock_waits_summary_by_table;</code></pre>
<h2 id="lock-획득">Lock 획득</h2>
<p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html">https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html</a></p>
<h3 id="locking-reads">Locking Reads</h3>
<pre><code class="language-sql">-- 읽기 락
select * from item_order where item_id = 2 for share
-- 쓰기 락
select * from item_order where item_id = 2 for update</code></pre>
<h4 id="for-share-vs-for-update">for share vs for update</h4>
<p><code>share</code>, <code>update</code> 는 다른 트랜잭션 A, B 에서 <code>select</code> 로 조회를 할 수 있는지에 차이점이 있다.
(일반적인 select 이 아닌 select for share, select for update)</p>
<ul>
<li>share : select 를 제외한 명령어(insert, update, delete) 에 락에 걸린다. </li>
<li>update : select, insert, update, delete</li>
</ul>
<p>❓<code>for share</code> 를 언제 사용할까?
현재 조회된 데이터의 무결성을 유지할 수 있다. (물론 트랜잭션 범위 안에서)
🔥 IMO) 예를 들면 order 를 <strong>조회</strong>하고 <strong>업데이트</strong>를 할 때는 <code>for update</code> 를 사용해야 한다.
하지만 order 를 <strong>조회</strong>하여 <strong>다른 테이블의 업데이트</strong>로 사용된다면 <strong>order의 select 락</strong> 은 필요하지 않다.
(update 할 때 select 에 락을 거는 이유를 생각해 보자. (동시성 이슈))</p>
<p>❓❓그러면 <code>for update</code> 를 사용하면 되지 않을까?
물로 <code>for share</code> 대신에 사용해도 상관이 없다. 당연하지만 select 까지 락이 걸리기 때문에 보다 더 성능이 좋지 않다.</p>
<h3 id="name-lock-획득">name lock 획득</h3>
<pre><code class="language-sql">-- 락 획득
SELECT GET_LOCK(&#39;jade-1&#39;, 10);
-- jade-1 이라는 문자열로 잠금을 획득하며
-- 이미 잠금이 있다면 10초간 대기하고 락 확득을 포기.

-- 락 상태 조회
SELECT IS_FREE_LOCK(&#39;jade-1&#39;);
-- 문자열 &#39;jade-1&#39; 에 대해서 획득 가능한지를 확인 합니다.
-- 반환 값: 1 사용 가능한, 0 사용이 불가능

SELECT IS_USED_LOCK(&#39;jade-1&#39;);
-- 문자열 jade-1 이 잠금이 설정되어 있는지 확인합니다.
-- 반환 값: 사용 중이면 잠금을 보유한 세션 식별자


-- 잠금해제 명령어
SELECT RELEASE_LOCK(&#39;jade-1&#39;);
-- 반환 값: 1 정상 해제
select RELEASE_ALL_LOCKS();
-- 반환 값: 해제한 Lock 의 수 (0 이면 없다는 뜻)


SELECT CONNECTION_ID();
-- 반환 값: 현재 세션(연결 아이디) 식별자

-- 세션 조회 명령어
show full processlist;</code></pre>
<h3 id="transaction">transaction</h3>
<pre><code class="language-sql">-- 오토커밋 유무 확인 및 세팅
SELECT @@AUTOCOMMIT;
-- Auto Commit 켜기
SET AUTOCOMMIT = 1;
-- Auto Commit 끄기
SET AUTOCOMMIT = 0;


START TRANSACTION;
-- Upudate Insert Delete Select
COMMIT;
ROLLBACK;</code></pre>
<h2 id="acid">ACID</h2>
<h3 id="atomicity-원자성">Atomicity (원자성)</h3>
<ul>
<li>ALL or Nothing</li>
<li>transaction 은 논리적으로 쪼개질 수 없는 작업 단위.</li>
</ul>
<h3 id="consistency-일관성">Consistency (일관성)</h3>
<ul>
<li><strong>transaction 은 DB 상태를 consistent 상태에서 또 다른 consistent 상태로 바꿔줘야 한다.</strong></li>
<li><strong>일관성(constraints, trigger 등...) 이 깨지는 경우 rollback.</strong></li>
<li>transaction 이 DB 에 정의된 rule 을 위반했는지는 DBMS 가 commit 전에 확인하고 알려준다.</li>
<li>그 외에 application 관점에서 transaciton 이 consistent 하게 동작하는지는 개발자가 챙겨야 한다. (DB rule 이 아닌 - db transaction 를 벗어나는 규칙 )</li>
</ul>
<h3 id="isolation-격리-분리">Isolation (격리, 분리)</h3>
<ul>
<li>여러 transaction 들이 동시에 실행하니 문제가 발생.</li>
<li>여러 transaction 들이 동시에 실행될 때도 혼자 실행되는 것 처럼 동작하게 만든다.</li>
<li>concurrency control 의 주된 목표가 isolation 이다.</li>
</ul>
<h3 id="durability-영존성">Durability (영존성)</h3>
<ul>
<li>commit 된 transaction 은 DB 에 영구적으로 저장된다.</li>
<li>&quot;영구적으로 저장한다.&quot; 라고 할 때는 일반적으로 비휘발성 메모리(HDD, SSD, ...) 에 저장함을 의미한다.</li>
<li>기본적으로 transaction 의 durability 는 dbms 가 보장한다.</li>
</ul>
<hr>
<h2 id="참고-url">참고 URL</h2>
<p><a href="https://labs.brandi.co.kr//2019/06/19/hansj.html">https://labs.brandi.co.kr//2019/06/19/hansj.html</a>
<a href="https://myinfrabox.tistory.com/188">https://myinfrabox.tistory.com/188</a>
<a href="https://jyeonth.tistory.com/32">https://jyeonth.tistory.com/32</a>
<a href="https://www.youtube.com/watch?v=bLLarZTrebU&amp;list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&amp;index=17">https://www.youtube.com/watch?v=bLLarZTrebU&amp;list=PLcXyemr8ZeoREWGhhZi5FZs6cvymjIBVe&amp;index=17</a></p>
<h3 id="mysql">mysql</h3>
<p><a href="https://dev.mysql.com/doc/refman/5.7/en/show-processlist.html">https://dev.mysql.com/doc/refman/5.7/en/show-processlist.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TCP 는 상태유지 프로토콜이고, HTTP 은 무상태 프로토콜이다.]]></title>
            <link>https://velog.io/@snowlight-aemt/tcp-http</link>
            <guid>https://velog.io/@snowlight-aemt/tcp-http</guid>
            <pubDate>Mon, 15 May 2023 10:25:23 GMT</pubDate>
            <description><![CDATA[<h3 id="tcp-는-상태유지-프로토콜이고-http-은-무상태-프로토콜이다">TCP 는 상태유지 프로토콜이고, HTTP 은 무상태 프로토콜이다.</h3>
<p>HTTP 도 결국은 TCP 로 통신(동작) 을 하는데 왜 한 쪽은 Statefull 이고 다른쪽은 Stateless 일까?</p>
<ul>
<li>TCP 는 3way 통신을 하면서 서버에 세션 정보를 저장하여 서버와 클라이언트를 신뢰할 수 있는 상태로 상태를 유지하면 데이터를 전달하므로 상태유지 프로토콜이다.</li>
<li>HTTP 도 TCP 를 사용하기 때문에 동일하게 3way 통신을 한다. 하지만 HTTP 프로토콜 라는 큰 관점에서 봤을 때 HTTP 는 무상태 이다. (요청(TCP) 당 상태를 보존하지 HTTP 통신이 상태를 보존하지 않는다.)<ul>
<li>이전에 HTTP 요청을 저장하고 있지는 않는다.</li>
<li>상태를 저장하지 않기 때문에 로그인시 쿠키, 세션 같은 부과적인 것들이 필요하다. (자원)</li>
</ul>
</li>
</ul>
<h3 id="참고-자료">참고 자료</h3>
<p><a href="https://roy-jang.tistory.com/87">[Network] HTTP 통신은 Stateless가 맞을까?</a></p>
<p><a href="https://ojt90902.tistory.com/642">HTTP의 Stateless, 비연결성</a></p>
<p><a href="https://www.itorian.com/2012/09/tcp-is-stateful-protocol-and-http-is.html">TCP is a STATEful protocol and HTTP is a STATEless protocol, why?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Oracle 연동 에러]]></title>
            <link>https://velog.io/@snowlight-aemt/Oracle-%EC%97%B0%EB%8F%99-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@snowlight-aemt/Oracle-%EC%97%B0%EB%8F%99-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Mon, 08 May 2023 05:18:23 GMT</pubDate>
            <description><![CDATA[<pre><code>(node:8175) UnhandledPromiseRejectionWarning: Error: DPI-1047: Cannot locate a 64-bit Oracle Client library: &quot;libclntsh.so: cannot open shared object file: No such file or directory&quot;. See https://oracle.github.io/node-oracledb/INSTALL.html for help
Node-oracledb installation instructions: https://oracle.github.io/node-oracledb/INSTALL.html
You must have 64-bit Oracle Client libraries configured with ldconfig, or in LD_LIBRARY_PATH.
If you do not have Oracle Database on this computer, then install the Instant Client Basic or Basic Light package from
https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html

    at OracleDb.getConnection (/web/nodejs-knex-express/node_modules/oracledb/lib/oracledb.js:354:25)
    at OracleDb.getConnection (/web/nodejs-knex-express/node_modules/oracledb/lib/util.js:192:10)
    at /web/nodejs-knex-express/node_modules/knex/lib/dialects/oracledb/index.js:150:21
    at new Promise (&lt;anonymous&gt;)
    at Client_Oracledb.acquireRawConnection (/web/nodejs-knex-express/node_modules/knex/lib/dialects/oracledb/index.js:124:29)
    at create (/web/nodejs-knex-express/node_modules/knex/lib/client.js:254:39)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:8175) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 6)
(node:8175) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.</code></pre><h3 id="oracle-client-설치">Oracle Client 설치</h3>
<p>일부러 낮은 버전으로 다운로드 받아서 테스트 진행 
(사용하는 오라클 버전이 많이 낮아서 혹시 몰라서...)
<a href="https://www.oracle.com/database/technologies/instant-client/downloads.html">오라클 클라이언트 설치</a></p>
<h3 id="라이브러리-설치-명령어">라이브러리 설치 명령어</h3>
<p>인터넷에서 찾았을때는 아래 파일 설치를 진행하라고 나왔는데;
우분투에서는 해당 패키지가 없다고 나옴.
<code>apt-get install libaio</code> </p>
<pre><code>Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package libaio</code></pre><p><code>apt search libaio</code> 로 찾아보니 비슷한 패키지(<code>libaio1</code>)를 확인
<code>apt-get install libaio1</code></p>
<h3 id="경로-설정">경로 설정</h3>
<p>아래에 경로 위에서 설치한 오라클 클라이언트 압축파일을 설치
&#39;/opt/oracle/`</p>
<h3 id="환경-변수">환경 변수</h3>
<p><code>vim ~/.bashrc</code> 명령어를 사용해서 오라클에서 사용하는 환경 변수 저장</p>
<pre><code class="language-bash">export TNS_ADMIN=
export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2</code></pre>
<h2 id="참고">참고</h2>
<p><a href="https://askubuntu.com/questions/227791/how-do-i-install-libaio">https://askubuntu.com/questions/227791/how-do-i-install-libaio</a></p>
<pre><code>echo env
unset 변수명</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Batch Processing 일관 처리]]></title>
            <link>https://velog.io/@snowlight-aemt/%EB%8B%A8%EA%B1%B4-%EC%9D%BC%EA%B4%84-%EC%A0%80%EC%9E%A5-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@snowlight-aemt/%EB%8B%A8%EA%B1%B4-%EC%9D%BC%EA%B4%84-%EC%A0%80%EC%9E%A5-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Sun, 07 May 2023 23:54:36 GMT</pubDate>
            <description><![CDATA[<h1 id="jdbc-batch">JDBC Batch</h1>
<h2 id="단-건-처리">단 건 처리</h2>
<p>일반적으로 데이터를 추가/수정 할 때, DB 로 SQL 를 전송하기 위해서 매번 네트워크 통신하며 비용을 발생 시킨다.</p>
<ul>
<li>네트워크 통신은 고 비용이 때문에 백만, 천만 단위를 데이터를 처리할 때 일반적인 단 건으로 처리하면 많은 리소스를 낭비하게 된다.</li>
<li>또한 처리 시간이 늦어나기 때문에 쓰레드 점유 시간이 길어지면 웹 서버에 요청 처리 건수가 늦아진다.</li>
</ul>
<h3 id="사용-예시-코드">사용 예시 코드</h3>
<pre><code class="language-java">@Transactional
@Override
public void saveAll(List&lt;Product&gt; products) {

    String sql = &quot;insert into product (title, created_ts, price) values (?, ?, ?)&quot;;
    for (Product product : products) {
        this.jdbcTemplate.update(sql,
            ps -&gt; {
                ps.setString(1, product.getTitle());
                ps.setTimestamp(2, Timestamp.valueOf(product.getCreatedTs()));
                ps.setBigDecimal(3, product.getPrice());
            }
        );
    }
}</code></pre>
<h2 id="일관-처리">일관 처리</h2>
<p>따라서 이러한 많은 량의 데이터(Sql)를 보낼 때 매번 요청을 하나씩 보내는게 아니라 묶어서 처리할 수 있는 <code>Bulk Sql</code> 를 제공한다.</p>
<ul>
<li>묶어서 처리하기 때문에 네트워크를 통하는 전송하는 횟수가 줄어든다. 따라서 고 비용인 네트워크 통신이 줄어들기 때문에 처리 시간을 단축할 수 있게된다.</li>
</ul>
<h3 id="사용-예시-코드-1">사용 예시 코드</h3>
<pre><code class="language-java">@Transactional
@Override
public void saveAll(List&lt;Product&gt; products) {
    String sql = &quot;INSERT INTO product (title, created_ts, price)  VALUES (?, ? ,?)&quot;;

    jdbcTemplate.batchUpdate(sql,
            products,
            100,
            (ps, product) -&gt; {
                ps.setString(1, product.getTitle());
                ps.setTimestamp(2, Timestamp.valueOf(product.getCreatedTs()));
                ps.setBigDecimal(3, product.getPrice());
            }
    );
}</code></pre>
<p>💡 Bulk Sql 를 사용할 때 전송하는 데이터를 많이 묶는다고 처리 속도가 비례해서 증가하지는 않는다.
또한 Bulk Sql 크기가 큰 경우 해당 로우(테이블) 에 오랜 시간 동안 <strong>락이 발생한다는 사실 숙지</strong>하고 적절한 크기를 정해야 한다.</p>
<h2 id="실제-적용">실제 적용</h2>
<h3 id="속도-비교">속도 비교</h3>
<p>아래의 내용을 보면 알 수 있지만 단건과 일괄 처리는 <strong>처리해야 하는 데이터가 많을 수록</strong>도 <strong>더 빠르게 처리</strong>하는 것을 확인 할 수 있다. (단건 저장, 일괄 저장)</p>
<p><img src="https://velog.velcdn.com/images/snowlight-aemt/post/5d345997-e70f-4a25-9ee4-4106ad53d2a3/image.png" alt="rewriteBatchedStatements = true"></p>
<p>rewriteBatchedStatements = true 인 경우</p>
<h3 id="mysql-설정">Mysql 설정</h3>
<p><code>spring.datasource.url</code> 에 <code>rewriteBatchedStatements</code> 은 일괄(batch) 처리를 할 수 있도록 해준다.</p>
<p>따라서 DB 일괄 처리가 필요한 경우 반드시 설정할 필요가 있다. (Mysql 에 대한 설정 정보)</p>
<pre><code>spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:13306/snow?rewriteBatchedStatements=true
    username: snow
    password: snow</code></pre><p>참고로 <code>rewriteBatchedStatements</code> 속성을 설정을 하지 않는 경우 기본 값으로 <code>false</code> 로 하는 경우 아래와 같이 단건과 동일한 처리율을 보여주는 것을 확인 할 수 있다. (단건 저장, 일괄 저장)</p>
<p><img src="https://velog.velcdn.com/images/snowlight-aemt/post/6ac29515-c7ca-453c-8bf5-d56a6fc25829/image.png" alt="rewriteBatchedStatements = false"></p>
<p>rewriteBatchedStatements = false 인 경우</p>
<h3 id="참고-자료">참고 자료</h3>
<p>심플 프로젝트</p>
<p><a href="https://github.com/snowlight-aemt/basic-project-colletion/tree/master/spring-db-batch-performance">https://github.com/snowlight-aemt/basic-project-colletion/tree/master/spring-db-batch-performance</a></p>
<p>일관 처리 프로젝트</p>
<p><a href="https://github.com/snowlight-aemt/grade-study">https://github.com/snowlight-aemt/grade-study</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Velog 로 이동]]></title>
            <link>https://velog.io/@snowlight-aemt/notiontovelog</link>
            <guid>https://velog.io/@snowlight-aemt/notiontovelog</guid>
            <pubDate>Sun, 07 May 2023 23:54:18 GMT</pubDate>
            <description><![CDATA[<h1 id="velog-이전-중">Velog 이전 중...!</h1>
<h2 id="velog-선택">Velog 선택</h2>
<p>Velog, Githug Blog, Tistory, Notion 여러 블로그 사이트 중에서 Velog 를 선택한 이유는 가장 쉽게 글로 작성할 수 있다는 이유이다.</p>
<p>쉽게 작성할 수 있다는 말은 다른 곳에 신경을 쓰지 않고 작성할 수 있다</p>
<p>블로깅은 처음인데다가 안 그래도 글을 못 쓰는데 복잡하면... </p>
<h2 id="블로깅-시작">블로깅 시작</h2>
<p>현재 Notion 를 사용 중 하고 있다 이전 이라고 했지만 사실 Notion 에서 작성하는 글은 필기 용으로 정리되지 않은 글이 많고 참고 링크만 걸어놓고 찾아 보는 용도로 사용했는데...</p>
<p>비 공개 글을 작성하다 보니깐 점점 대충 작성하는 글이 많아 지고 있다고 느꼈다.</p>
<p>일단 Notion 에서 작성했던 필기를 Velog 로 하나씩 정리할 생각이다.</p>
<h2 id="목표">목표</h2>
<p>최소 주 1개 이상 작성을 생각 중이다.</p>
]]></description>
        </item>
    </channel>
</rss>