<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>기억나는 노트</title>
    <link>https://milenote.tistory.com/</link>
    <description>기록하는 개발자</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 01:50:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>밀리노트</managingEditor>
    <image>
      <title>기억나는 노트</title>
      <url>https://tistory1.daumcdn.net/tistory/3499800/attach/de8242d74b6d45a6ad26d9f05321b02d</url>
      <link>https://milenote.tistory.com</link>
    </image>
    <item>
      <title>[javascript, Vue] fs을 이용한 Vue Component import 자동화 파일 생성</title>
      <link>https://milenote.tistory.com/178</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&amp;lt;문제점&amp;gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트들을 만든 후 index.js에 각 Vue 컴포넌트를 &quot;수기로 import&quot; 해야하는 상황이 발생하여 자동화가 필요하여 추가&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LqN6M/btsylDctwCQ/IkAFZn67xT8JjVEn7KAenk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LqN6M/btsylDctwCQ/IkAFZn67xT8JjVEn7KAenk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LqN6M/btsylDctwCQ/IkAFZn67xT8JjVEn7KAenk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLqN6M%2FbtsylDctwCQ%2FIkAFZn67xT8JjVEn7KAenk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;555&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동화할 대상들은 components 하위에 있는 1depth Directory에 index.js 생성이 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 각 1dpeth Directory 밑에는 모듈별 컴포넌트들이 존재하여 아래 Depth에 컴포넌트들도 모두 스캔이 필요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&amp;lt;자동화 전 소스 예시&amp;gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/dialog/index.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697086154373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import ApprovalHistoryModal from './approval/ApprovalHistoryModal.vue';
import ApprovalLineModal from './approval/ApprovalLineModal.vue';
import ApprovalModal from './approval/ApprovalModal.vue';
import BasicAlert from './basic/BasicAlert.vue';
import BasicConfirm from './basic/BasicConfirm.vue';
import AddressSearchModal from './common/AddressSearchModal.vue';
import TypeContentModal from './common/TypeContentModal.vue';
import GroupModal from './group/GroupModal.vue';
import SingleSiteModal from './site/SingleSiteModal.vue';
import MultiUserModal from './user/MultiUserModal.vue';
import SingleUserModal from './user/SingleUserModal.vue';

export default {
  install(Vue) {
    Vue.component('ApprovalHistoryModal', ApprovalHistoryModal);
    Vue.component('ApprovalLineModal', ApprovalLineModal);
    Vue.component('ApprovalModal', ApprovalModal);
    Vue.component('BasicAlert', BasicAlert);
    Vue.component('BasicConfirm', BasicConfirm);
    Vue.component('AddressSearchModal', AddressSearchModal);
    Vue.component('TypeContentModal', TypeContentModal);
    Vue.component('GroupModal', GroupModal);
    Vue.component('SingleSiteModal', SingleSiteModal);
    Vue.component('MultiUserModal', MultiUserModal);
    Vue.component('SingleUserModal', SingleUserModal);
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; /components/export.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697086202097&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export { default as dialog } from './dialog';
export { default as file } from './file';
export { default as input } from './input';
export { default as table } from './table';
export { default as tree } from './tree';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;/components/index.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697086229329&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import * as components from './export';

export default function install(Vue) {
  Object.values(components).forEach((component) =&amp;gt; {
    Vue.use(component);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;src/index.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697086325279&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import component from './common/components';

export default {
  install(Vue) {
    Vue.use(component);
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&amp;lt;작업 내용&amp;gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/components/index.js&lt;/b&gt;는 수기로 작성할 일이 없어 자동화 대상에서 제외&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 컴포넌트 1Depth Directory (&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;/dialog/index.js&lt;/b&gt;, &lt;b&gt;/file/index.js&lt;/b&gt;, 등)&lt;/span&gt; 와 최상위 디렉토리(&lt;b&gt;export.js&lt;/b&gt;)를 대상으로 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 컴포넌트&amp;nbsp; 경로는 './src/common/components' 으로 지정하고 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ /script/fileGenerate.js ]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697085410184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const rootFolder = './src/common/components';

const readDir = (path, filePaths = []) =&amp;gt; {
  const files = fs.readdirSync(path);
  files.forEach((fileName) =&amp;gt; {
    const name = `${path}/${fileName}`;
    if (fs.statSync(name).isDirectory()) {
      return readDir(name, filePaths);
    } else {
      filePaths.push(name);
    }
  });

  return filePaths;
};

const groupingDir = (files, moduleMap = {}) =&amp;gt; {
  files.forEach((file) =&amp;gt; {
    const filePathAndName = file.replace(rootFolder, '').substring(1);

    if (filePathAndName.includes('/')) {
      const dirName = filePathAndName.split('/')[0];
      moduleMap[dirName] = [
        ...(moduleMap[dirName] || []),
        ...[`.${filePathAndName.replace(dirName, '')}`],
      ];
    }
  });

  return moduleMap;
};

const writeIndexFile = (modulePathMap) =&amp;gt; {
  for (const [key, value] of Object.entries(modulePathMap)) {
    const rootPath = `${rootFolder}/${key}/index.js`;
    let content = '';

    //import
    value.forEach((modulePath) =&amp;gt; {
      // index.js인 경우 패스
      if (modulePath.includes('index.js')) return true;

      const moduleName = modulePath.substring(
        modulePath.lastIndexOf('/') + 1,
        modulePath.lastIndexOf('.'),
      );
      content += `import ${moduleName} from '${modulePath}';\n`;
    });

    content += '\nexport default {\n' + '  install(Vue) {\n';
    // Vue.component
    value.forEach((modulePath) =&amp;gt; {
      // index.js인 경우 패스
      if (modulePath.includes('index.js')) return true;

      const moduleName = modulePath.substring(
        modulePath.lastIndexOf('/') + 1,
        modulePath.lastIndexOf('.'),
      );
      content += `    Vue.component('${moduleName}', ${moduleName});\n`;
    });
    content += '  },\n' + '};';

    fs.writeFileSync(rootPath, content);
  }
};

const writeExportFile = (modulePathMap) =&amp;gt; {
  const rootPath = `${rootFolder}/export.js`;
  let content = '';
  for (const [key] of Object.entries(modulePathMap)) {
    content += `export { default as ${key} } from './${key}';\n`;
  }

  fs.writeFileSync(rootPath, content);
};

const modulePathMap = groupingDir(readDir(rootFolder));
writeIndexFile(modulePathMap);
writeExportFile(modulePathMap);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;readDir() 함수를 통해 지정한 rootFolder에 하위 파일들을 모두 스캔 후 배열(filePaths) 에 저장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Directory인 경우는 재귀호출을 하여 안에 있는 파일들을 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;groupingDir()을 통해 읽어드린 배열을 최상위 Directory 명으로 오브젝트를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1697085643524&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	dialog: [파일path1, 파일path2],
	input: [파일path1, 파일path2],
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;writeIndexFile()을 통해 1depth Directory 밑에 index.js를 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;index.js에는 각 컴포넌트 모듈들을 import 및 Vue.component 등록 로직을 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;writeExportFile()을 통해 최상위 경로에 export.js를 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;export.js에는 1depth Directory에 있는 index.js를 등록하는 로직을 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[ &lt;b&gt;/package.json&lt;/b&gt; ]&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;npm run serve&lt;/b&gt; 또는 &lt;b&gt;npm run build:lib&lt;/b&gt;라는 명령어가 들어오는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;node script/fileGenerate.js&quot;&amp;nbsp;&lt;/b&gt;문구를 추가하여 fileGenerate.js가 실행되도록 추가&lt;/p&gt;
&lt;pre id=&quot;code_1697086645837&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;컴포넌트명&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;private&quot;: true,
  &quot;scripts&quot;: {
    &quot;serve&quot;: &quot;node script/fileGenerate.js &amp;amp;&amp;amp; vue-cli-service serve&quot;,
    &quot;build:lib&quot;: &quot;node script/fileGenerate.js &amp;amp;&amp;amp; vue-cli-service build --target lib --name micro-portal-component ./src/index.js&quot;,
  }
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프런트엔드/javascript</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/178</guid>
      <comments>https://milenote.tistory.com/178#entry178comment</comments>
      <pubDate>Thu, 12 Oct 2023 13:59:34 +0900</pubDate>
    </item>
    <item>
      <title>[javascript] axios multi form 데이터 처리</title>
      <link>https://milenote.tistory.com/177</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[소스 환경]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BackEnd : Spring boot, jdk17, Lombok&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Front: Vue, Axios&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BackEnd에서 파일을 수정하는 로직을 배열로 받아 처리하는 부분이 포함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios에서 Form을 배열로 전달해야하는 상황이 발생&lt;/p&gt;
&lt;pre id=&quot;code_1697084689864&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PutMapping(value = &quot;[주소]&quot;,
        consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE)
public SuccessResponse&amp;lt;List&amp;lt;Response&amp;gt;&amp;gt; [메소드명] (@PathVariable String id,
        @Valid @ModelAttribute Requests requests) {
    return new SuccessResponse&amp;lt;&amp;gt;(service.upsert(id, requests));
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1697084715486&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
public class Request {
	private List&amp;lt;SubRequest&amp;gt; requests;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697084961684&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
public class SubRequest {
	private String id;
	private List&amp;lt;MultipartFile&amp;gt; files;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 Axios에서 파일을 전달하는 경우 아래와 같은 방식을 사용 (단일 처리)&lt;/p&gt;
&lt;pre id=&quot;code_1697085107876&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async update(id, files) {
    const headers = { 'Content-Type': 'multipart/form-data' };
    const formData = new FormData();
    files.forEach((file) =&amp;gt; {
      formData.append('files', file);
    });
    
    return await axios.put([주소], formData, headers);
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열로 사용하는 경우에는 아래와 같은 처리가 필요 (다건 처리)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;formdata.append(`requests...`, value)에 requests는 백엔드에서 사용한 key명을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1697085242488&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async update(id, parameters) {
    const headers = { 'Content-Type': 'multipart/form-data' };
    
    const formData = new FormData();
    parameters.forEach((param, index) =&amp;gt; {
      for (const [key, value] of Object.entries(param)) {
        if (value) formData.append(`requests[${index}].${key}`, value);
      }
    })
    
    return await axios.put([주소], formData, headers);
  },&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프런트엔드/javascript</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/177</guid>
      <comments>https://milenote.tistory.com/177#entry177comment</comments>
      <pubDate>Thu, 12 Oct 2023 13:35:03 +0900</pubDate>
    </item>
    <item>
      <title>[ SpringBoot + jsp + intellij ] jsp 사용을 위한 설정</title>
      <link>https://milenote.tistory.com/176</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 설치 환경&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;intellij:&amp;nbsp;IntelliJ IDEA 2021.1.3 (Ultimate Edition)&lt;br /&gt;jdk: java17&lt;br /&gt;spring boot: 2.6.4&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. spring boot 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;Intellij Community 버전은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://start.spring.io/&quot;&gt;https://start.spring.io/&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 프로젝트르 세팅&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. *Packaging 방식을 War로 선택 (jar방식은 지원 안되는 듯)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;971&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brD4KY/btrAPNy2JFu/wo2YJsmGI3SFZf2rEcyIIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brD4KY/btrAPNy2JFu/wo2YJsmGI3SFZf2rEcyIIk/img.png&quot; data-alt=&quot;war를 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brD4KY/btrAPNy2JFu/wo2YJsmGI3SFZf2rEcyIIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrD4KY%2FbtrAPNy2JFu%2Fwo2YJsmGI3SFZf2rEcyIIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;467&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;971&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;war를 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;JSP Limitations&lt;br /&gt;&lt;br /&gt;When running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.&lt;br /&gt;With Jetty and Tomcat, it should work if you use war packaging. An executable war will work when launched with java -jar, and will also be deployable to any standard container. JSPs are not supported when using an executable jar.Undertow does not support JSPs.Creating a custom error.jsp page does not override the default view for error handling. Custom error pages should be used instead.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.servlet.embedded-container.jsp-limitations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#web.servlet.embedded-container.jsp-limitations&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 사용할 Dependencies 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적으로는 Spring Web만 추가하면 사용 가능 (Lombok은 편의를 위해서 추가)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;979&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SGj6E/btrARFGMWcQ/DERAIuAb2LlmjDNH46lcNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SGj6E/btrARFGMWcQ/DERAIuAb2LlmjDNH46lcNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SGj6E/btrARFGMWcQ/DERAIuAb2LlmjDNH46lcNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSGj6E%2FbtrARFGMWcQ%2FDERAIuAb2LlmjDNH46lcNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;411&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;979&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Gradle에 jsp에서 사용하는 Dependencie 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- plugins에 &lt;u&gt;&lt;b&gt;war&lt;/b&gt;&lt;/u&gt;&amp;nbsp;확인 필요 (jar X)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- dependencies에 &lt;u&gt;&lt;b&gt;tomcat-embed-jasper&lt;/b&gt;&lt;/u&gt;, &lt;u&gt;&lt;b&gt;javax,servlet:jstl&lt;/b&gt;&lt;/u&gt;, &lt;u&gt;&lt;b&gt;spring-boot-starter-tomcat&lt;/b&gt;&lt;/u&gt; 확인&lt;/p&gt;
&lt;pre id=&quot;code_1651312343438&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
    id 'org.springframework.boot' version '2.6.7'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id 'war' // jsp 사용시 필수 요소
}

...

dependencies {
    implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' // 추가
    implementation 'javax.servlet:jstl' // 추가

    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' // jsp 사용시 필수 요소
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 소스 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 설정 파일&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;u&gt;&lt;b&gt;src/main/resources/application.yml&lt;/b&gt;&lt;/u&gt; 또는&amp;nbsp;&lt;u&gt;&lt;b&gt;src/main/resources/application.properties&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 두가지 방법 중 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필수요소는 아니지만 페이지에 반복적인 경로와 파일형식을 제거하기 위해 사용&lt;br /&gt;&amp;nbsp; -&amp;gt; 사용하는 경우 return &quot;home&quot;, 사용하지 않는 경우 return &quot;/WEB-INF/views/home.jsp&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651312540968&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.yml인 경우

spring:
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp


.properties인 경우

spring.mvc.view.previx=/WEB-INF/views/
spring.mvc.view.suffix=.jsp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. jsp 디렉토리 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- src/webapp/WEB-INF는 이름을 변경하지 않고 기본적인 디렉토리로 사용 &lt;b&gt;(필수)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- views, jsp, 등의 하위 디렉토리 생성&amp;nbsp;&lt;b&gt;(선택, 이름도 변경 가능)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vUjU8/btrASv5q7bC/QaZrzwGysMhKXIakHQcjH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vUjU8/btrASv5q7bC/QaZrzwGysMhKXIakHQcjH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vUjU8/btrASv5q7bC/QaZrzwGysMhKXIakHQcjH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvUjU8%2FbtrASv5q7bC%2FQaZrzwGysMhKXIakHQcjH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;242&quot; height=&quot;236&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 테스트 파일&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;테스트를 위한 용도로 만든 파일 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Controller (HomeController.java)&lt;/p&gt;
&lt;pre id=&quot;code_1651313175697&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller
public class HomeController {

    @GetMapping(&quot;/home&quot;)
    public String home() {
        return &quot;home&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. jsp (home.jsp)&lt;/p&gt;
&lt;pre id=&quot;code_1651313195474&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&amp;gt;
&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot;
          content=&quot;width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0&quot;&amp;gt;
    &amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    테스트
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;오류 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 원인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 프로젝트내에 Module을 추가하여 세팅을 하는 중 404 오류가 발생&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVl7if/btrAR8P9xSb/YK3m4CdkmJG7gF0LD7vUq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVl7if/btrAR8P9xSb/YK3m4CdkmJG7gF0LD7vUq0/img.png&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;502&quot; data-is-animation=&quot;false&quot; width=&quot;254&quot; height=&quot;259&quot; style=&quot;width: 18.9419%; margin-right: 10px;&quot; data-widthpercent=&quot;19.16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVl7if/btrAR8P9xSb/YK3m4CdkmJG7gF0LD7vUq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVl7if%2FbtrAR8P9xSb%2FYK3m4CdkmJG7gF0LD7vUq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RRc3m/btrARgHi1u6/qYUj6wd0cYWTIzStVjsQDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RRc3m/btrARgHi1u6/qYUj6wd0cYWTIzStVjsQDK/img.png&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;253&quot; data-is-animation=&quot;false&quot; width=&quot;566&quot; height=&quot;137&quot; style=&quot;width: 79.8953%;&quot; data-widthpercent=&quot;80.84&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RRc3m/btrARgHi1u6/qYUj6wd0cYWTIzStVjsQDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRRc3m%2FbtrARgHi1u6%2FqYUj6wd0cYWTIzStVjsQDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1048&quot; height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 해결방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Intellij 오른쪽 상단에 콤보박스를 선택 후 Edit Configurations..를 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- jsp가 실행되는 Spring Boot &amp;gt; MyJspApplication 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Configuration 탭에 Environment 밑에 있는 Working Directory에 &lt;u&gt;&lt;b&gt;$MODULE_WORKING_DIR$&lt;/b&gt;&lt;/u&gt; 입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qGaRM/btrAR9VQrPw/3ZNDeRz5H7XhMEWPrhIrPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qGaRM/btrAR9VQrPw/3ZNDeRz5H7XhMEWPrhIrPk/img.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;685&quot; data-is-animation=&quot;false&quot; width=&quot;616&quot; height=&quot;410&quot; style=&quot;width: 56.1914%; margin-right: 10px;&quot; data-widthpercent=&quot;56.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qGaRM/btrAR9VQrPw/3ZNDeRz5H7XhMEWPrhIrPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqGaRM%2FbtrAR9VQrPw%2F3ZNDeRz5H7XhMEWPrhIrPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1030&quot; height=&quot;685&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KVy99/btrAR9O4P1b/YZswNSkKb5WwvY72YCFmEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KVy99/btrAR9O4P1b/YZswNSkKb5WwvY72YCFmEK/img.png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;765&quot; data-is-animation=&quot;false&quot; width=&quot;453&quot; height=&quot;397&quot; style=&quot;width: 42.6458%;&quot; data-widthpercent=&quot;43.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KVy99/btrAR9O4P1b/YZswNSkKb5WwvY72YCFmEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKVy99%2FbtrAR9O4P1b%2FYZswNSkKb5WwvY72YCFmEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;873&quot; height=&quot;765&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드/SpringBoot</category>
      <category>IntelliJ</category>
      <category>jsp</category>
      <category>Spring Boot</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/176</guid>
      <comments>https://milenote.tistory.com/176#entry176comment</comments>
      <pubDate>Sat, 30 Apr 2022 19:19:44 +0900</pubDate>
    </item>
    <item>
      <title>[ Docker / 도커 ] 윈도우(windows) 도커 설치하기</title>
      <link>https://milenote.tistory.com/175</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 설치조건&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;WSL은 Windows Subsystem for Linux 2의 줄임말로 윈도우에서 리눅스를 사용할 수 있게 해주는 기능&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Windows 10 Pro 에디션
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WSL2 기반 Docker Engine 사용 가능&lt;/li&gt;
&lt;li&gt;Hyper-V 기반 Docker Engine 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Windows 10 Home 에디션 (윈도우 패치가 된 경우)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WSL2 기반 Docker Engine 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;Windows 11 설치 가능&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #dddddd;&quot;&gt;Windows 10 Home은 WSL2를 지원하지 않았는데, 2020년 5월&amp;nbsp;Windows 10 May 2020 Update(20H1) 업데이트&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; background-color: #dddddd;&quot;&gt;가 릴리스되면서 WSL2가 정식 릴리스되었다는 점입니다. WSL2는 Windows 10 Home에서도 사용 가능하도록 패치 됌&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. WSL 설치방법&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Windows Terminal을 &amp;rsquo;관리자 권한으로 실행&amp;rsquo;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. PowerShell 탭에서 다음 두 명령어를 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;$ dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
$ dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 두 명령어 모두 &amp;lsquo;작업을 완료했습니다&amp;rsquo; 출력으로 종료되었는지 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 윈도우를 재부팅합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi&quot;&gt;x64 머신용 최신 WSL2 Linux 커널 업데이트 패키지&lt;/a&gt;를 다운로드 받아 안내에 따라 설치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Windows Terminal을 열고 다음 명령어를 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ wsl --set-default-version 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 도커 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드주소: &lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.docker.com/products/docker-desktop/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650461127319&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Docker Desktop - Docker&quot; data-og-description=&quot;DockerCon 2022 Don&amp;rsquo;t miss it &amp;ndash; register now for May 10th! DockerCon is a free, immersive online experience complete with product demos, breakout learning tracks, panel discussions, hacks &amp;amp; tips, deep dive technical sessions from Docker experts, the dev&quot; data-og-host=&quot;www.docker.com&quot; data-og-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bd3jex/hyN6PWnmev/2AM4ShZo56k9vndhmHNkYk/img.png?width=2880&amp;amp;height=855&amp;amp;face=0_0_2880_855&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bd3jex/hyN6PWnmev/2AM4ShZo56k9vndhmHNkYk/img.png?width=2880&amp;amp;height=855&amp;amp;face=0_0_2880_855');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop - Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;DockerCon 2022 Don&amp;rsquo;t miss it &amp;ndash; register now for May 10th! DockerCon is a free, immersive online experience complete with product demos, breakout learning tracks, panel discussions, hacks &amp;amp; tips, deep dive technical sessions from Docker experts, the dev&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;설치파일을 받은 후 실행&lt;/li&gt;
&lt;li&gt;&lt;span&gt;도커 회원가입&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;https://hub.docker.com/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;설치와 회원가입이 모두 완료된 화면&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHmDx7/btrzUzIjuNZ/m5MsSbbciJQ66kLG9nVFyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHmDx7/btrzUzIjuNZ/m5MsSbbciJQ66kLG9nVFyK/img.png&quot; data-origin-width=&quot;1596&quot; data-origin-height=&quot;884&quot; width=&quot;712&quot; height=&quot;394&quot; style=&quot;width: 62.617%; margin-right: 10px;&quot; data-widthpercent=&quot;63.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHmDx7/btrzUzIjuNZ/m5MsSbbciJQ66kLG9nVFyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHmDx7%2FbtrzUzIjuNZ%2Fm5MsSbbciJQ66kLG9nVFyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1596&quot; height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O3Mys/btrzZL1Kj1V/O3qKT5CKYs4JoqCoxK2xz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O3Mys/btrzZL1Kj1V/O3qKT5CKYs4JoqCoxK2xz0/img.png&quot; data-origin-width=&quot;212&quot; data-origin-height=&quot;203&quot; data-is-animation=&quot;false&quot; style=&quot;width: 36.2202%;&quot; data-widthpercent=&quot;36.65&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O3Mys/btrzZL1Kj1V/O3qKT5CKYs4JoqCoxK2xz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO3Mys%2FbtrzZL1Kj1V%2FO3qKT5CKYs4JoqCoxK2xz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;212&quot; height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;도커 실행화면 및 숨긴 아이콘 표시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 그 외 문제해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 windows 10 Home을 사용중이라 WSL이 설치되어있지 않은 현상이 발생 아래와 같이 조치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;윈도우10 &amp;gt; 설정 &amp;gt; 업데이트 및 복구 &amp;gt; windows 업데이트로 최신화 진행&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;업데이트 진행중에 windows 10 버전 20h2의 기능 업데이트에서 멈춤현상 발생&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;-&amp;gt; 수동 업데이트 파일을 받아 다운로드 진행&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1650461919622&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;윈도우10 20H2 업데이트시 61% 에서 멈추는 오류 해결 방법&quot; data-og-description=&quot;제가 가지고 있는 LG 노트북에서 윈도우 10 20H2 업데이트를 실행하면 61% 에서 멈추는 현상이 있어서 ...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot; data-og-url=&quot;https://blog.naver.com/websearch/222248105770&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fkzFJ/hyN6ZxWsVP/6uQARLk0Y5LUjEsjkufKi1/img.png?width=743&amp;amp;height=476&amp;amp;face=0_0_743_476&quot;&gt;&lt;a href=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fkzFJ/hyN6ZxWsVP/6uQARLk0Y5LUjEsjkufKi1/img.png?width=743&amp;amp;height=476&amp;amp;face=0_0_743_476');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;윈도우10 20H2 업데이트시 61% 에서 멈추는 오류 해결 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;제가 가지고 있는 LG 노트북에서 윈도우 10 20H2 업데이트를 실행하면 61% 에서 멈추는 현상이 있어서 ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650460451010&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[Windows 10] Docker 설치 완벽 가이드(Home 포함)&quot; data-og-description=&quot;Docker는 경량 가상화 기술인 리눅스 컨테이너 도구입니다. Windows 10 Home과 Pro에서도 몇 가지 설정을 통해 Docker Desktop으로 리눅스 컨테이너를 사용할 수 있습니다. 이 글에서는 Windows 10에서 Docker Des&quot; data-og-host=&quot;www.lainyzine.com&quot; data-og-source-url=&quot;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&quot; data-og-url=&quot;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PtW5H/hyN61P1B9h/HuRhVF9BOIoJqUP9DQkzw0/img.png?width=1500&amp;amp;height=882&amp;amp;face=0_0_1500_882,https://scrap.kakaocdn.net/dn/zaJ26/hyN6Qnr2gR/xUPzSzeGVv9ZdQvmGxAdUk/img.png?width=1500&amp;amp;height=865&amp;amp;face=0_0_1500_865,https://scrap.kakaocdn.net/dn/dr6Z3W/hyN6RNopxY/kf03YWZXVNY3C87Q0X6I21/img.png?width=1500&amp;amp;height=849&amp;amp;face=0_0_1500_849&quot;&gt;&lt;a href=&quot;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.lainyzine.com/ko/article/a-complete-guide-to-how-to-install-docker-desktop-on-windows-10/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PtW5H/hyN61P1B9h/HuRhVF9BOIoJqUP9DQkzw0/img.png?width=1500&amp;amp;height=882&amp;amp;face=0_0_1500_882,https://scrap.kakaocdn.net/dn/zaJ26/hyN6Qnr2gR/xUPzSzeGVv9ZdQvmGxAdUk/img.png?width=1500&amp;amp;height=865&amp;amp;face=0_0_1500_865,https://scrap.kakaocdn.net/dn/dr6Z3W/hyN6RNopxY/kf03YWZXVNY3C87Q0X6I21/img.png?width=1500&amp;amp;height=849&amp;amp;face=0_0_1500_849');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Windows 10] Docker 설치 완벽 가이드(Home 포함)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 경량 가상화 기술인 리눅스 컨테이너 도구입니다. Windows 10 Home과 Pro에서도 몇 가지 설정을 통해 Docker Desktop으로 리눅스 컨테이너를 사용할 수 있습니다. 이 글에서는 Windows 10에서 Docker Des&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.lainyzine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mainia.tistory.com/5064&quot;&gt;https://mainia.tistory.com/5064&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650461986355&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;윈도우10 최신 상태로 업데이트 하는 방법&quot; data-og-description=&quot;윈도우10 최신 상태로 업데이트 하는 방법 환경: Windows 10 모든 프로그램이 그렇듯 윈도우 또한 처음부터 완벽할 수 없습니다. 그래서 윈도우는 항상 최신 상태를 유지하는 것이 좋습니다. 그 중&quot; data-og-host=&quot;mainia.tistory.com&quot; data-og-source-url=&quot;https://mainia.tistory.com/5064&quot; data-og-url=&quot;https://mainia.tistory.com/5064&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbzyiX/hyN64lHX6N/w1k6AQQbG75ljo1bFWKrEK/img.jpg?width=620&amp;amp;height=426&amp;amp;face=0_0_620_426,https://scrap.kakaocdn.net/dn/bJleYu/hyN6ZSelw6/R58D72W0NYYqxpuSIHavo0/img.jpg?width=620&amp;amp;height=426&amp;amp;face=0_0_620_426,https://scrap.kakaocdn.net/dn/bcEzbL/hyN622utll/NlsbwNc34gmOcFF1wdzcK0/img.jpg?width=620&amp;amp;height=463&amp;amp;face=0_0_620_463&quot;&gt;&lt;a href=&quot;https://mainia.tistory.com/5064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mainia.tistory.com/5064&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbzyiX/hyN64lHX6N/w1k6AQQbG75ljo1bFWKrEK/img.jpg?width=620&amp;amp;height=426&amp;amp;face=0_0_620_426,https://scrap.kakaocdn.net/dn/bJleYu/hyN6ZSelw6/R58D72W0NYYqxpuSIHavo0/img.jpg?width=620&amp;amp;height=426&amp;amp;face=0_0_620_426,https://scrap.kakaocdn.net/dn/bcEzbL/hyN622utll/NlsbwNc34gmOcFF1wdzcK0/img.jpg?width=620&amp;amp;height=463&amp;amp;face=0_0_620_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;윈도우10 최신 상태로 업데이트 하는 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;윈도우10 최신 상태로 업데이트 하는 방법 환경: Windows 10 모든 프로그램이 그렇듯 윈도우 또한 처음부터 완벽할 수 없습니다. 그래서 윈도우는 항상 최신 상태를 유지하는 것이 좋습니다. 그 중&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mainia.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot;&gt;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1650461991744&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;윈도우10 20H2 업데이트시 61% 에서 멈추는 오류 해결 방법&quot; data-og-description=&quot;제가 가지고 있는 LG 노트북에서 윈도우 10 20H2 업데이트를 실행하면 61% 에서 멈추는 현상이 있어서 ...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot; data-og-url=&quot;https://blog.naver.com/websearch/222248105770&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fkzFJ/hyN6ZxWsVP/6uQARLk0Y5LUjEsjkufKi1/img.png?width=743&amp;amp;height=476&amp;amp;face=0_0_743_476&quot;&gt;&lt;a href=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/PostView.naver?blogId=websearch&amp;amp;logNo=222248105770&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fkzFJ/hyN6ZxWsVP/6uQARLk0Y5LUjEsjkufKi1/img.png?width=743&amp;amp;height=476&amp;amp;face=0_0_743_476');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;윈도우10 20H2 업데이트시 61% 에서 멈추는 오류 해결 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;제가 가지고 있는 LG 노트북에서 윈도우 10 20H2 업데이트를 실행하면 61% 에서 멈추는 현상이 있어서 ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>서버/Docker</category>
      <category>도커</category>
      <category>도커설치</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/175</guid>
      <comments>https://milenote.tistory.com/175#entry175comment</comments>
      <pubDate>Wed, 20 Apr 2022 22:49:55 +0900</pubDate>
    </item>
    <item>
      <title>[ Intellj / 인텔리제이 ] Execution failed for task ':test'.</title>
      <link>https://milenote.tistory.com/174</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Intellij를 통해 간단한 출력용 코드를 junit으로 돌리는데 에러가 발생&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;class를 public으로 변경해도 동일 에러 발생&lt;/li&gt;
&lt;li&gt;메소드에 public으로 변경해도 동일 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1650374888719&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
public class UserSearchRepositoryTest {

    @Test
    void 사용자_생성() {
        System.out.println(&quot;aaaa&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1650374788134&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Execution failed for task ':test'.
&amp;gt; There were failing tests. See the report at: file:///D:/sideProject/elastic-jdk17-toy/build/reports/tests/test/index.html

* Try:
&amp;gt; Run with --stacktrace option to get the stack trace.
&amp;gt; Run with --info or --debug option to get more log output.
&amp;gt; Run with --scan to get full insights.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일에 들어가서 확인하니 gradle이 테스트 실행할때 Exception이 발생&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not execute test class 'com.mile.elasticjdk17toy.repository.rdb.UserRepositoryTest'.&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 해결방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;File &amp;gt; Setting &amp;gt; Gradle에 빨간색 부분을 Gradle -&amp;gt; Intellij IDEA로 변경하여 해결&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;1101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UFn01/btrzMwkNjOJ/unPTVJkwktRnsl4KqeolcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UFn01/btrzMwkNjOJ/unPTVJkwktRnsl4KqeolcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UFn01/btrzMwkNjOJ/unPTVJkwktRnsl4KqeolcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUFn01%2FbtrzMwkNjOJ%2FunPTVJkwktRnsl4KqeolcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;646&quot; height=&quot;468&quot; data-origin-width=&quot;1518&quot; data-origin-height=&quot;1101&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발 유틸리티/intellij</category>
      <category>IntelliJ</category>
      <category>테스트코드</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/174</guid>
      <comments>https://milenote.tistory.com/174#entry174comment</comments>
      <pubDate>Tue, 19 Apr 2022 22:33:36 +0900</pubDate>
    </item>
    <item>
      <title>[ Intellj / 인텔리제이 ] 파일 저장시 자동 정렬 (Save Actions)</title>
      <link>https://milenote.tistory.com/173</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 설치하는 법 : File &amp;gt; Settings &amp;gt; Plugins &amp;gt; Markeyplace &amp;gt; SaveActions 검색&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Fka9/btrsFugdrTz/juRQZ4fpOszReuvZfM3nC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Fka9/btrsFugdrTz/juRQZ4fpOszReuvZfM3nC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Fka9/btrsFugdrTz/juRQZ4fpOszReuvZfM3nC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Fka9%2FbtrsFugdrTz%2FjuRQZ4fpOszReuvZfM3nC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;735&quot; height=&quot;444&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;840&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 설정하는법 : File &amp;gt; Settings &amp;gt; Save Actions &lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[General]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Activate save actions on save (before saving each file, performs the configured actions below)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장시 활성화 (각 파일을 저장하기 전에 아래에 구성된 작업 수행)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Activate save actions on shorcut (default &quot;CTRL + SHIFT + S&quot;)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단축키로 저장했을 때 활성화 (기본값 &quot;CTRL + SHIFT + S&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Activate save actions on batch
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일괄 작업 시 활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;No action if compile errors(applied per file)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 오류 발생시 조치 없음 (파일별로 적용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[Formatting Actions]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Optimize imports
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;import 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reformat file
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;file 재정렬&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;883&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ay4eF/btrsLw5nWw9/Msp43YG4qVsT4wrBvPNkvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ay4eF/btrsLw5nWw9/Msp43YG4qVsT4wrBvPNkvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ay4eF/btrsLw5nWw9/Msp43YG4qVsT4wrBvPNkvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAy4eF%2FbtrsLw5nWw9%2FMsp43YG4qVsT4wrBvPNkvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;666&quot; height=&quot;422&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;883&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;span&gt;포함할 파일과 제외할 파일 지정&lt;/span&gt; :&lt;span&gt;&amp;nbsp;&lt;/span&gt;File &amp;gt; Settings &amp;gt; Save Actions&lt;span&gt; 스크롤 맨 아래&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;879&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfAfxA/btrsO3nCEnQ/KQycImGdwf1Vln75fkENwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfAfxA/btrsO3nCEnQ/KQycImGdwf1Vln75fkENwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfAfxA/btrsO3nCEnQ/KQycImGdwf1Vln75fkENwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfAfxA%2FbtrsO3nCEnQ%2FKQycImGdwf1Vln75fkENwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;437&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;879&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bicB12/btrsC9QUCxo/rAys6LdSjkXy1IIImygky0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bicB12/btrsC9QUCxo/rAys6LdSjkXy1IIImygky0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bicB12/btrsC9QUCxo/rAys6LdSjkXy1IIImygky0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbicB12%2FbtrsC9QUCxo%2FrAys6LdSjkXy1IIImygky0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;181&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고: &lt;a href=&quot;https://hirlawldo.tistory.com/136&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hirlawldo.tistory.com/136&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1644242926294&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[IntelliJ] 저장 시 자동 정렬 설정하는 방법 (Save Actions) - Mac&quot; data-og-description=&quot;단축키(Option + Command + L)를 누르면 자동 정렬이 되지만, 가끔 까먹고 안할 때가 있다. 자동으로 저장할 때 정렬해주면 편하지 않을까? (가끔 정렬하면 더 구린 경우 팀원들에게 욕을 먹을 수 있으&quot; data-og-host=&quot;hirlawldo.tistory.com&quot; data-og-source-url=&quot;https://hirlawldo.tistory.com/136&quot; data-og-url=&quot;https://hirlawldo.tistory.com/136&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/94duD/hyNlfayhct/ghC9Z4XQi3wW2pQNDn2LF0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/mrDla/hyNlqQHsZO/tar7tFSGnA41aik4igg1bk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hGZ7o/hyNlcZbzgT/5K1dzzBZgFc1ZqFPIinAvk/img.jpg?width=400&amp;amp;height=399&amp;amp;face=161_93_229_167&quot;&gt;&lt;a href=&quot;https://hirlawldo.tistory.com/136&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hirlawldo.tistory.com/136&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/94duD/hyNlfayhct/ghC9Z4XQi3wW2pQNDn2LF0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/mrDla/hyNlqQHsZO/tar7tFSGnA41aik4igg1bk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hGZ7o/hyNlcZbzgT/5K1dzzBZgFc1ZqFPIinAvk/img.jpg?width=400&amp;amp;height=399&amp;amp;face=161_93_229_167');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[IntelliJ] 저장 시 자동 정렬 설정하는 방법 (Save Actions) - Mac&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;단축키(Option + Command + L)를 누르면 자동 정렬이 되지만, 가끔 까먹고 안할 때가 있다. 자동으로 저장할 때 정렬해주면 편하지 않을까? (가끔 정렬하면 더 구린 경우 팀원들에게 욕을 먹을 수 있으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hirlawldo.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 유틸리티/intellij</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/173</guid>
      <comments>https://milenote.tistory.com/173#entry173comment</comments>
      <pubDate>Mon, 7 Feb 2022 23:19:49 +0900</pubDate>
    </item>
    <item>
      <title>[도커 / docker] 명령어 정리</title>
      <link>https://milenote.tistory.com/172</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 한글시간으로 변경&lt;/h4&gt;
&lt;pre id=&quot;code_1644197925008&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -e TZ=Asia/Seoul debian:jessie date&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>서버/Docker</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/172</guid>
      <comments>https://milenote.tistory.com/172#entry172comment</comments>
      <pubDate>Mon, 7 Feb 2022 10:38:49 +0900</pubDate>
    </item>
    <item>
      <title>[토비의 스프링 - Vol.2] 2장 - 2.4 JPA</title>
      <link>https://milenote.tistory.com/171</link>
      <description>&lt;article id=&quot;54bf78c9-62b8-46fa-b04e-41a37edef56d&quot; class=&quot;page sans Notion_P content__permalink&quot;&gt;&lt;header&gt;&lt;h1 class=&quot;page-title&quot;&gt;2.4 JPA&lt;/h1&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;ul id=&quot;32f39a4b-2c87-402d-9797-828874811a48&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;Java Persistent API의 약자로 EJB 3.0과 함꼐 등장한 JavaEE와 JavaSE를 위한 영속성 관리와 O/R 매핑을 위한 표준 기술&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9f2a2bb2-ba9b-4017-84d4-c6cb4621a381&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;오브젝트를 중심으로 개발하는 자바 같은 언어를 통해 접근하려면 불편한 점이 많았음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;11693087-642e-44ea-97af-7792d338a0ba&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;ORM이란 오브젝트와 RDB 사이에 존재하는 개념과 접근 방법, 성격의 차이 떄문에 요구되는 불편한 작업을 제거&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fa0b2149-c326-43db-9b09-36db32d49b8b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;오브젝트를 가지고 정보를 다루면 ORM 프레임워크가 이를 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;RDB에 적절한 형태로 변환&lt;/strong&gt;&lt;/span&gt;해주거나 그 반대로 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;RDB에 저장되어 있는 정보를 자바오브젝트가 다루기 쉬운 형태로 변환&lt;/strong&gt;&lt;/span&gt;해주는 기술&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c9e3b735-e00e-4f59-a088-f26e14c5f817&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;ORM을 사용하는 개발자는 모든 데이터를 오브젝트 관점으로 생각&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e708b07d-ece9-4e7d-a3fd-7d6756011d93&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;가장 믾이 사용되는 대표적인 JPA 구현 제품들&lt;ul id=&quot;6087c1ee-4ed3-41ca-90a6-803e5c79adb7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JBoss의 하이버네이트&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;d8b09ed6-33a3-41e9-bc43-fa26aed31e26&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;아파치 OpenJPA&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;94e70482-46a2-4816-bed9-5829bc59ff03&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;이클립스 EclipseLink&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;046476bc-d988-4752-baaf-877379890037&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;오라클 TopLink Essentionals&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;1d0a60fd-878a-42c3-a745-babb6d5ae202&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.4.1 EntityManagerFactory 등록&lt;/h2&gt;&lt;ul id=&quot;a4b664cb-e7a0-45b4-9902-d9f1d0b9d871&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA Persistence Context에 접근하고 엔티티 인스턴스를 관리하려면 JPA의 핵심 인터페이스인 EntityManager를 구현한 오브젝트가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0db55d6a-7a83-4169-a888-70ce77567d02&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManager는 JPA에서 두가지 방식으로 관리&lt;ol type=&quot;1&quot; id=&quot;14f0b1e0-7130-4ae1-834c-8c284bf24514&quot; class=&quot;numbered-list&quot; start=&quot;1&quot;&gt;&lt;li&gt;애플리케이션이 관리하는 EntityManager&lt;ul id=&quot;3a2af7be-cfe4-42d9-a77a-40d013c85e17&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JavaEE와 JavaSE에서 모두 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ol type=&quot;1&quot; id=&quot;c670030a-b4eb-4126-b54e-3b5ed2d12658&quot; class=&quot;numbered-list&quot; start=&quot;2&quot;&gt;&lt;li&gt;컨테이너가 관리하는 EntityManager&lt;ul id=&quot;d2e41663-9184-4df4-ad74-760f473d2f29&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JavaEE 환경과 서버가 필요&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ac5eef18-4aa6-43d7-bc5b-0c3814114690&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;반드시 EntityManagerFactory를 빈으로 등록해줘야 함&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;8824b2cc-0a4b-4fe8-8a1a-60f962074b9d&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;c18593c4-dbf4-4af6-8605-e7a09212b562&quot; class=&quot;&quot;&gt;LocalEntityManagerFactoryBean&lt;/h2&gt;&lt;ul id=&quot;9ec233f3-00e6-4ed1-a0a2-87d5cd2ac509&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA 스펙의 JavaSE 기동 방식을 이용해 EntityManagerFactory를 생성&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;b18e0c7e-7af7-4d5b-9998-e7fffc345c84&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;emf&amp;quot; class=&amp;quot;org.springframework.orm.jpa.LocalEntityManagerFactoryBean&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;200ef282-64fa-472e-9a1c-bd2cabf83027&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 빈은 &lt;code&gt;PersistentProvider&lt;/code&gt; 자동 감지 기능을 이용해 프로바이더를 찾고 &lt;code&gt;META-INF/persistence.xml&lt;/code&gt;에 담긴 정보를 활용해 &lt;code&gt;EntityManagerFactory&lt;/code&gt;를 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;286a7594-e049-49eb-b2eb-385ef27ca0cc&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 방식은 JPA만을 사용하는 단순한 환경에서 적용 가능하지만 스프링에서 본격적으로 사용하기에는 많은 제약사항이 발생&lt;ul id=&quot;959f146b-6cf3-4844-808f-49a916c053b6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;가장 큰 단점은 스프링의 빈으로 등록한 DataSource를 사용 못함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ae1a8455-d528-414f-a305-21bf38d7ae8b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;스프링이 제공하는 바이트코드 위빙 기법도 적용할 수 없음&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1ee8e1ec-37ef-454a-8f88-2f4a58337ec1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;실전에서 이 방법을 사용하는건 좋지 않음&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;7c51909e-9f8f-47c9-ad87-2a3a16fbcbb7&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;b1bc03c6-8832-446e-846a-183e6ea21c56&quot; class=&quot;&quot;&gt;JavaEE 5 서버가 제공하는 EntityManagerFactory&lt;/h2&gt;&lt;ul id=&quot;b9a4119b-6a4b-4464-ac40-ab835bb0873d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA는 JavaSE 환경보다는 JavaEE에서 서버가 제공하는 JPA 프로바이더를 통해 사용하는 것이 일반적인 방법&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;43093ede-c147-4dba-be8e-a5ab6ae46314&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링에선 JNDI를 통해 서버가 제공하는 EntityManager와 EntityFactory를 제공 받음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6dc03d2f-80af-4789-9d5f-d0da27654031&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;서버의 JTA를 이용해 트랜젹솬 관리 기능을 활용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ca0d6940-3adb-401b-ada6-7cd16c597177&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 방식은 JPA를 지원하는 JavaEE 5이상의 서버에 배치하고 JPA 프로바이더와 서버가 요구하는 설정을 해뒀다고 전제&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;36a84a89-207a-4959-8202-a29d42e3e2e3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;모든 JPA 기능은 서버와 JPA 퍼시스턴스 유닛 설정을 따름&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;aa40d2f0-d244-448a-99b3-f088e26dbad2&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;jee:jndi-lookup id=&amp;quot;emf&amp;quot; jndi-name=&amp;quot;persistence/myPersistenceUnit&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;6d6ee4a6-d9ed-490e-afeb-09ede310b0b4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;jndi-name은 JNDI로 등록된 퍼시스턴스 유닛의 이름을 지정&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;d832d44b-e339-4cf2-88cb-6ebe53f1432d&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;586dbfe9-1d11-4983-8e07-048431937856&quot; class=&quot;&quot;&gt;LocalContainerEntityManagerFactoryBean&lt;/h2&gt;&lt;ul id=&quot;1a2cf258-de57-49f9-beab-04fb084f37ed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링이 직접 제공하는 컨테이너 관리 EntityManager를 위한 EntityManagerFatocy를 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5db75569-8f60-42f4-b9e5-88201f96d74e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JavaEE 서버에 배치하지 않아도 컨테이너에서 동작하는 JPA 기능 활용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;81cae1a4-9ea0-4f3a-a9b9-fdbc96fd83f9&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링이 제공하는 일관성 있는 데이터 액세스 기술 접근 방법도 적용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;15a2991a-9ca1-4fc6-8dd9-53d322828b3b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링의 JPA 확장 기능도 활용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;95064f18-2127-477f-95c9-38a06f78c773&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;emf&amp;quot;
			class=&amp;quot;org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean&amp;quot;&amp;gt;
		&amp;lt;property name=&amp;quot;dataSource&amp;quot; ref=&amp;quot;dataSource&amp;quot; /&amp;gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;8e0a7d5a-e22a-4f66-a29c-4c56d36c8f8b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 빈은 META-INF/persistence.xml을 참고해 퍼시스턴스 유닛과 이를 활용하는 EntityManagerFactory를 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1c3fab21-c6e6-4570-8d83-10ed7a03b4d1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB 연결정보는 persistence.xml 프로퍼티에 등록하지 않아도 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;23ee28f5-ec44-42a3-8fcc-a568c70aac08&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;대신 스프링에 빈으로 DataSource를 JPA에서 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;20728d03-010e-4333-8577-c8debe73c0ea&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;META-INF/persistence.xml 파일 예시&lt;pre id=&quot;3bcfcd6b-5472-4df4-ba51-df356dba11bb&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;persistence xmlns=&amp;quot;http://java.sun.com/xml/ns/persistence&amp;quot;
							xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
							xsi:schemaLocation=&amp;quot;http://java.sun.com/xml/ns/persistence
							http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd&amp;quot; 
							version=&amp;quot;2.0&amp;quot;&amp;gt;
		&amp;lt;persistence-unit name=&amp;quot;default&amp;quot;&amp;gt;
				&amp;lt;class&amp;gt;springbook.learningtest.spring.jpa.Member&amp;lt;/class&amp;gt;
				&amp;lt;exclude-unlisted-classes /&amp;gt;

				&amp;lt;properties&amp;gt;
						&amp;lt;property name=&amp;quot;eclipselink.waving&amp;quot; value=&amp;quot;false&amp;quot; /&amp;gt;
				&amp;lt;/properties&amp;gt;				
		&amp;lt;/persistence-unit&amp;gt;
&amp;lt;/persistence&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;1a047aab-f69b-4400-848c-635ea65a4a2d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;일부 프로퍼티 설정은 JPA 구현 제품마다 다름을 주의&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;28c0c382-1d1c-4de3-92ae-be0e58add200&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;자바오브젝트와 RDB 테이블 사이의 매핑과 변환을 위한 정보는 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;orm.xml과 같은 매핑 정보를 담은 파일에 정의&lt;/strong&gt;&lt;/span&gt;하거나 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;애노테이션을 이용해 클래스 안에 정의 가능&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;ca994cd8-f553-4e95-ac57-b024a8e7658e&quot; class=&quot;code&quot;&gt;&lt;code&gt;@Entity
public class Member {
		@Id
		int id;

		@Column(length=100)
		String name;
	
		@Column(nullable=false)
		double point;
		
		// 수정자(setter), 접근자(getter)
		...
}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;98e5ac68-5ba4-4389-8da4-33a5dc23c023&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;LocalContainerEntityManagerFactoryBean에는 dataSource 외에 다음과 같은 프로퍼티 추가가 가능&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;ed2f63e8-93ca-43c5-a256-7bdc7a4e3cc7&quot; class=&quot;&quot;&gt;persistenceUnitName&lt;/h3&gt;&lt;ul id=&quot;25d2bbd6-fb98-4987-82a2-f740db2a3d14&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;persistence.xml에는 하나 이상의 퍼시스턴스 유닛이 정의될 수 있음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;34a9d315-679d-4bde-8380-73a2877a4297&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;persistence.xml에 다음과 같이 퍼시스턴스 유닛이 정의되어 있고, 이 설정을 따라 EntityManagerFactory 빈을 정의해야한다면 아래와 같이 추가&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;6883d7fe-82ea-4296-b4d1-27add0d2fa4c&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;!--persistence.xml--&amp;gt;
&amp;lt;persistence-unit name=&amp;quot;subPersistenceUnit&amp;quot;&amp;gt;

&amp;lt;!-- LocalContainerEntityManagerFactoryBean --&amp;gt;
&amp;lt;property name=&amp;quot;persistenceUnitName&amp;quot; value=&amp;quot;subPersistenceUnit&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;babc20df-50a6-44ff-88dd-9fdf2cc33f11&quot; class=&quot;&quot;&gt;persistenceXmlLocation&lt;/h3&gt;&lt;ul id=&quot;6bbb2e30-ec36-4513-b471-a08cab4e6557&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;LocalContainerEntityManagerFactoryBean은 디폴트 위치인 META-INF에서 persistence.xml 파일을 찾음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0d66f261-592a-495c-a888-c419644cece1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;일부 WAS에서는 META-INF/persistence.xml 파일을 자동으로 인식해서 서버가 관리하는 EntityManagerFactory와 충돌이 발생&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;cacd336e-e314-437a-8972-49e140248f4e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;따라서 스프링이 제공하는 컨테이너 관리 EntityManager를 적용하고 동시에 JPA 프로바이더를 제공하는 WAS에 배포할 경우 디폴트 위치에 persistence.xml을 넣는건 피해야 함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b07a3556-8784-4d9a-bfd3-b519efe1ab3c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;persistenceXmlLocation의 프로퍼티에 파일 위치를 지정하여 변경&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0ccae54d-9fa6-4a26-93fe-f2809fcd5c48&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;가장 간단한 방법은 파일의 이름을 spring-persistence.xml과 같이 변경하는 방법&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;ffe06ec1-8fc9-4c4a-88a0-60ff4b985036&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;property name=&amp;quot;persistenceXmlLocation&amp;quot; value=&amp;quot;META-INF/spring-persistence.xml&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;79390dcb-4a42-459b-8dd9-90604b82c1e3&quot; class=&quot;&quot;&gt;jpaProperties, jpaPropertyMap&lt;/h3&gt;&lt;ul id=&quot;a72e2d00-082e-4f33-bd4a-6831d84fee8a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;EntityManagerFactory를 위한 프로퍼티를 지정할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ed6561d4-2498-48dc-8049-5e277bc1c7cb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;jpaProperties는 &amp;lt;props&amp;gt;를 이용, jpaPropertyMap은 &amp;lt;map&amp;gt;을 이용해 정보를 입력&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;b69584a5-2493-407d-a9f1-34a188f953f1&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;!--persistence.xml--&amp;gt;
&amp;lt;persistence-unit name=&amp;quot;default&amp;quot;&amp;gt;
		...
		&amp;lt;properties&amp;gt;
				&amp;lt;property name=&amp;quot;eclipselink.waving&amp;quot; value=&amp;quot;false&amp;quot; /&amp;gt;
		&amp;lt;properties&amp;gt;
&amp;lt;/persistence-unit&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;e4723ed0-abd0-4af0-821c-8b0b3ebec7e7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;persistence.xml 파일 대신 스프링의 LocalContainerEntityManagerFactoryBean 빈에 정의&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;c7b58d73-19a2-464c-9655-1bd0cabe1a24&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;!--LocalContainerEntityManagerFactoryBean--&amp;gt;
&amp;lt;property name=&amp;quot;jpaProperties&amp;quot;&amp;gt;
		&amp;lt;props&amp;gt;
				&amp;lt;prop key=&amp;quot;eclipselink.waving&amp;quot;&amp;gt;false&amp;lt;/prop&amp;gt;
		&amp;lt;/props&amp;gt;
&amp;lt;/property&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;32f82bad-f7a6-4607-8825-4adebcfc17c1&quot; class=&quot;&quot;&gt;jpaVendorAdapter&lt;/h3&gt;&lt;ul id=&quot;2fe8de6d-7a28-4c72-9e54-4574a14139e1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JPA는 비슷한 기능이지만 벤더별로 다른 설정 프로퍼티를 사용해야 하는 경우가 많음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;004d7bf5-6440-48b4-9bd1-5a6921600aed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;구현 벤더별로 다르게 지정되는 프로퍼티나 설정을 JpaVendorAdapter를 이용하면 스프링이 정의한 표준 프로퍼티를 이용해 지정 가능 &lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;dcdb9c20-5a8f-4c86-9bd7-fd3929631c10&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JPA는 코드상에서 데이터 액세스 로직을 작성할 때 자바오브젝트와 전용 쿼리 언어, Criteria 등을 이용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;01437d79-8519-4b46-b3dd-5e63cd40f597&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;이런 API와 오브젝트 쿼리 등을 DB가 이해할 수 있는 SQL 언어로 전환해서 처리&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6e10aad0-02ac-4de6-9322-b4760d23e5b2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;ORM 계층의 언어와 API가 아닌 DB SQL을 출력하고 싶을때 아래와 같이 옵션 설정&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;bb97423e-cd66-4f91-8b91-dcb15c4ce92b&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;property name=&amp;quot;jpaVendorAdapter&amp;quot;&amp;gt;
		&amp;lt;bean class=&amp;quot;org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter&amp;quot;&amp;gt;
				&amp;lt;property name=&amp;quot;showSql&amp;quot; value=&amp;quot;true&amp;quot; /&amp;gt;
		&amp;lt;/bean&amp;gt;
&amp;lt;/property&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;c485ccc1-a727-448a-b484-f3efcd20ffcf&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;showSql이라는 프로퍼티는 true, false로 지정 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ebc94ea5-44b6-481e-af84-4dd95d548dc8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;밴더 어댑터에 맞는 설정으로 변환 (EclipseLink: eclipselink.logging.level=FINE, 등)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;48566399-7cca-4f6e-8ff6-c54b4c4b4820&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;스프링 3.1에선 EclipseLink. Hibernate, OpenJpa, TopLink 네가지 벤더를 위한 JpaVendorAdapter를 지원&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7ecffd63-ce57-42e1-a334-956943da8e38&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;code&gt;JpaVendorAdapter&lt;/code&gt;를 이용하면 &lt;code&gt;showSql&lt;/code&gt;뿐 아니라 매핑 DDL을 자동생성해주는 &lt;code&gt;generatedDdl&lt;/code&gt;과 DB 종류인 &lt;code&gt;database&lt;/code&gt;, DB 플랫폼 정보인 &lt;code&gt;databasePlatform&lt;/code&gt; 등을 지정&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;75ca8fbc-a41f-4f90-89b2-b4ebf9ed6f5f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;이 외에도 각 벤더의 JPA 구현에 따라 달라지는 다양한 정보를 &lt;code&gt;EntityManagerFactory&lt;/code&gt; 생성을 위헤 제공&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;82388b83-51a0-41e5-bcf1-173522d063e1&quot; class=&quot;&quot;&gt;loadtimeWeaver&lt;/h3&gt;&lt;ul id=&quot;24f2481b-aa41-40b1-a65e-c1b8ab08a715&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JPA는 POJO 클래스를 ORM의 엔티티로 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;10ab5ec7-b7c7-4c6f-8c66-8f7b5b610480&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;POJO방식의 단점은 오브젝트가 만들어 진 후엔 컨테이너가 직접 관리할 수 없다는 점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ac8028ff-b640-49dc-803a-9653c087c78d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;엔티티 사이에 관계도 JPA 인터페이스가 아닌 직접 POJO 오브젝트끼리 연결 되있음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b9aec16e-2ab1-453d-aa52-f7e35134af1b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JPA는 그래서 단순한 자바 코드로 만들어진 엔티티 클래스의 바이트코드를 직접 조작해서 확장된 기능을 추가하는 방식을 이용&lt;ul id=&quot;efc8b463-796d-4493-ac2e-2b7b98f0c12f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;엔티티 오브젝트 사이에 지연된 로딩이 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;43b86b48-9545-4ea5-ba25-6182febe5ad3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;엔티티 값의 변화를 추적 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7fd3d04e-592a-47e0-a770-4a0b7790f555&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;최적화와 그룹 페칭(fetching) 등의 고급 기능을 적용 가능&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fcef5c52-1521-4df1-aba4-16b839ae1d5f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;이미 &lt;strong&gt;컴파일된 클래스 바이트 코드를 조작해서 새로운 기능을 추가하는 것&lt;/strong&gt;을 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;바이트코드 향상 기법&lt;/strong&gt;&lt;/span&gt;이라고 함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a7b16d62-362e-40ca-860e-f36e67c3df75&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;클래스의 바이트 코드를 향상시키는 방법은 두가지&lt;ul id=&quot;f014233e-c80a-4323-a3b5-39ca16857a2a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;바이트코드를 빌드 중에 변경하는 것, JPA 벤더가 제공하는 바이트 코드 컴파일러가 필요하며 매번 빌드 작업중에 이 과정을 반드시 거쳐야 함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9201bb5a-bf81-485c-96b4-5b03fca21a87&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;런타임 시에 클래스 바이트코드를 메모리에 로딩하면서 다이내믹하게 바이트코드를 변경해서 기능을 추가하는 방법&lt;ul id=&quot;5770b775-9c77-4398-82e2-78cb30958373&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;특별한 툴과 ANT 등을 이용한 번거로운 빌드 작업을 추가하지 않아도 되기 떄문에 애용되는 방법&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b99aeb32-2fd3-41e5-a2c5-3c2af438d399&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;strong&gt;런타임 시에 클래스를 로딩하면서 기능을 추가하는 것&lt;/strong&gt;을 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;로드타임 위빙&lt;/strong&gt;&lt;/span&gt;이라 하고 이런 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;기능을 가진 클래스를 로드타임 위버&lt;/strong&gt;&lt;/span&gt;라고 부름&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e38cb3f5-218a-442a-af12-5f81c6b96406&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;자바 5 이상에서는 JVM을 기동할 때 javaagent 옵션을 줘서 JVM이 로딩하는 모든 자바 클래스를 조작할 수 있는 기능을 넣었음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;74cf911b-2a78-438f-bbfd-86eafcf1b9e4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;JPA 구현 제품은 대부분 자바 에이전트를 이용해 로드타임 위버를 적용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;4da26ffc-c388-4e74-a93d-efbc6d82ce6a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;자바 에이전트는 간단해 보이지만 단점이 많음&lt;ul id=&quot;1b97c0ae-1414-46ce-8fb5-d24b270714a6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;엔티티 클래스는 몇십 개지만, JVM을 통해 로딩되는 모든 클래스를 일일이 다 확인&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ecadc486-1c5f-496a-bd81-080e78370970&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;서버환경에서는 기동하는 JVM에 자바 에이전트를 설정해줘야하고, 운영정책과 관리 측면에서 부담을 줄 수 있어서 거부될 위험이 많음&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6ef439e8-f6ef-42d1-b835-ddadd427d47a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;스프링은 자바 에이전트 대신 특별한 클래스 로더를 이용해 로드타임 위빙 기능을 제공&lt;/strong&gt;&lt;/span&gt;&lt;ul id=&quot;96b4a424-151f-4a7e-9698-c1567e510159&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;JPA 벤더에 종속되지 않는 방법을 통해 로드타임 위빙 기능 적용 가능 (5장 참고)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;184fa92f-41dc-4191-b5d8-c4b0d506b87c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:square&quot;&gt;org.springframework.instrument-3.0.7.RELEASE.jar를 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;0834e58b-0f84-486d-a640-2b5b7634a07d&quot; class=&quot;code&quot;&gt;&lt;code&gt;//자바 에이전트
-javaagent:eclipselink.jar

//스프링이 제공하는 자바 에이전트
-javaagnet:lib/org/springframework.instrument-3.0.7.RELEASE.jar&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ff949434-4083-43bd-94d6-1d654e48b0ea&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;LocalContainerEntityManagerFactoryBean의 loadtimeWaver프로퍼티를 아래로 지정&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;81e7acae-2df3-48d8-aa6a-206f4c0241e3&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;property name=&amp;quot;loadTimeWeaber&amp;quot;&amp;gt;
		&amp;lt;bean class=
		&amp;quot;org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver&amp;quot; /&amp;gt;
&amp;lt;/property&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;09e58ce3-5997-4726-b204-df23b2d4137a&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;5700c8fb-8c29-40e7-9f2b-220cde94a6f9&quot; class=&quot;&quot;&gt;트랜잭션 매니저&lt;/h2&gt;&lt;ul id=&quot;8d83b7ae-b7bf-489c-8b1e-311c8fd27e0e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;컨테이너가 관리하는 &lt;code&gt;EntityManager&lt;/code&gt; 방식에는 컨테이너가 제공하는 트랜잭션 매니저가 반드시 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;4c37d73f-0a44-443a-b14c-5d323e8f890b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링의 EntityManager를 사용하려면 적절한 트랜잭션 매니저 등록이 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c3807b86-3229-4f61-a01e-5c94b18c99be&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC는 트랜잭션 매니저가 없어도 동작, JDBC 자체가 자동 트랜잭션 모드를 갖고 있기 때문에 명시적으로 트랜잭션 관리를 안해도 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1b0f9348-1275-41c2-ae94-eade8f0abbf2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;반면 JPA는 반드시 트랜잭션 안에서 동작하도록 설계&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ee2e91ce-b594-4df7-b025-1da497b7a2ac&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LocalContainerEntityManagerFactoryBean을 통해 컨테이너 관리 EntityManger를 사용할 때는 트랜잭션 매니저를 다음과 같이 추가&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;713ae902-f455-4751-ae52-3a45ac2080f7&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;emf&amp;quot; class=
			&amp;quot;org.springframework.orm.jpa.localContainerEntityManagerFactoryBean&amp;quot;&amp;gt;
		...
&amp;lt;/bean&amp;gt;

&amp;lt;bean id=&amp;quot;transactionManager&amp;quot;
			class=&amp;quot;org.springframework.orm.jpa.JpaTransactionManager&amp;quot;&amp;gt;
		&amp;lt;property name=&amp;quot;entityManagerFactory&amp;quot; ref=&amp;quot;emf&amp;quot; /&amp;gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;926af624-fe2e-416e-b6be-63c47a4ed07b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA를 이용하는 DAO 코드는 스프링이 관리하는 트랜잭션 관리 기능을 이용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2d218111-cb93-4a45-80fb-69aa14cd90e7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@Transactional이나 트랜잭션 AOP를 이용해서 트랜잭션 경계설정을 해주면 자동으로 JPA 트랜잭션을 시작하고 커밋하도록 만듬&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fcb49809-1ba5-400f-91ef-7a2ac63c7e45&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JpaTransactionManager&lt;/code&gt;를 사용하면 &lt;code&gt;DataSource&lt;/code&gt;를 공유하는 JDBC DAO와 트랜잭션 공유 가능 (서비스 계층의 코드가 JPA DAO와 JDBC DAO를 하나의 트랜잭션 안에서 사용 가능)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c738ddde-34eb-4dde-b690-805842854ac7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JTA 트랜잭션을 이용하는 경우라면 JtaTransactionManager를 사용&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
  
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.4.2 EntityManager와 JpaTemplate&lt;/h2&gt;&lt;ul id=&quot;875727ec-719d-4ba1-be7e-cc8648aaf2ed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC나 iBatis를 사용한 템플릿처럼 JPA도 템플릿 방식을 지원&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;50ff17e9-b83a-4162-980d-5b948e9ecb96&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;템플릿을 통해 JPA 코드가 스프링 트랜잭션과 동기화 할 수 있도록 하고 예외를 변환하는 등의 기능을 지원 받음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;28eaaef1-ca32-40e0-980b-99e33faf12ef&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링에선 JpaTemplate뿐 아니라 JPA API를 직접 사용해 DAO를 작성 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a70c5f9c-800b-44ae-a8c0-4177df23afef&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA의 핵심 프로그래밍 인터페이스는 EntityManager&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b28cd68f-6417-4793-b0d1-3551a766b332&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManager 오브젝트를 가져올 수 있으면 JPA의 모든 기능을 이용 가능&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;aec12c64-187e-444a-851b-c491afe96388&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;65514127-4840-4e41-82ce-14a01f6e2906&quot; class=&quot;&quot;&gt;JpaTemplate&lt;/h2&gt;&lt;ul id=&quot;675979aa-07c2-4857-9b24-8c5bf36653df&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;jdbcTemplate, SqlMapClientTemplate와 동일하게 템플릿 방식으로 JPA 코드를 작성 가능&lt;ul id=&quot;5c92a2c8-60df-4e21-8091-7bbc65393f29&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;장점 : 템플릿을 이용하면 반복 작업을 줄여주고 예외 변환같은 편리한 기능을 제공&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5c157594-3418-47ba-8be4-51d1dca3102d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;단점 : 데이터 액세스 기술이 직접 제공하는 API 대신 템플릿의 메소드와 콜백을 사용&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6656e3ef-419e-42fd-ba2c-58623ddcb8b5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링에선 JPA를 사용할 때 JpaTemplate은 자주 사용 안함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;13931f00-25bf-413b-b64b-aa4922ac95a2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA API가 익숙치 않고 스프링 템플릿 방식이 편리할 때 JpaTemplate를 사용 권장&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;764291c9-f948-47fa-8684-1f1a4fb95e9e&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberTemplateDao {
		private JpaTemplate jpaTemplate;

		@Autowired
		public void init(EntityManager emf) {
				jpaTemplate = new JpaTemplate(emf);
		}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;000574f0-dd02-4ded-94c5-92f06659fe6d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JpaDaoSupport&lt;/code&gt; 클래스를 상속해서 DAO를 만들면 &lt;code&gt;JpaTemplate&lt;/code&gt; 생성코드 생략 가능&lt;ul id=&quot;92fd29fd-6bc9-4746-b1d2-373439c05d0a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;code&gt;JpaTemplate&lt;/code&gt; 필요할 떄는 &lt;code&gt;getJpaTemplate()&lt;/code&gt;를 이용&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;91d4733f-1501-47e1-9804-24a4b8c90c20&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JpaTemplate&lt;/code&gt;를 사용할 떄는 기본적으로 &lt;code&gt;JpaCallback&lt;/code&gt; 인터페이스의 &lt;code&gt;doInJpa()&lt;/code&gt;에 필요한 작업을 입력&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2ea95c04-abd0-4fc6-ba9b-86f01f777062&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;DoinJpa()&lt;/code&gt;는 파라미터로 &lt;code&gt;EntityManager&lt;/code&gt;를 전달, 이를 통해 모든 JPA 기능을 사용가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;56100ff7-e920-4272-9401-e3e24e491b09&quot; class=&quot;code&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; ms = templateDao.jpaTemplate.execute(new JpaCallback&amp;lt;List&amp;lt;Member&amp;gt;&amp;gt;() {
		public List&amp;lt;Member&amp;gt; doInJpa(EntityManager entityManager) throws
				PersistenceException {
				return entityManager.createQuery(&amp;quot;select m from Member m&amp;quot;.getResultList();
		}
});&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;36714fa5-65e3-4fde-8312-b5e7f83c41b3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JpaTemplate은 콜백 오브젝트 없이도 간단한 메소드를 이용해 EntityManager가 제공하는 대부분의 기능을 사용 가능하게 해줌&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;617b8164-e571-415f-b85a-bf4b26706e1c&quot; class=&quot;code&quot;&gt;&lt;code&gt;Member m = new Member(1, &amp;quot;Spring&amp;quot;, 8.9);
jpaTemplate.persist(m);
Member m2 = templateDao.jpaTemplate.find(Member.class, 1);&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;a84f304d-a6c6-4dd1-8cf8-2f77a4540803&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;4ac04713-9f10-4928-8ce1-4d49cbe1e784&quot; class=&quot;&quot;&gt;애플리케이션 관리 EntityManager와 @PersistenceUnit&lt;/h2&gt;&lt;ul id=&quot;51b9c991-d5aa-441f-9180-a4247941d438&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;애플리케이션 코드가 관리하는 EntityManager는 JavEE환경과 JavaSE 모두 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;942112c4-f1e1-4aa8-9dd0-6d377a04d4ce&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManager는 EntityManagerFactory가 있다면 다음과 같이 직접 생성&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;9503d1b5-e18a-4662-a96a-7b8eecb1de2c&quot; class=&quot;code&quot;&gt;&lt;code&gt;EntityManager em = entityManagerFactory.createEntityManager();&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;992bd7c6-75d6-454a-816e-47bbce4fe6c4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;컨테이너가 관리하지 않는 EntityManager이므로 트랜잭션은 다음과같이 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;cd25923b-de5f-4869-b51f-e5ab08b69d90&quot; class=&quot;code&quot;&gt;&lt;code&gt;em.getTransaction().begin();

Member m = new Member(1, &amp;quot;Spring&amp;quot;, 7.8);
em.persist(m);
Long count = em.createQuery(&amp;quot;select count(m) from Member m&amp;quot;, Long.class)
							.getSingleResult();

em.getTransaction().commt();&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;88cfd523-1e00-4701-891b-b089be13166f&quot; class=&quot;&quot;&gt;@Autowired, @Resource&lt;/h3&gt;&lt;ul id=&quot;41102d10-21e0-44c9-991c-8dbe162e9054&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManagerFactory를 빈으로 등록하는 것은 LocalContainerEntityManagerFactoryBean을 이용하는 방법과 JNDI를 통해서 서버가 제공하는 EntityManagerFactory를 가져와 빈으로 사용하는 방법 두가지가 존재&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;35bac8fd-741f-4f00-8fae-e3ffddeb104d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;어떤 방법이든 EntityManagerFactory는 빈으로 등록되므로 @Autowired, @Resource 또는 일반적인 스프링 DI방식으로 DAO 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;9805201f-74e5-4ba1-a6e8-10ebe8d58af2&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		@Autowired EntityManagerFactory emf;

		public void addMember(Member member) {
				EntityManager em = emf.createEntityManager();
				...
		}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;7bb9aad5-01fb-469f-a71c-6c1a755bb3bd&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManagerFactory는 EntityManager를 만들 수 있는 createEntityManager()를 제공&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;8770c48d-65d4-4a72-8506-dd5dbc5d3bcf&quot; class=&quot;&quot;&gt;@PersistenceUnit&lt;/h3&gt;&lt;ul id=&quot;17e9d847-febe-437b-ad5e-ba0b73df3968&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EJB에서 JPA를 사용할 때와 비슷&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;99769502-6283-440d-b24e-e5a24a0d75c1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링의 DI 방식 대신 JPA 표준 스팩에 나온 방식을 이용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c7dd3964-6fd8-46f9-9528-0f8bf8a50915&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;javax.persistence 패키지의 @PersistenceUnit 애노테이션을 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;85447b98-0016-4ad3-b418-61390961cdb9&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		@PersistenceUnit EntityManagerFacotry emf;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;a55cf008-a3bc-4736-a52d-5fbe2c621cb4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt;를 쓸때와 다른점은 스프링 의존도가 전혀 없는 순수한 JPA 코드라는 점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c1134786-7fd6-4b3d-bd7c-bf6613c4f6a7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JavaEE 컨테이너에서 EntityManagerFactory를 제공받아 사용하는 전형적인 JPA 코드&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;4d1cc9f4-7b0c-4bd7-afc3-303aec6c5332&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@PersistenceUnit에 의해 주입되려면 애노테이션을 이용한 의존관계 설정이 가능한 컨테이너이거나, XML에 반드시 다음 설정이 필요&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;95394709-07ad-40a2-a0a4-27dc03ca6546&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;context:annotation-config /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;22f7fae3-421e-4aee-b7c3-4f161d612fc8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;내부적으론 &lt;code&gt;&amp;lt;context:annotation-config /&amp;gt;&lt;/code&gt;에 의해 자동등록되는 &lt;code&gt;PersistenceAnnotationBeanPostProcessor&lt;/code&gt; 후처리기가 @PersistenceUnit에 대한 DI 담당&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;14046624-b333-447f-b779-1a0005772511&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;ul id=&quot;85447090-5385-41c1-9972-57cdee1d9c5d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManagerFactory를 직접 이용하는 방법은 실제로 자주 사용 안함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c33666cc-a0d6-4321-b6c3-0eabc2f185d0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManagerFactory 인터페이스에서 제공하는 QueryBuilder, Metamodal, PersistenceUnitUtil을 가져오거나 캐시나 프로퍼티 정보를 참조할 필요가 있을때 사용&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;23625a58-d3e2-4fee-9126-395ce76593cb&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;f0623542-3b40-40f1-a5c1-a7c95dcf58c3&quot; class=&quot;&quot;&gt;컨테이너 관리 EntityManager와 @PersistenceContext&lt;/h2&gt;&lt;ul id=&quot;33f6ebae-1d62-4dd6-a296-0dcae08f5f19&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DAO가 컨테이너로부터 EntityManager를 직접 주입받으려면 JPA의 @PersistenceContext을 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;75fb62d3-a15f-418d-b381-2c2523b4dca9&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManager는 스프링의 빈으로 등록하지 않음, 따라서 스프링 DI 방법으론 주입X&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e3a253b2-450d-4d79-99ad-06cdfe6bbe24&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링에서는 JavaEE 컨테이너가 관리하는 EntityManager를 주입받는 방법을 스프링 애플리케이션의 코드에도 동일하게 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;421f3f23-767f-40f2-8ea8-fb774e692080&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;표준 스펙을 따르는 프로그래밍 모델을 스프링에서도 동일하게 사용 가능해짐&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;46ff17e0-1aa6-486c-80b9-300a842e2f60&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;LocalContainerEntityManagerFactoryBean에 의해 등록된 EntityManagerFactory로부터 컨테이너가 관리하는 EntityManager를 직접 DOA에 주입받는 예시&lt;pre id=&quot;31f2a274-f156-4265-aedf-3da69cb41d0b&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		@PersistenceContext EntityManager em;

		public void addMember(Member member) {
				em.persist(member);
		}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;db269887-02b0-4747-9127-12e071a70a8c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;EntityManager는 인스턴스 변수에 한 번 주입받아서 재사용 못함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;224cfba1-2d5f-48d2-bda3-4dcfe6e38364&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;EntityManager는 그 자체로 멀티스레드에서 공유 할 수 없음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2f88e83b-f3da-4429-81aa-bc2d29bb726a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;트랜잭션마다 하나씩만 만들어져서 사용되고 트랜잭션이 종료되면 함꼐 제거가 돼야 함&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;314f72eb-2389-4111-b3cc-7feaf72f4362&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;인스턴스 변수에서 한번 DI 받아놓고 여러 스레드에서 사용할 수 있는 이유&lt;ul id=&quot;9b2f6da7-b437-4fd2-9187-de03036396ef&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;@PersistenceContext로 주입받은 EntityManager는 실제가 아니라 현재 진행 중인 트랜잭션에 연결되는 퍼시스턴스 컨텍스트를 갖는 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;일종의 프록시&lt;/strong&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;99bf68e0-0012-42ba-96e7-64fdff8271d0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;하나의 오브젝트를 공유하는 듯하지만 각 스레드가 자신의 컨텍스트에 따라서 만들어진 독립적인 오브젝트를 사용하도록 연결해주는 기능을 가진 프록시를 이용하는 것&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;49d81f07-2d15-42eb-9868-153827d24655&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;컨테이너가 관리하는 EntityManager도 이와 비슷한 방식으로 동작&lt;ul id=&quot;532eeb89-8a0f-4bde-88c3-22a462273dd8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;DAO에서 마치 하나의 EntityManager를 독점적으로 사용하듯이 접근하지만 실제로는 트랜잭션마다 다른 EntityManager 오브젝트를 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;be562179-2c6f-468e-90a3-5cbc445c3af1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;code&gt;EntityManager&lt;/code&gt;가 존재하는 컨텍스트가 트랜잭션 범위이므로 type 앨리먼트는 아래와 같이 default 값이 적용&lt;pre id=&quot;97b05e6c-fff2-4e0b-845c-958f9e21ea38&quot; class=&quot;code&quot;&gt;&lt;code&gt;@PersistenceContext(type=PersistenceContextType.TRANSACTION) EntityManager em;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;3ac52926-47ab-4e04-a82a-f780c9e4da06&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA 스펙에 따르면 트랜잭션 스코프의 퍼시스턴스 컨텍스트는 JTA를 통해 트랜잭션 관리&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;cebf6506-8a9b-4905-aab1-8aaffc72318a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링은 이를 &lt;code&gt;JpaTransactionManager&lt;/code&gt;를 통해 관리하기 떄문에 &lt;code&gt;JavaEE&lt;/code&gt; 서버의 트랜잭션 매니저와 JTA가 없어도 JPA의 장점인 &lt;code&gt;@PersistenceContext&lt;/code&gt;를 통한 &lt;code&gt;EntityManager&lt;/code&gt; 주입 가능&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;54d7d9ba-bb61-425e-9a9f-6ed7755523d9&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;e8ab58a4-9511-47c2-90a8-fb2cca2529d7&quot; class=&quot;&quot;&gt;@PersistenceContext와 확장된 퍼시스턴스 컨텍스트&lt;/h2&gt;&lt;ul id=&quot;86247da2-4cf0-4e45-ae4a-389265063bb6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@PersistenceCOntext를 이용해서 컨테이너가 관리하는 EntityManager를 주입&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;daf24a5a-1901-4b83-8da1-cf8d2f498eea&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;다만 type 앨리먼트의 값이 다름, type을 &lt;code&gt;PersistenceContextType.EXTENDS&lt;/code&gt;로 지정&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;4b0c16c4-4450-4ffa-a95d-f57fb5ebf8cf&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;트랜잭션 스코프 대신 확장된 스코프를 갖는 EntityManager가 만들어짐&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;164bc377-819c-4add-8262-bcbf85890ad6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA에서 확장된 퍼시스턴스 컨텍스트는 상태유지 세션빈에 바인딩되는 것을 의미&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;49c5785b-4a8c-4c9c-b7b1-570f756b55b0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;상태유지 세션빈은 사용자별로 독립적이며 장기간 보존되는 오브젝트를 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a29ab05b-7dbe-4b9c-809b-776647e3b0ec&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;세션빈에 바인딩되는 EntityManager 역시 사용자별로 독립적으로 장기간 보존&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2a3e22dd-5e3f-48df-85c4-a37803d8a9ce&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;상태를 가진 세션빈이나 장기간 지속되는 스코프 빈에만 싱글톤 빈으로 사용 가능&lt;ul id=&quot;90bcfa6f-96f6-4e84-b00c-0d7eafba4052&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;하나 이상의 오브젝트로 만들어지기 때문에 각각 독립적으로 EntityManager를 가질 수 있기 때문에 스코프 프록시를 사용할 필요가 없음&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;1de83700-086d-4122-862a-667c71b81759&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;1893957f-8767-4d59-87ce-c590e90154fb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;확장된 퍼시스턴스 컨텍스트는 싱글톤 빈에 적용하면 안되며, 상태를 가진 세션빈 또는 스프링 스코프 빈의 활용 방법을 잘 이해하고 이에 맞게 EntityManager 활용할때 추천&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;6067ecb3-6f6f-4b90-b7be-ea0c8379d093&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;e57a46dd-4dd1-46b3-b6d5-c13d22cdd234&quot; class=&quot;&quot;&gt;JPA 예외 반환&lt;/h2&gt;&lt;ul id=&quot;c3f2bb59-9de3-4d23-9a32-fc70c88bd79a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JpaTemplate이 JPA API를 직접 사용하는 방법이 좀 더 나은 점은 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;JPA의 예외를 스프링의 데이터 액세스 예외 추상화 클래스 계층인 DataAccessException의 예외를 반환&lt;/strong&gt;&lt;/span&gt;해준다는 점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;155c34d5-6505-4357-92b4-80cc76648f60&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA의 API는 자동 예외 변환이 발생X, 런타임 예외를 발생시키기 떄문에 try/catch 블록이나 throws 선언이 필요 없음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;3d15aa03-f7eb-4713-8a15-422eaf1000cb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;EntityManager와 같은 리소스 관리는 JPA 지원 컨테이너가 알아서 관리&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;6886ea67-386b-4b71-ace8-55ace3b78939&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;b8d7abc7-108f-414d-acb6-d183dfbe2112&quot; class=&quot;&quot;&gt;JPA 예외 변환 AOP&lt;/h2&gt;&lt;ul id=&quot;8065a297-7d60-413f-ae5b-9563452b3732&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA API를 직접 이용하는 경우에도 JPA 예외를 스프링의 DataAccessException 전환 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;d15e9707-dcd9-4f00-9fb3-af81ce94e495&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;AOP를 이용해서 JPA API가 던지는 JPA 예외를 스프링의 예외로 전환하는 부가기능을 추가&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;85db0b95-1a63-4eb6-bf68-2c596ff59ce6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 방법을 이용하려면 다음 두가지 작업이 필요&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;70a320f1-47c0-461e-a4fd-15c900190afa&quot; class=&quot;&quot;&gt;@Repository&lt;/h3&gt;&lt;ul id=&quot;8647cfb1-8a76-4fe5-8fc5-69468486ff65&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;예외 변환이 필요한 DAO 클래스에 @Repository 애노테이션을 부여&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;54c3daf6-7290-42c5-885a-7d158ec46959&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@Repositry는 @Component와 같은 자동인식을 위한 스테레오타입 애노테이션&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;51412928-abae-4fbe-ad6a-21063af25b1a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;빈 스캐너를 사용하지 않는 경우에도 @Repository를 DAO에 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;01d17b4f-0ccf-4bfc-94b1-9a4eae06ca22&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@Repository가 붙은 DAO 클래스의 메소드는 AOP 예외 변환 기능이 부가될 빈으로 선정&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;092e6727-8a9c-4167-908e-e23988c6294a&quot; class=&quot;&quot;&gt;PersistenceExceptionTranslationPostProcessor&lt;/h3&gt;&lt;ul id=&quot;d6f11f5d-d0cb-439a-bcfc-e80b5fbec1da&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;@Repository가 붙은 빈을 찾아 예외 변환 기능을 가진 AOP 어드바이스를 적용해주는 후처리기가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;feb46ebb-eaae-4f2c-9173-119bd5e52dca&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;PersistenceExceptionTranslationPostProcessor를 빈으로 등록만 하면 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;c823b366-4e77-4e5b-ba5c-43a038b7322b&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;bean class=
&amp;quot;org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor&amp;quot; /&amp;gt;	&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;94fbeca4-fb94-4259-95d7-70709572d904&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 에러 코드를 직접 해석해서 일관된 의미의 예외로 변환해주는 JdbcTemplate의 예외 변환과는 달리, JPA의 예외 자체가 분류하기 힘든 예외로 던져주기 떄문에 해석해서 변환&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;612bf6f3-99ac-4207-81cd-5a710d536cc5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA 스펙이 정의하는 예외는 제한적, 대부분의 DB 예외는 벤더가 정의한 예외나 시스템 예외 등으로 포장돼서 전달되고 스프링은 포장된 예외의 코드 수준까지 분석해 변환하는 기능X&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;d0d4839c-08ec-4362-9cd3-64f85ce14b31&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JPA 실행 중에 발생한 DB 예외등은 JDBC와 다른 방식으로 전달, 패러다임이 다르기 떄문에 발생하는 근본적인 한계&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c7e8e153-dbd1-4632-af4d-3a6f19d0b0eb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JDBC/iBatis&lt;/code&gt;와 &lt;code&gt;JPA/하이버네이트&lt;/code&gt; 같은 ORM은 프로그래밍이 근본적으로 많은 차이 존재&lt;ul id=&quot;2e04dd2c-891a-4a8b-a467-483efddaf929&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;POJO 기반의 투명한 영속성이 적용된 ROM의 엔티티 오브젝트를 사용하는 서비스 계층&lt;/strong&gt;&lt;/span&gt; 코드와 항상 명시적으로 특정 &lt;span style=&quot;border-bottom:0.05em solid&quot;&gt;&lt;strong&gt;SQL을 실행하는 JDBC/iBatis의 서비스 계층 코드&lt;/strong&gt;&lt;/span&gt;는 미묘하지만 분명한 차이가 존재&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a5a59d32-538d-4685-bf07-7b725703370f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;예외 변환을 통해 완벽하게 독립적인 예외를 기대할 순 없지만 JPA의 예외를 스프링의 예외로 변경하는 건 가치가 있는 작업&lt;ul id=&quot;6e34104f-79f8-4950-a7dd-661306c7f76e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;&lt;code&gt;@Repository&lt;/code&gt;와 &lt;code&gt;PersistenceExceptionTanslationPostProcessor&lt;/code&gt;를 이용한 예외 변환 AOP를 반드시 적용&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;2525c667-ed48-4823-9399-ff8c6dbad15e&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;/article&gt;</description>
      <category>개발서적/토비 스프링 3.1-Vol.2</category>
      <category>jpa</category>
      <category>스프링</category>
      <category>토비</category>
      <category>토비스프링</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/171</guid>
      <comments>https://milenote.tistory.com/171#entry171comment</comments>
      <pubDate>Mon, 17 Jan 2022 22:34:07 +0900</pubDate>
    </item>
    <item>
      <title>[토비의 스프링 - Vol.2] 2장 - 2.3 iBatis SqlMaps</title>
      <link>https://milenote.tistory.com/170</link>
      <description>&lt;article id=&quot;3357cd22-9861-44e9-8f30-9d5ac2145bbd&quot; class=&quot;page sans Notion_P content__permalink&quot;&gt;&lt;header&gt;&lt;h1 class=&quot;page-title&quot;&gt;2.3 iBatis SqlMaps&lt;/h1&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;ul id=&quot;2eace041-afd0-4449-91ff-ed1bd256263e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;자바오브젝트와 SQL 문 사이의 자동매핑 기능을 지원하는 ORM 프레임워크&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;cb26b914-a572-4afc-89c1-01b02ba5f557&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;iBatis는 코드 내에서 자바오브젝트만을 이용해 데이터 로직을 작성할 수 있게 해주고 SQL을 별도의 파일로 분리해서 관리해주며, 오브젝트-SQL 사이의 파라미터 매핑 작업을 자동으로 해주기 때문에 많은 인기를 얻고 있는 기술&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9cee748b-a5fe-4ce3-b994-d3dfe0d08526&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;본격적인 ORM인 JPA나 하이버네이트처럼 새로운 DB 프로그래밍 패러다임을 익힐 부담X&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a1daa6f2-2453-4749-b2ae-d38e450f0290&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL을 그대로 이용할 수 있으면서도 JDBC 코드 작성의 불편함을 제거해주고, 도메인 오브젝트나 DTO를 중심으로 개발이 가능하다는 장점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0c7ac518-c128-40f5-a2ce-692c00f45084&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;XML파일로 작성하므로 컴파일이 필요 없고, SQL 작성과 관리 또는 검토를 DBA와 같은 개발자가 아닌 사람에 맡길 수 있다는 장점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b8f056f7-d93e-406f-9a5e-26e0473d8b64&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 매핑은 스프링 JDBC에도 지원하지만, iBatis는 매핑 이상의 많은 기능을 제공&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;e0d40d9e-782e-4bd2-9a13-b60e12e813dd&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/div&gt;


&lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.3.1 SqlMapClient 생성&lt;/h2&gt;&lt;ul id=&quot;3c44328f-0e3c-40ca-b88c-a2cd13caaf09&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;핵심 API는 SqlMapClient 인터페이스에 담겨 있음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;f9a49b80-a463-4357-b85a-160d04ccdb8d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC가 Connection, Statement, ResultSet을 생성해 사용하듯 iBatis를 이용하려면 SqlMapClient를 구현한 오브젝트가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;27b5d167-4344-41a0-9a3e-9fdaa2470619&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링에서는 SqlMapClient를 빈으로 등록해두고 DAO에서 DI 받아 사용해야 하기 때문에 SqlMapClient를 빈으로 등록해주는 팩토리 빈의 도움이 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;869d932f-197b-4888-a1cb-d8286e2fa91b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링이 제공하는 SqlMapClient용 팩토리 빈은 SqlMapClientFactoryBean&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;2e0e4bc3-881e-41a2-a20d-d6bfbf1c3c8a&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;11e68fba-c797-4bae-8f88-b6aa2b365d25&quot; class=&quot;&quot;&gt;iBatis 설정파일과 매핑파일&lt;/h2&gt;&lt;ul id=&quot;f9d66aef-706c-4c59-a433-e4307878571c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;iBatis를 이용하려면 공통 설정을 담은 XML 파일과 매핑정보를 담은 XML매핑 파일이 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b3bcc7b9-1290-4331-a3a9-a69653bf2df1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;보통 하나의 설정파일과 한 개 이상의 매핑파일로 구성&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;41ef19ec-c6ce-4f0f-9f43-fabffe9312bb&quot; class=&quot;&quot;&gt;설정파일&lt;/h3&gt;&lt;ul id=&quot;93dd76a7-611a-4f6b-b648-ce2829290ef1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;데이터소스, 트랜잭션 매니저, 매핑 리소스 파일 목록, 프로퍼티, 타입별칭과 핸들러, 오브젝트 패곹리와 설정 프로퍼티 값을 넣을 수 있음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b768cb21-c6c1-4979-a358-2d7d60c8f7c8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;데이터소스와 트랜잭션 매니저는 스프링의 빈으로 등록된 것을 사용하는게 좋음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;da78cd11-eb6a-4506-b70d-e6306d979fb7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;그 외의 반드시 넣어야 하는 것은 매핑파일 정보&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;4cb953b1-9f23-4b4a-baff-9e1f75ec23bb&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;
&amp;lt;!DOCTYPE sqlMapConfig
		PUBLIC &amp;quot;-//ibatis.apache.org//DTD SQL Map Config 2.0//EN&amp;quot;
		&amp;quot;http://ibatis.apache.org/dtd/sql-map-config-2.dtd&amp;quot;&amp;gt;

&amp;lt;!-- 매핑정보를 담은 파일의 클래스 패스를지정, 매핑파일마다 &amp;lt;sqlMap&amp;gt; 태그를 추가 --&amp;gt;
&amp;lt;sqlMapConfig&amp;gt;
		&amp;lt;sqlMap resource=&amp;quot;springboot/learningtest/spring/ibatis/Member.xml&amp;quot;/&amp;gt;
&amp;lt;/sqlMapConfg&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;27dc6009-6bb1-4de9-91fc-fecffb9a453d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB 커넥션과 트랜잭션 관리를 위한 정보는 iBatis 설정파일이 아닌 스프링 빈으로 등록한 것을 사용하는게 바람직한 방법&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;aabb916a-9fe4-4e0c-981d-9087401c64be&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링의 DI 기법으로 DataSource 변경도 쉽고 트랜잭션 기능을 iBatis DAO도 이용 가능&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;73382f11-5aaf-4b1d-927a-894853412b3d&quot; class=&quot;&quot;&gt;매핑파일&lt;/h3&gt;&lt;ul id=&quot;e8515a0c-ed3a-4409-a7df-5b98704f4769&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL-오브젝트 사이의 매핑정보는 XML 파일로 만듬&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c16d14df-c66f-43b4-8034-f1ccbc2c589e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;사용할 SQL 문과 SQL 파라미터, 실행 결과를 자바 오브젝트로 변환할지에 대해 정의&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;758d006e-a8b9-4a14-ba79-7622933a37fe&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;각 SQL은 고유한 아이디를 가지며, DAO에서는 아이디를 이용해 SQL을 실행&lt;ul id=&quot;a3b8cd92-58e8-4e6e-949c-2998893e4919&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;‘#’으로 둘러싸인 부분은 이름 치환자 (스프링 JDBC의 ‘:’ 이용한 것과 비슷)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6a0c0de3-161a-4dff-92f0-18b6d6746774&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;테이블의 컬럼 이름과 매핑할 오브젝트의 프로퍼티 이름이 일치하면 자동으로 파라미터와 결과의 전환이 가능, 불일치할 경우 매핑 정보를 추가&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;76146188-5ec0-4865-aee3-5cf69cafd601&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;
&amp;lt;!DOCTYPE sqlMap
		PUBLIC &amp;quot;-//ibatis.apache.org/DTD SQL Map 2.0//EN&amp;quot;
		&amp;quot;http://ibatis.apache.org/dtd/sql-map-2.dtd&amp;quot;&amp;gt;

&amp;lt;sqlMap namespace=&amp;quot;Member&amp;quot;&amp;gt;
		&amp;lt;typeAlias alias=&amp;quot;Member&amp;quot; type=&amp;quot;springbook.learningtest.spring.jdbc.Member&amp;quot;/&amp;gt;
		
		&amp;lt;delete id=&amp;quot;deleteMemberAll&amp;quot;&amp;gt;
				delete from member
		&amp;lt;/delete&amp;gt;

		&amp;lt;insert id=&amp;quot;insertMember&amp;quot; parameterClass=&amp;quot;Member&amp;quot;&amp;gt;
				insert into member(id, name, point) values(#id#, #name#, #point#)
		&amp;lt;/insert&amp;gt;

		&amp;lt;select id=&amp;quot;findMemberById&amp;quot; parameterClass=&amp;quot;int&amp;quot; resultClass=&amp;quot;Member&amp;quot;&amp;gt;
				select * from member where id = #id#
		&amp;lt;/select&amp;gt;
	
		&amp;lt;select id=&amp;quot;findMembers&amp;quot; resultClass=&amp;quot;Member&amp;quot;&amp;gt;
				select * from meber order by id
		&amp;lt;/select&amp;gt;
&amp;lt;/sqlMap&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;3ff68bbc-a58b-4459-b11a-0b042fe10fae&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;7a381cb6-23d6-4bf8-84f2-8510f5007e80&quot; class=&quot;&quot;&gt;SqlMapClient를 위한 SqlMapClientFactoryBean 등록&lt;/h2&gt;&lt;ul id=&quot;96cec8fb-ed8c-46bf-b082-22d527903aa3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DAO가 iBatis 기능을 사용하려면 SqlMapClient가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;58e2c16a-6fc9-4883-9401-156521e50d51&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC의 Connection처럼 모든 데이터 액세스 작업에 필요로 하는 오브젝트&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;84b09c1c-d825-4727-b309-5999e0ba1774&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SqlMapClient를 싱글톤 빈으로 등록해서 필요한 DAO에서 DI받아 사용 가능&lt;ul id=&quot;6f59f203-7ec6-4d64-a325-ded4619f9fb5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;멀티 스레드에서 공유해서 사용해도 안전한 오브젝트&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0ca7a306-8c5b-4f8d-8091-1aa638eccad3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SqlMapClientFactoryBean을 이용해 팩토리 빈이 생성해줘야 함, 필요한 프로퍼티는 DataSource와 앞에서 만들어둔 설정파일의 위치&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;1ab42e6f-e8f5-4124-b4c0-7dd6e3180d79&quot; class=&quot;code&quot;&gt;&lt;code&gt;&amp;lt;bean id=&amp;quot;sqlMapClient&amp;quot;
			class=&amp;quot;org.springframework.orm.ibatis.SqlMapCleintFactoryBean&amp;quot;&amp;gt;
		&amp;lt;property name=&amp;quot;dataSource&amp;quot; ref=&amp;quot;dataSource&amp;quot; /&amp;gt;
		&amp;lt;property name=&amp;quot;configLocation&amp;quot;
							value=&amp;quot;springbook/learningtest/spring/ibatis/SqlMapConfig.xml&amp;quot; /&amp;gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;4c74f6dc-3187-4244-9209-ed9e625ed1ae&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/div&gt;
  
  
  
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.3.2 SqlMapClientTemplate&lt;/h2&gt;&lt;ul id=&quot;fb9c1349-a64b-4f77-b8ef-6a68cb937d4d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;iBatis용 DAO는 &lt;code&gt;SqlMapClient&lt;/code&gt; 빈을 DI 받아서 iBatis 기능을 이용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;52a19a97-69e0-4a4f-b6d9-72e1eccb1612&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;SqlMapClient&lt;/code&gt;를 직접 사용하는 대신 스프링이 제공하는 템플릿 오브젝트인 &lt;code&gt;SqlMapClientTemplate&lt;/code&gt;를 이용하는 것이 좋음&lt;ul id=&quot;59b582c5-6327-485c-80a7-4298c67cb105&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;스프링 데이터 액세스 기술이 제공하는 다양한 혜택을 제공 받음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7b32709c-6c28-4438-9519-9218bedeaaad&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;사용방법은 JdbcTemplate과 거의 유사하며, 예외 변환, 스프링 트랜잭션과 동기화 등이 지원&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;e6631908-c735-4874-94a3-d25f4c44ff8e&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		private SqlMapClientTemplate sqlMapClientTemplate;

		public void setSqlMapClient(SqlMapClient sqlMapClient) {
				sqlMapClientTemplate = new SqlMapClientTemplate(sqlMapClient);
		}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;d2bccb06-ee15-4c55-b948-2d6ad81de8eb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SqlMapClientTemplate를 직접 생성하는 대신 스프링이 재공하는 SqlMapClientDaoSupport를 상속해 DAO를 만들어도 사용 가능&lt;ul id=&quot;cc7d7c4f-caa2-4a60-8309-4e135a843e73&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;SqlMapClient를 DI 받아서 템플릿을 만들어주는 기능이 포함&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5126e23f-1ce7-4966-bd02-c21e8b1f5745&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;템플릿 오브젝트는 getSqlMapClientTemplate()로 가져와서 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;e1e95eff-db99-40ba-aef5-3a4962cc77e6&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao extends SqlMapClientDaoSupport {
		public void insert(Member member) {
				getSqlMapclientTemplate().insert(&amp;quot;insertMember&amp;quot;, member);
		}
}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;af509ec4-f8c8-47d1-863f-34296f864b31&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;6af7d92e-e227-4588-8043-2da55f0d8cd7&quot; class=&quot;&quot;&gt;등록, 수정, 삭제&lt;/h2&gt;&lt;h3 id=&quot;984a36fc-748e-432b-9917-2654a72d2dd7&quot; class=&quot;&quot;&gt;insert()&lt;/h3&gt;&lt;ul id=&quot;b2c566e7-f0a2-4127-ad58-5f6c945ab8c9&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 아이디와 파라미터 오브젝트를 넣어주면 해당 INSERT 문을 실행&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;83e8e2aa-e0ef-4337-90e8-f6e7bacbea77&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;내부적으로 iBatis의 SqlMapExecutork의 isnert()가 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;412756a1-cdfb-4a4e-a5bc-d22d0309b4b9&quot; class=&quot;code&quot;&gt;&lt;code&gt;Ojbect insert(String statementName)
Object insert(String statementName, Object parameterObject)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;20f86416-b566-4844-b4fc-40c08c629cb0&quot; class=&quot;&quot;&gt;update()&lt;/h3&gt;&lt;ul id=&quot;4ed4b8d5-aa86-429d-b6d8-c965e61d321a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 아이디와 파라미터 오브젝트를 제공하면 해당 UPDATE 문을 실행&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;681893e5-ba1d-4f31-bdfe-3566ee2ea62a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;내부적으로 SqlMapExecutor의 update()가 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;23da9924-158f-4191-90d8-e78c2be71709&quot; class=&quot;code&quot;&gt;&lt;code&gt;int update(String statementtName)
int update(String statementName, Object parameterObject)

//영향을 받은 로우의 개수를 체크
//기대했던 로우의 개수와 실행결과가 일치하지 않으면 예외가 발생
void update(String statementName, Object parameterObject, 
			int requiredRowsAffected)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9378700e-bff9-492b-9d21-870aaee9ea0d&quot; class=&quot;&quot;&gt;delete()&lt;/h3&gt;&lt;ul id=&quot;daa34556-06e7-4150-a78a-a8a55bc49036&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;매핑파일에 정의된 DELETE문을 실행&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;974f9522-8629-4a1b-b488-57c47080b763&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SqlMapExecutor의 delete() 가 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;cf4a413e-3cf4-4222-b269-7961d04c2669&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;메소드의 실행은 update()와 비슷&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;0ee11203-6f43-4d2f-8451-ff413c43b96e&quot; class=&quot;code&quot;&gt;&lt;code&gt;int delete(String statementName)
int delete(String statementName, Object parameterObject)
void delete(String statementName, Object parameterObject, 
			int requiredRowsAffected)&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;440181b6-2c0f-4b4b-a0b6-212121a823d3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;sqlMapClientTemplate을 갖고 있는 DAO라면 아래와 같이 작성 가능&lt;pre id=&quot;aae3bba2-6e0e-4b41-83cf-6da7a2213fa0&quot; class=&quot;code&quot;&gt;&lt;code&gt;public void insert(Member member) {
		sqlMapClientTemplate.insert(&amp;quot;insertMember&amp;quot;, member);
}

public void deleteAll() {
		sqlMapClientTemplate.delete(&amp;quot;deleteMemberAll&amp;quot;);
}&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;58658b43-c4b8-49cc-865b-e25d3bde0ad3&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;1f892264-c2c8-47ff-a111-8865b4b0cc53&quot; class=&quot;&quot;&gt;조회&lt;/h2&gt;&lt;h3 id=&quot;9d6e8bb7-21e1-4af0-8054-a940450f1c7a&quot; class=&quot;&quot;&gt;단일 로우 조회: queryForObject()&lt;/h3&gt;&lt;ul id=&quot;da78b7c4-fe56-4ef3-8dbb-c0a791ea6e71&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL의 실행 결과가 한 건인 경우에 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2cb188ea-f00c-46ad-b947-a612bc8d3c7c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;리턴 오브젝트는 매핑파일에 지정된 타입이 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;1b9a6101-570f-4960-a794-bb3849d1d6b1&quot; class=&quot;code&quot;&gt;&lt;code&gt;Object queryForObject(String statementName)
Object queryForObject(String statementName, Object parameterObject)
Object queryForObject(String statementName, Object parameterObject,
				Object resultObject)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;e4392942-a8be-4e01-a4c8-15f1b28ab22e&quot; class=&quot;&quot;&gt;다중 로우 조회: queryForList()&lt;/h3&gt;&lt;ul id=&quot;bd029c3e-02f6-47f0-9f34-27d720ce3e7a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 실행 결과가 한 건 이상인 경우 각 로우를 오브젝트에 담고 리스트로 리턴&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;bff42b6e-a0d0-4374-88ed-268614a644e4&quot; class=&quot;code&quot;&gt;&lt;code&gt;List queryForList(String statementName)
List queryForList(String statementName, Object ParameterObject)
List queryForList(String statementName, int skipResult, int maxResults)
List queryForList(String statementName, Object parameterObject, int skipResults,
									int maxResults)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;e945ccfd-306e-431e-b533-9802899bf45c&quot; class=&quot;&quot;&gt;다중 로우 조회: queryForMap()&lt;/h3&gt;&lt;ul id=&quot;7b777433-1639-4e49-b676-c6fb1c80d825&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC의 queryForMap()과 이름은 비슷하지만 맵에 내용이 담기는 방식은 전혀 다르므로 주의가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;bd072141-dc34-4325-9d65-703324fe348c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;iBatis의 queryForMap()은 다중 로우를 가진 결과를 조회할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c753b940-4836-4910-b3ca-000b5012ac0e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;맵의 키는 지정된 컬럼 값이 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;3662305a-1103-4ada-8f8d-46cdad0e1cda&quot; class=&quot;code&quot;&gt;&lt;code&gt;Map queryForMap(String statementName, Object parameterObject,
								String keyProperty)
Map queryForMap(String statementName, Object parameterObject,
								String keyProperty, String valueProperty)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;ab042863-84c5-4054-943f-f91289786336&quot; class=&quot;&quot;&gt;다중 로우 조회: queryWithRowHandler()&lt;/h3&gt;&lt;ul id=&quot;87320133-bf23-49ad-937a-f392bcd6884d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC의 &lt;code&gt;RowMapper&lt;/code&gt;처럼 SQL의 결과를 루프로 돌면서 각 로우마다 콜백 오브젝트를 호출해주는 방식&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;221c972c-2fce-4aca-b823-d2b77436990c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;RowMapper&lt;/code&gt;는 각 로우를 매핑해서 돌려주는 것이 목적인 데 반해서 &lt;code&gt;queryWithRowHandler()&lt;/code&gt;의 &lt;code&gt;RowHandler&lt;/code&gt;는 그 자체로 해당 로우를 매핑한 결과를 어떻게 처리할지를 스스로 결졍&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9576b141-70ab-4aa8-b02d-c08714624cdf&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;조회된 로우의 개수가 매우 많다면 리스트나 맵에 담는 것보다 각 로우를 직접 처리하는 방법을 쓰는편이 좋음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;583bc38d-5a44-41ca-9276-9ae2f527aac6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;RowHandler&lt;/code&gt;는 iBatis에서 직접 제공되는 콜백 인터페이스&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e5a3e51f-b9cd-4eec-b39e-4359260029c4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;queryWithRowHandler()&lt;/code&gt;는 결과를 리스트에 담는 목적이 아니라 리턴이 없음&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;9a38ec9e-72e8-4d8a-be6c-8a7462e8c842&quot; class=&quot;code&quot;&gt;&lt;code&gt;void queryWithRowHandler(String statementName, RowHandler rowHandler)
void queryWithRowHandler(String statementName, Object parameterObject,
												RowHandler rowHandler)&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;ec4e9808-a504-4bf8-95ec-66466fe48d66&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;d2d876a9-d1ec-46e6-8612-554dfddce4b3&quot; class=&quot;&quot;&gt;SqlMapClientCallback&lt;/h2&gt;&lt;ul id=&quot;6f2a486a-139e-489c-a0de-6763d4d9c272&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;콜백이 내장된 템플릿 메소드를 이용하는 대신 직접 iBatis의 SqlMapExecutor의 API를 사용하고 싶다면 SqlMapClientCallback 인터페이스를 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;55ab0289-fe3d-48d6-9d16-e8bf86ea6d10&quot; class=&quot;code&quot;&gt;&lt;code&gt;public interface SqlMapClientCallback&amp;lt;T&amp;gt; {
		T doInSqlMapClient(SqlMapExecutor executor) throw SQLException;
}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;c86f2a18-dd32-4b92-b3d2-3e5dd437d070&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 인터페이스를 구현한 콜백 오브젝트를 SqlMapClientTemplate의 execute()에 전달&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;a9a4a3cc-5d53-4d44-a66a-c98a30741150&quot; class=&quot;code&quot;&gt;&lt;code&gt;public &amp;lt;T&amp;gt; T execute(SqlMapClientCallback&amp;lt;T&amp;gt; action)&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;adda01f1-e333-42c3-a515-2409f8dbd085&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SqlMapClientCallback은 iBatis API의 사용법을 충분히 숙지 후 스프링 템플릿/콜백 방식의 동작원리를 잘 이해한 후에 사용&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/article&gt;</description>
      <category>개발서적/토비 스프링 3.1-Vol.2</category>
      <category>ibatis</category>
      <category>스프링</category>
      <category>토비</category>
      <category>토비스프링</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/170</guid>
      <comments>https://milenote.tistory.com/170#entry170comment</comments>
      <pubDate>Mon, 17 Jan 2022 22:29:44 +0900</pubDate>
    </item>
    <item>
      <title>[토비의 스프링 - Vol.2] 2장 - 2.2 JDBC</title>
      <link>https://milenote.tistory.com/169</link>
      <description>&lt;article id=&quot;ef84ca2b-eb8e-497a-89fc-f745926178b6&quot; class=&quot;page sans Notion_P content__permalink&quot;&gt;&lt;header&gt;&lt;h1 class=&quot;page-title&quot;&gt;2.2 JDBC&lt;/h1&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;ul id=&quot;a13d2d07-6339-4b32-890b-4b5d839ed71c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;자바의 데이터 액세스 기술의 기본이 되는 로우 레벨의 API&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;3bd8128d-9cfe-4c4d-91b3-ae2f73bcd425&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC는 표준 인터페이스를 제공하고 각 DB 벤더와 개발팀에서 이 인터페이스를 구현한 드라이버를 제공하는 방식으로 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c499178a-486f-4880-81a9-f392a856ba0b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC는 모든 자바의 데이터 액세스 기술의 근간&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;9fefda0f-e576-436f-8d15-7aa343599bf1&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/div&gt;

  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.2.1 스프링 JDBC 기술과 동작원리&lt;/h2&gt;&lt;ul id=&quot;06379ffb-cd76-4afa-8945-0854b261f7c4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 3.0에서는 다섯 가지 종류의 접근 방법을 제공&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;690f5216-b305-4373-b8b3-355a0bcbc468&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JdbcTemplate는 그중에서 가장 오래된 기초적인 접근 방법&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;9f38264c-04b9-4063-aa10-cac89a1fe022&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;0a56664e-e6af-4ed4-a6d9-294a43fa6f2e&quot; class=&quot;&quot;&gt;스프링의 JDBC 접근 방법&lt;/h2&gt;&lt;ul id=&quot;07072456-e16e-45d9-ad39-5a384cb99bca&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;접근 방법 중에서 가장 사용하기 편하고 자주 이용되는 것은 다음 두가지&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;353d3522-9236-4ba6-a640-a4e7ee0286df&quot; class=&quot;&quot;&gt;SimpleJdbcTemplate&lt;/h3&gt;&lt;ul id=&quot;a2aab392-95b8-44dd-93a9-cd6fa43ec9e9&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;jdbcTemplate과 NameParameterJdbcTemplate에서 가장 많이 사용되는 기능을 통합하고 자바 5 이상의 장점을 최대한 활용할 수 있게 만든 방식&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7102f3ca-c826-41ed-b26b-329c3c39c876&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;방대한 템플릿 메소드와 내장된 콜백을 제공&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;3d3d66bb-c057-4b4c-810a-c0ee487a970b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;JDBC의 모든 기능을 최대한 활용할 수 있는 유연성을 지님&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;dffd2260-46cc-4b7a-a176-60b680684a10&quot; class=&quot;&quot;&gt;SimpleJdbcInsert, SimpleJdbcCall&lt;/h3&gt;&lt;ul id=&quot;3eebd715-fe84-4c25-91e7-45f6ab54ac16&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이 두가지 접근 방법은 DB가 제공해주는 메타정보를 활용해서 최소한의 코드만으로 단순한 JDBC 코드를 작성 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;f0291133-f18d-4b6c-8db3-0514d79f0c13&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;메타정보에서 컬럼 정보와 파라미터 정보를 가져와서 삽입용 SQL과 프로시저 호출 작업에 사용해주기 때문에 매우 편리&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;02e1c2d9-b723-419f-bbc5-370b177ee180&quot; class=&quot;&quot;&gt;스프링 JDBC가 해주는 작업&lt;/h2&gt;&lt;h3 id=&quot;c4f0e05f-a298-4aac-9766-6e750553e111&quot; class=&quot;&quot;&gt;Connection 열기와 닫기&lt;/h3&gt;&lt;ul id=&quot;03c5b187-e8a1-449a-b779-c2fc653296ec&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC를 사용하면 코드에서 직접 Connection을 열고 닫는 작업이 필요 없음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;b9199c87-2d8f-455f-a8d0-220363582a70&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;Connection과 관련된 모든 작업은 스프링 JDBC가 필요한 시점에서 알아서 진행&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;8c73c6a2-8a3d-4525-9b48-f3c0ba2a6680&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;Connectio을 열고 닫는 시점은 스프링 트랜잭션 기능과 맞물려서 결졍&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;917313c9-93ea-4e61-b472-2cd693bb325a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;같은 코드와 DAO라고 해도 트랜잭션 경계를 어떻게 선언해뒀고 어떤 순서로 호출하느냐에 따라서 매번 Connection을 열고 닫는 위치가 달라짐&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;ac1fce70-18fc-40b2-b57c-d5c6c9b19458&quot; class=&quot;&quot;&gt;Statement 준비와 닫기&lt;/h3&gt;&lt;ul id=&quot;0f48e926-316e-4740-888c-679a304104e7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 정보가 담긴 Statement 또는 PreparedStatement를 생성하고 필요한 준비 작업을 해주는 것도 대부분 스프링 JDBC의 몫&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e29f75bd-60ed-4835-b0c0-b665a1c98155&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;준비된 Statement는 콜백 오브젝트가 전달받아서 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;d4f9aa49-89ae-44c7-9738-ac18051d6922&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;콜백을 직접 만들기보다는 스프링 JDBC가 미리 만들어 놓은 것을 사용하는 경우가 많음 그래서 직접 Statement를 사용하는 코드는 많지 않음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;be75a345-1784-4f1b-9d0e-a4b4afec2195&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;Statement도 Connection과 마찬가지로 사용이 끝나고 스프링 JDBC가 알아서 반환&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;2f07fd59-fe8a-40e0-b6ee-a5d9dfc9f307&quot; class=&quot;&quot;&gt;Statement 실행&lt;/h3&gt;&lt;ul id=&quot;2a6c63a9-0e75-41c3-bbe8-bc994f6232a0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL이 담긴 Statement를 실행하는 것도 스프링 JDBC의 몫&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;59241b4c-fa65-41ef-99e3-c344afa11412&quot; class=&quot;&quot;&gt;ResultSet 루프&lt;/h3&gt;&lt;ul id=&quot;b5f902aa-8981-4dc4-9ac6-0ae4ddd467ed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;ResultSet&lt;/code&gt;에 담긴 쿼리 실행 결과가 한 건 이상이라면 루프를 돌면서 각각의 로우들에 대해 처리가 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;6c3063f4-bf57-441e-8ee9-40c564f61068&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;ResultSet&lt;/code&gt;의 루프를 만들어 반복해주는 것도 스프링 JDBC가 해주는 작업&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;8a2fd241-c2fb-4602-aad0-8dbe574a46ad&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;ResultSet&lt;/code&gt; 각 로우의 내용을 어떻게 오브젝트에 담을 것인지는 루프 안에서 실행되는 콜백으로 만들어 템플릿에 제공해주면 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1fd45f1b-7e22-4198-90a4-f2addd37e125&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;어떤 경우 각 로우의 매핑을 위해 콜백을 직접 작성하기 보다는 스프링 JDBC가 미리 정해둔 포맷의 오브젝트나 컬렉션으로 전환하고 이를 전달받는 것이 편리&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;619914f2-c3dd-4423-af41-0ccc318ad62e&quot; class=&quot;&quot;&gt;트랜잭션 처리&lt;/h3&gt;&lt;ul id=&quot;315a096e-edf7-4807-9fce-ffe32f47b29c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC는 트랜잭션 동기화 기법을 이용해 선언적 트랜잭션 기능과 맞물려 실행&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0747077d-a2fd-456e-abde-6ee06f18a45e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;트랜잭션을 시작한 후에 스프링 JDBC의 작업을 요청하면 진행 중인 트랜잭션에 참여&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e444ce21-3a63-4a5b-a999-9a8af52984c5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;트랜잭션이 없는 채로 호출된 경우 새로운 트랜잭션을 만들어서 사용&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;d00277e3-31b6-4fc6-a6b2-4c17972ada25&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;ul id=&quot;b394a473-bd20-4d93-ae82-526189481ef3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC가 대부분 작업을 해주기 떄문에 데이터 액세스 로직만 정의해주면 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e374ca0e-0378-4d79-ab26-145fffd73c36&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;많은 경우 실행할 SQL과 바인딩할 파라미터를 넘겨주거나 쿼리의 실행 결과를 어떤 오브젝트에 어떻게 넣어서 받을지 지정해주는 역할만 해주면 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;8bfbcebd-f4d6-412d-8461-c3273bd3b014&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleSqlInsert를 사용하면 SQL도 생략 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;abf7d2b1-e36e-4dae-bcbe-92c89510f8c4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 개발자가 해야하는 한가지는 DB 커넥션을 가져올 DataSource를 정의해주는 것&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;5025f4da-a20d-4ff6-978e-27a25418068c&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/div&gt;
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.2.2 SimpleJdbcTemplate&lt;/h2&gt;&lt;ul id=&quot;4b414611-4f5c-4cf3-9df4-314330d12f8e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC를 사용한다면 가장 많이 이용하게 될 JDBC용 템플릿&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7d062fba-df00-4830-81d6-28d6135a1893&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcTemplate이 제공하는 기능은 실행, 조회, 배치의 세가지 작업으로 구분&lt;ul id=&quot;ece1f8b6-aab8-4ddc-9400-52e03b26aa00&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;실행 작업은 INSERT, UPDATE와 같이 DB의 데이터 변경이 일어나는 작업&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2a4b5d93-f5dc-4513-a8a4-c58c5582976a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;조회는 SELECT를 이용해 결과를 가져오는 작업&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2c2c7948-bea8-44c8-9677-8dfcb8f31df1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;배치는 하나 이상의 실행 작업을 한 번에 수행해줘야하는 작업&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;ab7a2620-c050-480b-ab76-7a1b80d2db5f&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;5b009ea6-7a60-41a3-bfa1-f77688d223ac&quot; class=&quot;&quot;&gt;SimpleJdbcTemplate 생성&lt;/h2&gt;&lt;ul id=&quot;d43fa2bf-3864-4579-a60f-1c5e3953c6a6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;은 &lt;code&gt;DataSource&lt;/code&gt;를 파라미터로 해서 다음과 같이 생성&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;8730f4d8-499d-4b47-b651-899d23a877a3&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcTemplate template = new SimpleJdbcTemplate(dataSource);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;41df68de-f110-4c19-a154-b9320b2f53d5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;DataSource&lt;/code&gt;는 보통 빈으로 등록하므로 필요한 DAO에서 &lt;code&gt;DataSource&lt;/code&gt; 빈을 DI 받아서 &lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;를 생성해두고 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;67d8c607-6895-42ed-99a7-2f77e6fc4bb0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;은 멀티스레드 환경에서도 안전하게 공유해서 쓸 수 있기 때문에 DAO의 인스턴스 변수에 저장해두고 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;4964fb89-f3be-416f-96f3-61cd39bd5201&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;SimpleJdbcTemplate&lt;/code&gt; 자체를 싱글톤 빈으로 등록하고 모든 DAO에 공유해서 사용도 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7a5e1a2c-5692-4d6a-9da8-b543ed9a7f8d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 개발자는 관례적으로 DAO의 코드에서 &lt;code&gt;DataSource&lt;/code&gt;를 받아 &lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;를 생성하는 방식을 선호&lt;ul id=&quot;d76c5a92-e629-4014-9920-e7497ba600ba&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;DataSource가 있으면 다른 스프링 JDBC 오브젝트를 만들어 사용이 가능하기 떄문&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;3de46cd0-d8c7-4f15-a151-226d4cc2f4d3&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		SimpleJdbcTemplate simpleJdbcTemplate;
		public void setDataSource(DataSource dataSource) {
				this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
		}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;61d67d40-7549-4d60-9d50-ceede14f2a7f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;애노테이션 방식을 이용한다면 @Autowired나 @Resource를 붙이거나 메소드에 의한 주입 방법이나 생성자 주입을 이용해서도 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;5419c222-4f62-4190-a7a5-87deb5244f59&quot; class=&quot;code&quot;&gt;&lt;code&gt;@Autowired
public void init(DataSource dataSource) {
		this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;c9074a74-c543-4477-b9cd-e30866149b77&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;65735995-d978-48f8-83b7-1161490e4d07&quot; class=&quot;&quot;&gt;SQL 파라미터&lt;/h2&gt;&lt;ul id=&quot;52be0e79-8de8-4cea-9b3a-b09da5a7c073&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;에 작업을 요청할 때는 문자열로 된 SQL 제공이 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9f7e9450-6b8e-4360-9932-1f1ed09f1cdb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL에 매번 달라지는 값이 있는 경우에는 ‘?’와 같은 치환자를 넣어 파라미터 바인딩 방법을 사용하는 것이 편리&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9855249e-f491-42ee-b972-d8f90bc914ed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링 JDBC는 JDBC에서 제공하는 위치를 이용한 치환자인 ‘?’뿐 아니라 명시적으로 이름을 지정하는 이름 치환자도 지원&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e97d9d37-f587-411e-9c56-139426af38d2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;위치 치환자를 사용하는 경우에는 파라미터의 개수가 많으면 실수하기 쉬움&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;446a1f95-4270-4f49-a6c8-3f9873d5db98&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;또한 치환자의 순서를 바꾸거나 추가, 삭제하는 작업도 어려움&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;f80f9f19-2de8-4189-bd55-4eea4ebe0b45&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL을 사용하는 예시&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;0ba99009-e248-4d40-bc64-30b3447b8960&quot; class=&quot;code&quot;&gt;&lt;code&gt;//실행할 SQL
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(1, &amp;#x27;Spring&amp;#x27;, 2.3);

//위치 치환자
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(?, ?, ?);

//이름 치환자
INSERT INTO MEMBER(ID, NAME, POINT) VALUES(:id, :name, :point);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;3d28d2bc-09f3-4f85-967b-1e88bfc05cfa&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이름 치환자의 또 다른 장점은 맵이나 오브젝트에 담긴 내용을 키 값이나 프로퍼티 이름을 이용해 바인딩 할 수있다는 점&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;8d2bd9cf-3000-402b-86db-42fc0148e74f&quot; class=&quot;&quot;&gt;Map / MapSqlParameterSource&lt;/h3&gt;&lt;pre id=&quot;0d62b019-f7f5-436e-b0f1-b95bde7ddef2&quot; class=&quot;code&quot;&gt;&lt;code&gt;Map&amp;lt;String, Object&amp;gt; map = new HashMap&amp;lt;String, Object&amp;gt;();
map.put(&amp;quot;id&amp;quot;, 1);
map.put(&amp;quot;name&amp;quot;, &amp;quot;Spring&amp;quot;);
map.put(&amp;quot;point&amp;quot;, 3.5);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;7bd2f1b6-f0c5-4693-ace0-a1b738f8b570&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;map은 이름 치환자를 가진 SQL과 함께 SimpleJdbcTemplate에 전달돼서 바인딩 파라미터로 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;89155011-b515-4aaa-992f-a936a0e5b7ab&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;맵의 키 값과 일치하는 치환자에 맵의 값이 자동으로 삽입&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5ca719af-16f2-48a4-b7b4-decf1dd9c3cd&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;코드를 이용해 맵에 정보를 직접 넣어야 한다면 Map 대신 스프링 JDBC의 MapSourceParameterSource를 사용하는 것이 편리&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;8d2d3af7-c9d4-4123-84a7-4ec98327f1cc&quot; class=&quot;code&quot;&gt;&lt;code&gt;MapSqlParameterSource params = new MapSqlParameterSource()
																		.addValue(&amp;quot;id&amp;quot;, 1)
																		.addValue(&amp;quot;name&amp;quot;, &amp;quot;Spring&amp;quot;)
																		.addValue(&amp;quot;point&amp;quot;, 3.5);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;ec30549e-340a-443e-8f9f-c1dcd191bd3a&quot; class=&quot;&quot;&gt;BeanPropertySqlParameterSource&lt;/h3&gt;&lt;ul id=&quot;2fa942c3-c029-4061-b0b0-cfb9003deb95&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;Map 대신 도메인 오브젝트나 DTO를 사용하게 해줌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5db1f23b-8202-4ba5-ae0c-419ae0ef9dca&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;오브젝트의 프로퍼티 이름과 SQL의 이름 치환자를 매핑해 파라미터 값을 넣어주는 방식&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;38e10dce-655f-413c-acc2-0b009684c420&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;도메인 오브젝트의 파라미터와 SQL 치환자의 이름만 같게 만들면 매우 편리&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;810fe005-3383-4dd8-a42a-f95d0bd5e7a2&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class Member {
		int id;
		String name;
		double point;

		public int getId() {return this.id;}
		...
}&lt;/code&gt;&lt;/pre&gt;&lt;pre id=&quot;9078cc77-688a-49c2-bcae-1b317a36e89d&quot; class=&quot;code&quot;&gt;&lt;code&gt;Member member = new Member(1, &amp;quot;Spring&amp;quot;, 3.5);
BeanPropertySqlParameterSource params = new BeanPropertySqlParameterSource(member);&lt;/code&gt;&lt;/pre&gt;&lt;p id=&quot;255743a4-eedf-4fbf-b2fb-d86830c13bb2&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;f98c3e69-46f0-4fc5-b056-4cb31c0eff5f&quot; class=&quot;&quot;&gt;SQL 실행 메소드&lt;/h2&gt;&lt;ul id=&quot;ba5ba8ae-0637-4194-a0c5-8b47c8aab135&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;INSERT, UPDATE, DELETE와 같은 SQL을 실행할 때는 SimpleJdbcTemplate의 update()를 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;ee4f901a-9b82-4e42-8078-8e2e5cccb36f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;update()를 호출할 때는 SQL과 함께 바인딩할 파라미터를 다음 세가지 방식 중 하나로 전달&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;8f44dac2-5e6d-4f59-bce3-b58a7fd72b58&quot; class=&quot;&quot;&gt;varargs&lt;/h3&gt;&lt;ul id=&quot;1d3ef149-bc2b-4511-81fc-db9dffb34ffd&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;위치 치환자를 사용하는 경우 바인딩할 파라미터 순서대로 전달&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;aef96fab-3df2-42c6-ae6a-2aea4c2b39da&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.update(
		&amp;quot;INSERT INTO MEMBER(ID, NAME, POINT, args) VALUES(?,?,?)&amp;quot;, 1, &amp;quot;Spring&amp;quot;, 1.5);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;9ef216a1-fa48-462c-9900-9352ab57800c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;파라미터는 가변인자이므로 필요 없다면 생략 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;73addec0-2422-48c5-8105-0ddabec55421&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.update(&amp;quot;delete from member&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;4f31c7e8-20d7-47f4-baf2-b639d3626f6a&quot; class=&quot;&quot;&gt;Map&lt;/h3&gt;&lt;ul id=&quot;0d4841c2-6a60-4251-a6b4-4dcb5d7aab7a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이름 치환자를 사용한다면 파라미터를 Map으로 전달&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;aed4e6aa-70a0-4d6f-9b89-63ae2c6d944f&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.update(
		&amp;quot;INSERT INTO MEMBER(ID, NAME, POINT, args) VALUES(:id, :name, :point)&amp;quot;, map);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;6e5a2081-8869-4ca2-9b32-d0b38694f4f1&quot; class=&quot;&quot;&gt;SqlParameterSource&lt;/h3&gt;&lt;ul id=&quot;02b922a8-6db7-4c9c-acc6-0b9c9bb647c8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;도메인 오브젝트나 DTO를 이름 치환자에 직접 바인당하려면 SqlParameterSource 타입인 BeanPropertySqlParameterSource를 사용해 update()를 호출&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;da671daf-86ff-4a90-8b77-982c9944ac33&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.update(
		&amp;quot;INSERT INTO MEMBER(ID, NAME, POINT, args) VALUES(:id, :name, :point)&amp;quot;,
		new BeanPropertySqlParameterSource(member));&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;29b95eaf-1dc0-4ebe-b42a-88447dc51155&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;파라미터를 직접 지정하려면 MapSqlParameterSource의 addValue()를 이용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;c01b7ac1-7912-4b09-aff3-69a87ec42229&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.update(
		&amp;quot;INSERT INTO MEMBER(ID, NAME, POINT, args) VALUES(:id, :name, :point)&amp;quot;,
		new MapSqlParameterSource()
			.addValue(&amp;quot;id&amp;quot;, 1).addValue(&amp;quot;name&amp;quot;, &amp;quot;Spring&amp;quot;).addValue(&amp;quot;point&amp;quot;, 3.5&amp;quot;));&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;a0989c21-487c-4534-a9f8-5f94068cfa61&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcTemplate의 update()는 SQL 실행으로 영향을 받은 레코드의 개수를 리턴&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;8f2b7a93-6805-4f86-b657-19bff6e860a0&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;5f9c68bd-d9db-40de-8a52-af73fde25a09&quot; class=&quot;&quot;&gt;SQL 조회 메소드&lt;/h2&gt;&lt;ul id=&quot;ae05c64d-e129-42a2-a892-e4e55c5e7dc1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SELECT를 이용하는 조회용 메소드는 단순 값이나 오브젝트를 가져오는 경우와 리스트를 가져오는 경우로 구분&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;a25e6e3f-b6c0-44b2-8219-ec57dc41c312&quot; class=&quot;&quot;&gt;int queryForInt(String sql, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;b83ab457-ae83-4ff2-8bb1-f74fa56b2ab3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나의 int 타입 값을 조회할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;df5012df-9ad1-423c-bf4b-54d5429f2f96&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;[SQL 파라미터]에 사용할 수 있는 방법들&lt;ul id=&quot;95a55b98-cfb2-46e8-b00b-712ea0066d0b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;위치 치환자에 사용하는 Object 타입 가변인자(&lt;code&gt;Object... args&lt;/code&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;709f2093-8e31-4c16-ab99-e6fa0dbae2ec&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;이름 치환자에 사용할 수 있는 맵(&lt;code&gt;Map&amp;lt;String, ?&amp;gt; args&lt;/code&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;67cc13e8-2a45-47e8-84c9-0a1d9d1329a9&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;SQL 파라미터 소스(&lt;code&gt;SqlParameterSource args&lt;/code&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;34bfa0f2-631d-4df2-861c-d6bf6ad23680&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;파라미터가 없는 단순한 쿼리라면 다음과 같이 SQL 파라미터 생략이 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;9055caeb-da37-4038-9c01-13018cd1d37f&quot; class=&quot;code&quot;&gt;&lt;code&gt;int count = simpleJdbcTemplate.queryForInt(&amp;quot;select count(*) from member&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;pre id=&quot;df0be2f0-e734-4e68-91ef-b23fdcc31413&quot; class=&quot;code&quot;&gt;&lt;code&gt;simpleJdbcTemplate.queryForInt(&amp;quot;select count(*) from member point &amp;gt; :min&amp;quot;,
				new MapSqlParameterSource(&amp;quot;min&amp;quot;, min));&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;e1e26506-ea9d-409a-883f-6ffb77081b30&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;queryForInt()&lt;/code&gt;의 실행 결과는 한 개의 숫자 컬럼만 가져야하며, 아닌 경우 예외 발생&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;480fa8be-40eb-4336-9eb3-dd119e5d06ff&quot; class=&quot;&quot;&gt;long queryForLong(String sql, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;d96c8d09-dffd-4c26-a1fd-06d208e3ba9f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나의 long 타입 값을 조회할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;87d56505-12be-4ea7-8dbb-5d0cdbd44c87&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;리턴 타입만 다를 뿐 사용 방법은 &lt;code&gt;queryForInt()&lt;/code&gt;와 동일&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;7426e613-8a80-4fe8-a446-1669620f2cc5&quot; class=&quot;&quot;&gt;&amp;lt;T&amp;gt; T queryForObject(String sql, Class&amp;lt;T&amp;gt; requiredType, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;79cbf250-6e83-439d-9284-7c9971bc2978&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;쿼리를 실행해서 하나의 값을 가져올 떄 사용, 결과 타입을 직접 지정 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fa99b0e0-8ff7-45ee-a856-d5ac4fca9dc3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 실행 결과는 하나의 컬럼을 가진 하나의 로우, 아닌 경우 예외 발생&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;60d45d08-1fd7-4a9e-ac85-73e1890ad7d0&quot; class=&quot;code&quot;&gt;&lt;code&gt;String name = simpleJdbcTemplate.queryForObject(
		&amp;quot;select name from member where id = ?&amp;quot;, String.class, id);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;8a224c25-cc69-45b2-a9c5-74559029df71&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;검색된 로우가 없다면 EmptyResultDataAccessException 예외가 발생&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e5ce1f1f-25d9-42bc-95f6-9ffe9b997641&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;쿼리의 결과가 없어도 예외가 던져지길 원하지 않는다면 DAO에서 직접 처리 필요&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;d73b0bed-7201-4ee5-a29a-8bb268c74fc5&quot; class=&quot;code&quot;&gt;&lt;code&gt;try {
		return simpleJdbcTemplate.queryForObject(
		&amp;quot;select name from member where id = ?&amp;quot;, String.class, id);
} catch(EmptyResultDataAccessException) {
		return null;
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;0cba80f2-fc2a-4ebd-82f3-7ef8a233ca9c&quot; class=&quot;&quot;&gt;&amp;lt;T&amp;gt; T queryForObject(String sql, RowMapper&amp;lt;T&amp;gt; rm, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;e7903bc1-a5b9-485b-90d6-a2b220860df1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 실행 결과, 하나의 로우가 돌아오는 경우에 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2eeb4716-459d-4291-8ed1-6dc7fa73cc77&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;단일 컬럼이 아니라 다중 컬럼을 가진 쿼리에 사용할 수 있다는 장점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9b797b59-da02-423d-ac7a-f9af05d2b7be&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;다중 컬럼을 가진 결과이므로 도메인 오브젝트나 DTO처럼 여러 개의 프로퍼티 오브젝트로 전환 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;7df1e997-2ad1-46ba-a01b-dbb87dd9513a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;테이블의 컬럼 이름과 매핑될 오브젝트의 프로퍼티 이름이 일치한다면 RowMapper를 직접 구현하는 대신 BeanPropertyRowMapper&amp;lt;T&amp;gt;를 사용하는 것이 편리&lt;ul id=&quot;46575385-2d43-4d07-9dba-a552095a68c8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;생성자에 매핑할 클래스를 넣어서 오브젝트를 생성하면 주어진 클래스의 프로퍼티 이름과 SQL 결과를 자동 매핑해주는 RowMapper 콜백 오브젝트로 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;cd61e891-5820-4c5c-a868-47700a5b13fe&quot; class=&quot;code&quot;&gt;&lt;code&gt;Member m = simpleJdbcTemplate.queryForObject(
	&amp;quot;select * from member where id=?&amp;quot;
	, new BeanPropertyRowMapper&amp;lt;Member&amp;gt;(Meber.class)
	, id)	&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;397a885e-fd07-411f-aa78-ab616205e275&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;queryForObject()는 단일 조회, 결과가 없거나 여러 개의 로우로 돌아면 예외 발생&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;4afd0085-17da-46b1-89e6-44a1dee299f7&quot; class=&quot;&quot;&gt;&amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; query(String sql, RowMapper&amp;lt;T&amp;gt; rm, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;28931466-6c33-457d-9250-6dc123ee2ed6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 실행 결과로 여러 개의 컬럼을 가진 로우를 RowMapper 콜백을 이용해 도메인 오브젝트나 DTO에 매핑&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;087e853b-f3d6-4df5-af9a-e56f79a507f3&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;query()는 여러 개의 로우를 처리 가능, 리스트의 각 요소가 하나의 로우에 해당&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;58ffc012-da68-48dd-8ea3-368dd323511c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;로우의 개수에 제한은 없음 로우의 개수가 0이어도 예외가 발생 안함 &lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;aec1a8cd-8229-40ae-b679-a68421387971&quot; class=&quot;code&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; members = simpleJdbcTemplate.query(
	&amp;quot;select * from member where point &amp;gt; ?&amp;quot;, 
	new BeanPropertyRowMapper&amp;lt;Member&amp;gt;(Member.class),
	point);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;9a5bf511-fbc2-4d86-a74e-b0403446df21&quot; class=&quot;&quot;&gt;Map&amp;lt;String, Object&amp;gt; queryForMap(String sql, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;bec4bf60-7c40-41bb-8f4a-ef6b1f8ab9f1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;queryForObject() 처럼 단일 로우의 결과를 처리하는데 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;452a6010-462f-41cf-91c8-86850f77c58e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;RowMapper를 이용해 도메인, DTO에 매핑하는 대신 맵에 로우 내용을 저장해서 리턴&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;aeb81b45-ccad-4a9c-9452-3334e4531a1c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;저장할 오브젝트를 매번 정의하기 번거롭거나 맵의 사용이 편리한 환경에서 유용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;48ed2e45-e052-4b03-84e9-ef954d439138&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;맵의 키에는 컬럼 이름이 들어가고 값에는 컬럼의 값이 저장&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;bf46ead1-ef47-4b0b-a431-2388c4985354&quot; class=&quot;code&quot;&gt;&lt;code&gt;Map&amp;lt;String, Object&amp;gt; map = simpleJdbcTemplate.queryForMap(
	&amp;quot;select * from member where id = ?&amp;quot;, id);&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;31f185e3-72b7-422d-bd2a-25aab47194d8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL 실행 결과는 하나의 로우를 돌려주는 것이 보장 필요, 그 외엔 오류 발생&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;96e867b2-3285-4bcb-a7d3-20d2bf7a7663&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;조회 결과를 서비스 계층의 비즈니스 로직에 활용할 경우 컬럼 값을 매번 적절한 타입으로 캐스팅해줘야 하는 번거로움 발생&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;a70cf90d-6601-4a50-b29c-3fd882ae0d84&quot; class=&quot;&quot;&gt;List&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; queryForList(String sql, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;2ba7e2d1-f5c9-46f7-806b-fde2448817a2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;queryForMap()&lt;/code&gt;의 다중 로우 버전, 로우의 내용을 Map에 넣고 리스트로 만들어 리턴&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;b475af2b-c1a2-4831-982a-3a682b04348d&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;95f07008-49a3-440b-aee6-5bda7cd67bea&quot; class=&quot;&quot;&gt;SQL 배치 메소드&lt;/h2&gt;&lt;ul id=&quot;adbe6ef7-6704-4597-9aa3-9b57e7ab2f34&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;update()로 실행하는 SQL들을 배치 모드로 실행하게 해줌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1e890313-f5e9-48f9-b422-cb1b6c13ba95&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;내부적으로 &lt;code&gt;JDBC Statement&lt;/code&gt;의 &lt;code&gt;addBatch()&lt;/code&gt;와 &lt;code&gt;executeBatch()&lt;/code&gt;를 이용해 여러 개의 SQL을 한번에 처리&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;912da3fd-4d10-4c92-b228-3783fb876022&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;많은 SQL을 실행해야 하는 경우 배치 방식을 사용하면 DB 호출을 최소화하여 성능 향상&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;f3331e5b-4f9b-4121-b063-2dc9c7d3a943&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;모든 배치 메소드는 하나의 SQL과 SQL 파라미터 배열을 파라미터로 가짐&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;8be0dc99-c784-438a-9c78-192fbe4ba4f0&quot; class=&quot;&quot;&gt;int[] batchUpdate(String sql, Map&amp;lt;String, ?&amp;gt;[] batchValues)&lt;/h3&gt;&lt;ul id=&quot;e7bf4f74-dd0d-47ed-a474-f0a562f3359d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;이름 치환자를 가진 SQL과 파라미터 정보가 담긴 맵의 배열을 이용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;40133df3-3bff-436c-a061-8da9fc6313ea&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;배열의 개수만큼 SQL을 실행하며, 리턴 값은 영향받은 로우의 개수를 담은 배열&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;6f358cf8-d960-4cb6-8063-14ae5982843c&quot; class=&quot;&quot;&gt;int[] batchUpdate(String sql, SqlParameterSource[] batchArgs)&lt;/h3&gt;&lt;ul id=&quot;792dd103-3cd4-4ff6-8b4c-667167c3836d&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;맵 대신 SqlParameterSource 타입 오브젝트의 배열로 파라미터를 제공&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fc11fdf1-c068-4db4-9711-f2321c034078&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;MapSqlParameterSource와 BeanPropertyParameterSource는 모두 SqlParameterSource 타입이므로 함꼐 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;36ac8905-1190-4bf5-9a45-7d361175d913&quot; class=&quot;code&quot;&gt;&lt;code&gt;dao.simpleJdbcTemplate.batchUpdate(&amp;quot;update member set name = :name where id = :id&amp;quot;,
		new SqlParameterSource[] {
				new MapSqlParameterSource().addValue(&amp;quot;id&amp;quot;, 1).addValue(&amp;quot;name&amp;quot;, &amp;quot;Spring3&amp;quot;),
				new BeanPropertySqlParameterSource(new Member(2, &amp;quot;Book3&amp;quot;))
		}
};&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;6f8b4a8d-b0ac-476b-8e7c-4f09d248f795&quot; class=&quot;&quot;&gt;int[] batchUpdate(String sql, List&amp;lt;Object[]&amp;gt; batchARgs)&lt;/h3&gt;&lt;ul id=&quot;8ba58b05-5adb-49da-b51c-c3e60b68c5af&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;위치 치환자를 사용할 때 varags로 전달했던 파라미터를 Object 배열에 넣고 이를 List로 만들어서 전달 가능&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;f51ea065-cdc8-4aed-a0b5-1b1a16d7c316&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;ul id=&quot;07ee55f4-ffb5-4996-b5c0-53b454adb6c0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JdbcTempate&lt;/code&gt;에서 제공하는 좀 더 세밀한 템플릿/콜백 방식을 이용하고 싶다면 &lt;code&gt;getJdbcOperations()&lt;/code&gt;를 이용, JdbcTemplate이 제공하는 메소드를 직접 이용 가능&lt;p id=&quot;f8269019-570b-4a44-b3b6-c4766c13eae2&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.2.3 SimpleJdbcInsert&lt;/h2&gt;&lt;ul id=&quot;1b90dd1e-4a95-450b-8c1b-d5c678b04de2&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL을 이용하는 프로그래밍의 귀찮은 일은 비슷한 구조의 SQL을 반복적으로 만드는 점&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;f5748813-96a9-4568-80c8-3916630894d1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;특히 모든 컬럼을 다 적어야하는 INSERT 문의 작성은 가장 귀찮은 일&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;e13bec68-78dd-4fe2-9366-93f87e7589e0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SQL은 런타임 시에 DB에서 처리되기 떄문에 빌드 시점에서 미리 검증X (쿼리 오타 빈번)&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;15fff40d-11b4-4348-831b-2eec5531aaa4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB 메타정보를 활용해서 INSERT 문의 작성을 간편하게 만들어주는 것이 &lt;code&gt;SimpleJdbcInsert&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;a078c781-c9b2-488d-a70c-df2150233a60&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;998bcbfd-0d67-4903-b4e9-964f1f311510&quot; class=&quot;&quot;&gt;SimpleJdbcInsert 생성&lt;/h2&gt;&lt;ul id=&quot;d77984d4-9a14-4c3b-83ba-19794a9a45b4&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcInsert는 테이블별로 만들어서 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;099c4599-1612-4ae9-b897-7f2bbf1de28c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나의 DAO에서 여러 개의 SimpleJdbcInsert를 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;27455d46-24a6-49d4-972c-8332bcb1b226&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcTemplate은 멀티스레드 환경에서 안전하게 공유해서 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1fae558f-47df-432f-975c-25b4aeee7e46&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;생성할 떄는 DataSource가 필요&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;fa8dbfd1-478c-4231-8a64-b2f928e69646&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(dataSource);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;f3322832-f0a3-4738-a64a-ecbb3a27f311&quot; class=&quot;&quot;&gt;SimpleJdbcInsert withTableName(String tableName)&lt;/h3&gt;&lt;ul id=&quot;553155e1-5e9e-4c81-8f38-2a6847be9893&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;테이블 이름을 지정, DB로부터 테이블 메타정보를 읽어서 INSERT 문에 활용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;72af701e-297b-461c-bd3f-057927f81706&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcInsert jdbcInsert =
		new SimpleJdbcInsert(dataSource).withTableName(&amp;quot;member&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;70a4eb15-57d4-4b49-ba51-b208e3aac269&quot; class=&quot;&quot;&gt;SimpleJdbcInsert withSchemaName(String schemaName), SimpleJdbcInsert withCatalogName(String catalogName)&lt;/h3&gt;&lt;ul id=&quot;8290c973-9277-4094-885b-611d67d63c0b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스키마와 카탈로그 이름을 지정해야 할 경우 사용&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;012477b3-8d6e-430f-b6e3-1fbd6722a8a4&quot; class=&quot;&quot;&gt;SimpleJdbcInsert usingColumns(String... columnNames)&lt;/h3&gt;&lt;ul id=&quot;c0051fb6-f286-4e52-a574-f8bed715546c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcInsert는 기본적으로 테이블의 모든 컬럼을 사용해서 INSERT문을 작성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0df87299-8f0e-4f29-8386-83a218c4b50e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;usingColumns()를 사용하면 일부 컬럼만 사용해서 INSERT문을 작성&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;e9140cba-7e48-4d9b-9d9e-ffb58e192e05&quot; class=&quot;&quot;&gt;SimpleJdbcInsert usingGeneratedKeyColumns(String... columnNames)&lt;/h3&gt;&lt;ul id=&quot;cd01345d-fb81-441f-a8d3-98e4e3152cb6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB에 의해 자동으로 생성되는 키 컬럼을 지정 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;520104c4-692e-48f4-96ea-4a7f909196ed&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;지정된 컬럼은 INSERT 문장에서 제외, 자동 키 값은 INSERT 실행 후 가져오는 것 가능&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;89b82c5d-5c78-4599-871d-9b33497dc865&quot; class=&quot;&quot;&gt;SimpleJdbcInsertOperations withoutTableColumnMetaDataAccess()&lt;/h3&gt;&lt;ul id=&quot;41b04e2e-7a31-4894-97de-92d825b1ff81&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB에서 테이블 메타 정보를 가져오지 않도록 만듬&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;5afd9127-76d4-4223-886d-ba5db39c8a51&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;일부 DB는 메타정보를 제공해주지 않는데 이때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1f041dac-a8fc-4133-8dab-3897f9d02d9f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB의 메타정보 대신 파라미터로 제공된 정보를 활용해서 INSERT 문을 작성&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;dc46f8e7-bd32-442a-bd64-311c3f78d7f9&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;d21c5e2f-1b29-45cf-abe5-b689e5604494&quot; class=&quot;&quot;&gt;SimpleJdbcInsert 실행&lt;/h2&gt;&lt;h3 id=&quot;bd257765-1368-488b-a94b-a0113d5f335b&quot; class=&quot;&quot;&gt;int execute([이름 치환자 SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;94431bf6-6d5c-4397-af31-a0b72eeed590&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcInsert가 내부적으로 생성하는 SQL은 이름 치환자를 가진 INSERT 문이라고 생각하면 됌&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0a5054f2-8b9a-41cd-9646-590cefb99043&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;치환자를 넣을 SQL 파라미터 지정이 필요&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;0ed168e6-3f4f-47e6-877c-61baee9c0656&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;파라미터 지정 방법은 맵(&lt;code&gt;Map&amp;lt;String, Object&amp;gt;&lt;/code&gt;)과 &lt;code&gt;SqlParameterSource&lt;/code&gt; 타입 오브젝트 두 가지 종류 이용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;7120f387-c68d-4005-aa4f-c32608c5b55a&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcInsert insert = new SimpleJdbcInsert(dataSource).withTableName(&amp;quot;member&amp;quot;);
Member member = new Member(1, &amp;quot;Spring&amp;quot;, 3.5);
insert.execute(new BeanPropertySqlParameterSource(member));&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;dabf3972-6b13-4add-b17e-5a94b14af9dd&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcInsert 오브젝트는 테이블 설정이 같다면 재사용 가능, 새롭게 만들 필요 X&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;c26ba887-33c3-43b9-9958-dd0da6e9c279&quot; class=&quot;&quot;&gt;Number executeAndReturnKey([이름 치환자 SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;1c053c73-f6ec-46b3-926a-49487f46fa14&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;execute()와 동일한 작업을 수행하고, 자동생성된 키 값을 Number 타입으로 리턴&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1ac10573-eabb-49ea-afc1-b207df26ff8b&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;java.lang.Number&lt;/code&gt;는 숫자 타입 클래스(Integer, 등)가 모두 상속하고 있는 상위 클래스&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;7fc8e212-a185-427c-9e8e-70da2a483ac7&quot; class=&quot;code&quot;&gt;&lt;code&gt;-- 테이블 생성
CREATE TABLE REGISTER (
		ID INT PRIMARY KEY AUTO_INCREMENT,
		NAME VARCHAR(100) NOT NULL
)

-- INSERT문 (ID는 자동생성)
INSERT INTO REGISTER(NAME) VALUE(&amp;#x27;Spring&amp;#x27;)&lt;/code&gt;&lt;/pre&gt;&lt;pre id=&quot;a97cebf8-c395-4fa1-b296-3cad160906f0&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcInsert registerInsert = new SimpleJdbcInsert(dataSource)
																	.withTableName(&amp;quot;register&amp;quot;)
																	.usingGeneratedKeyColumns(&amp;quot;id&amp;quot;);
int ket = registerInsert.executeAndReturnKey(
					new MapSqlParameterSource(&amp;quot;name&amp;quot;, &amp;quot;Spring&amp;quot;)).intValue();&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;abccb297-441a-4732-9d37-42f3bcf3e6a9&quot; class=&quot;&quot;&gt;KeyHolder executeAndReturnKeyHolder([이름 치환자 SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;f6293f09-fd62-4f0c-a8b9-a09c7883235a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나 이상의 자동생성 키 컬럼을 갖는 테이블도 존재&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;22d1ecb0-cf62-4448-b089-cfa1c6fbc94e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;Number&lt;/code&gt; 대신 &lt;code&gt;KeyHolder&lt;/code&gt; 타입으로 생성된 키 정보를 돌려주는 &lt;code&gt;executeAndReturnKeyHolder()&lt;/code&gt;를 이용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;a8b3eb93-298a-4eaf-a29f-eafc0a31fee8&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;usingGeneratedKeyColumns()&lt;/code&gt;를 초기화할 때 하나 이상의 자동생성 키 컬럼을 넣음&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;1d179747-437a-48be-9242-d97e6605a33a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;KeyHolder&lt;/code&gt;는 키 이름과 생성된 값이 담긴 List&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; 타입으로 돌려주는 &lt;code&gt;getKeyList()&lt;/code&gt;를 제공&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
  
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.2.4 SimpleJdbcCall&lt;/h2&gt;&lt;ul id=&quot;8c0137a1-0f59-429c-bd4c-3df4bf09d314&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB에 생성해둔 저장 프로시저 또는 저장 펑션을 호출할 떄 사용&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;4401fd1d-ccc7-4ba7-a191-4e4b050e0259&quot; class=&quot;&quot;&gt;SimpleJdbcCall 생성&lt;/h2&gt;&lt;ul id=&quot;94e4edc1-adae-4a79-aa44-be98ed186c08&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;dataSource를 이용해 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;dee91fa3-3825-4684-acba-4179ab1fcb50&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;멀티스레드 환경에 안전하므로 인스턴스 변수에 저장해두고 공유해서 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;14e8f345-530a-4923-8d39-f4abc53bba7c&quot; class=&quot;&quot;&gt;SimpleJdbcCallOperations withProcedureName(String procedureName)&lt;/h3&gt;&lt;ul id=&quot;e351d786-48c8-4834-9e05-23a86430a247&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;실행할 프로시저 이름을 지정&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;4649b0c4-0148-4bdf-8891-410fb0fc5390&quot; class=&quot;&quot;&gt;SimpleJdbcCallOperations withFunctionName(String functionName)&lt;/h3&gt;&lt;ul id=&quot;c11b6b56-5219-42fc-924e-0f06c3010344&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;실행할 펑션의 이름을 지정&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;e6023025-891e-4cae-824f-3bf23ff4fbb3&quot; class=&quot;&quot;&gt;SimpleJdbcCallOperations returningResultSet(String parameterName, parameterizedRowMapper rowMapper)&lt;/h3&gt;&lt;ul id=&quot;d508703d-791b-4f3d-9ce0-971cf89f745f&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;프로시저가 ResultSet을 돌려주는 경우에 이를 RowMapper를 이용해 매핑&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;666d147b-8bba-4066-819d-ab1a599e6b8c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나 이상의 ResultSet이 돌아오는 경우라면 순차적으로 returningResultSet()을 지정&lt;/li&gt;&lt;/ul&gt;&lt;p id=&quot;a051f9b4-1034-4e19-8050-c64d5b6f89cd&quot; class=&quot;&quot;&gt;
&lt;/p&gt;&lt;h2 id=&quot;f0098b4b-61aa-4c84-852d-0e8d6117656f&quot; class=&quot;&quot;&gt;SimpleJdbcCall 실행&lt;/h2&gt;&lt;ul id=&quot;b87432c0-3954-4b77-af92-0ea80fd6232e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;DB의 메타정보를 이용해 필요한 파라미터 정보를 가져옴&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;45ceb673-c243-45ea-9368-69926b00260e&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;프로시저나 펑션을 실행할 때는 이에 맞게 파라미터 값을 전달&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;cc8bdcdd-f396-4d46-9336-33ff24d18ea3&quot; class=&quot;&quot;&gt;&amp;lt;T&amp;gt; T executeFunction(Class&amp;lt;T&amp;gt; returnType, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;11f2ba83-0747-4deb-96eb-91e161a730f1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;저장 펑션을 실행해주는 메소드, 리턴 값의 타입과 SQL 파라미터를 전달해서 사용&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;4f8a4149-364f-4527-91d1-f9747e12b80c&quot; class=&quot;code&quot;&gt;&lt;code&gt;create function find_name(in_id INT)
returns varchar(255)
begin
		declare out_name varchar(255);
		select name
				into out_name
				from member
				where id = in_id;
		return out_name;
end&lt;/code&gt;&lt;/pre&gt;&lt;pre id=&quot;a3f1cf24-9896-46b0-ad7c-af02a9b890cb&quot; class=&quot;code&quot;&gt;&lt;code&gt;SimpleJdbcCall call = new SimpleJdbcCall(dataSource).withFunctionName(&amp;quot;find_name&amp;quot;);
String ret = call.executeFunction(String.class, id);&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;dfbab7ef-1b51-4148-89ca-d04b7e0ecd6a&quot; class=&quot;&quot;&gt;&amp;lt;T&amp;gt; T executeObject(Class&amp;lt;T&amp;gt; returnType, [SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;cae6a877-f605-4ce2-9e9b-35755d90ffec&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;저장 프로시저를 호출할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;fd6f5f3c-bcaf-418a-a5f8-68f181a85838&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;프로시저의 출력 파라미터가 하나일 때만 이용, 사용방법은 &lt;code&gt;executeFunction()&lt;/code&gt;과 동일&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;f7a4707c-156d-4d97-856d-fa3fc7499230&quot; class=&quot;&quot;&gt;Map&amp;lt;String, Object&amp;gt; execute([SQL 파라미터])&lt;/h3&gt;&lt;ul id=&quot;a7ce5426-1c79-4447-8dca-d8d8ecbf94db&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;하나 이상의 출력 파라미터를 가진 저장 프로시저를 호출할 때 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;d4892d88-7c60-4eaa-a573-4ba59369cbe5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;여러 개의 출력 파라미터 값이 맵의 형태로 리턴, 리턴 타입을 따로 지정할 필요 X&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
  
  
  
  &lt;header&gt;&lt;/header&gt;&lt;div class=&quot;page-body contents_style&quot;&gt;&lt;h2 class=&quot;page-title&quot;&gt;2.2.5 스프링 JDBC DAO&lt;/h2&gt;&lt;ul id=&quot;9d1a7ef3-0eb3-42f2-9654-cd94981132cb&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;보통 DAO는 도메인 오브젝트 또는 DB 테이블 단위로 생성&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c4555d51-e98d-4f9e-88cf-fddf27c7f84a&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;&lt;code&gt;JdbcTemplate&lt;/code&gt;, &lt;code&gt;SimpleJdbcTemplate&lt;/code&gt;, &lt;code&gt;SimpleJdbcInsert&lt;/code&gt; 등은 모두 멀티스레드 환경에서 안전하게 공유해서 사용 가능&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;92502c6a-d8c6-4dc2-bbb0-a173bd5ac1b0&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;각각을 싱글톤 빈으로 등록해두고 이를 DAO에서 DI 받아서 사용 가능, 하지만 스프링 개발자는 &lt;code&gt;DataSource&lt;/code&gt; 타입의 빈을 DI 받은 뒤 DAO 코드에서 템플릿 오브젝트 등을 생성해서 자주 사용&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;2bacaf2f-7652-4fb1-a900-e2a478d3252c&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcInsert와 SimpleJdbcCall은 테이블이나 저장 프로시저 단위로 오브젝트를 만들어야 하기 떄문에 DAO마다 다른 SimpleJdbcInsert가 사용되는 경향&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9fe1248f-e2c7-418f-bb66-35329dd6a9b5&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;모든 JDBC 오브젝트는 한번 만들어지면 반복적으로 사용 가능하기 떄문에 초기에 만들어 인스턴스 변수에 저장해두는 것이 편리&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;71d0ae06-4643-40b6-af79-c0526d19cc40&quot; class=&quot;code&quot;&gt;&lt;code&gt;public class MemberDao {
		private SimpleJdbcTemplate simpleJdbcTemplate;
		private SimpleJdbcInsert memberInsert;
		private SimpleJdbcCall memberFindCall;

		@Autowired
		public void init(DataSource dataSource) {
				this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
				this.memberInsert = new SimpleJdbcInsert(dataSource).withTableName(&amp;quot;member&amp;quot;);
				this.memberFindCall = 
						new SimpleJdbcCall(dataSource).withFunctionName(&amp;quot;find_member&amp;quot;);
		}&lt;/code&gt;&lt;/pre&gt;&lt;ul id=&quot;1fb6639f-e718-4b3f-a324-09c1b1930e37&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;SimpleJdbcTemplate을 생성하는 코드의 중복을 제거하는 방법은 두가지&lt;ol type=&quot;1&quot; id=&quot;d9ef3625-65d6-4e10-a1de-0b867a0aa06c&quot; class=&quot;numbered-list&quot; start=&quot;1&quot;&gt;&lt;li&gt;SimpleJdbcTemplate를 독립적인 빈으로 등록하고 주입받는 방법&lt;/li&gt;&lt;/ol&gt;&lt;ol type=&quot;1&quot; id=&quot;cc1bd646-9cd0-45ed-86d6-1ef3af4db44c&quot; class=&quot;numbered-list&quot; start=&quot;2&quot;&gt;&lt;li&gt;DAO의 공통 코드를 뽑아내 추상 클래스를 만들어두고 모든 DAO가 이를 상속하는 방법&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;9cc25352-746d-4aec-97c9-f6312bd08ba7&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;스프링은 JdbcDaoSupport라는 JDBC를 이용한 DAO 작성에 사용할 수 있는 추상클래스를 제공&lt;ul id=&quot;a891df4f-0507-4d3d-b17b-81cb013cbfe6&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;DataSource의 DI와 JdbcTemplate의 생성과 같은 공통 기능을 담은 클래스&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;c2dd403a-186b-4024-85ea-a20c8eea91d1&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;SimpleJdbcDaoSupport는 SimpleJdbcTemplate을 사용하는 DAO를 만들때 사용&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id=&quot;451b98fc-17b7-4adc-86d1-62be5adb7229&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:disc&quot;&gt;AbstractSimpleJdbcDaoSupport는 JdbcDaoSupport를 확장해서 SimpleJdbcTemplate 생성과 초기화를 담당하는 메소드를 자동으로 실행해주는 기능을 가진 추상 클래스&lt;ul id=&quot;dca1c190-77af-461e-9889-38bfbdf96955&quot; class=&quot;bulleted-list&quot;&gt;&lt;li style=&quot;list-style-type:circle&quot;&gt;initJdbcObjects()를 오버라이드해서 SimpleJdbcInsert 등을 생성하는 코드를 넣으면 됌&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre id=&quot;002f77ad-153d-4ddf-a103-d4756eb784dd&quot; class=&quot;code&quot;&gt;&lt;code&gt;public abstract class AbstractSimpleJdbcDaoSupport extends JdbcDaoSupport {
		protected SimpleJdbcTemplate simpleJdbcTemplate;
		
		//JdbcDaoSupport에서 제공하는 초기화용 메소드, dataSource가 준비 된 후 호출
		protected void initTemplateConfig() {
				this.simpleJdbcTemplate = new SimpleJdbcTemplate(getDataSource());
				initJdbcObjects();
		}
		
		//SimpleJdbcDaoSupport를 상속받는 DAO에서 SimpleJdbcInsert 등을 생성할 때 
		//오버라이드해서 사용할 수 있는 초기화 메소드
		protected void initJdbcObjects() {}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  
&lt;/article&gt;</description>
      <category>개발서적/토비 스프링 3.1-Vol.2</category>
      <category>스프링</category>
      <category>토비</category>
      <category>토비스프링</category>
      <author>밀리노트</author>
      <guid isPermaLink="true">https://milenote.tistory.com/169</guid>
      <comments>https://milenote.tistory.com/169#entry169comment</comments>
      <pubDate>Mon, 17 Jan 2022 22:14:30 +0900</pubDate>
    </item>
  </channel>
</rss>