티스토리 뷰
Spring Boot 에서는 대표적인 DBMS(DataBase Management System)에 표준적으로 접속 정보를 설정하고 JDBC, Connection Pool 등을 자동으로 구성해서 사용자가 쉽게 질의(query)를 할 수 있는 기능을 제공합니다.
1. 프로젝트 생성
아래와 같이 프로젝트 생성 시 JDBC 와 DBMS 에 맞는 Driver 만 선택해주면 의존성 추가를 해줍니다.
실제 이미지와 같이 선택하면 아래 코드와 같이 pom.xml 파일에 두 개의 의존성만이 추가될 뿐입니다. 하지만, 이 두 개의 의존성 추가만으로 DB 접속을 할 수 있는 환경을 쉽게 구축할 수 있습니다.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
2. DB 연결 정보 설정
프로젝트를 생성한 뒤 실행해보면 아래와 같이 오류가 발생합니다.
이유는 Spring Boot JDBC 환경을 구성한 상태에서 아무런 접속 정보를 입력하지 않았기 때문에 접속할 수 있는 DBMS 가 없기 때문입니다. 만약 Embedded 하게 동작하는 DBMS(H2, HSQL, Derby) 을 프로젝트 생성 시 선택했다면 프로그램 실행과 동시에 DBMS 가 같이 시작되고 Spring Boot 의 기본값에 의해 자동 접속을 하기 때문에 위와 같은 오류가 나타나지 않지만, 위에서 MySQL 을 선택했기 때문에 오류가 발생합니다.
그래서 아래와 같이 application.yml (application.properties 을 이용해도 됩니다) 파일에 DB 접속 정보를 설정합니다. (물론 아래 접속 정보는 실제 정보와 다릅니다)
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost/dev username: zepinos password: "testpassword"
사실 일반적인 DBMS 는 위의 네 가지 정보만 입력해도 사용가능하지만, 여러가지 설정을 위해서 Spring Boot 레퍼런스 가이드의 부록을 확인하여 더 많은 JDBC 옵션을 이용할 수 있습니다.
추가적으로, 지금 이 글을 적고 있는 현재의 Spring Boot 최신 버전은 2.0.3-RELEASE 로
Connection Pool 은 기본적으로 Hikari CP 를 이용하도록 되어 있습니다. Hikari CP 는 뛰어난 성능을
보여주는 Connection Pool 이지만 설정변수가 기존의 다른 Connection Pool 와 조금 다릅니다. 하지만,
Spring Boot 에서 기본 DBMS 설정 정보로 입력해줄 경우에는 Hikari CP 고유의 설정변수가 아니어도 치환되어서
자동으로 설정을 해줍니다.
Spring Boot 의 기본 DBMS 접속 설정은 1 개의 접속 설정만 입력받을 수 있기 때문에, 2 개 이상의 접속 설정을
입력 받아 Connection 을 여러 개 만들어야 한다면 Hikari CP 을 이용할 경우 설정 변수명을 바꿔야 하므로 주의해야
합니다.
위와 같이 설정 정보를 입력한 후 다시 프로그램을 실행하면 정상적으로 프로그램이 실행되는 것을 확인할 수 있습니다.
3. 웹사이트 생성 확인
DB 에 질의를 하기 전에, 먼저 확인하기 쉽도록 웹페이지를 만들어 보겠습니다.
먼저 Controller 파일입니다.
package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Collections; import java.util.Map; @Controller @RequestMapping("/hello") public class HelloController { @GetMapping("") public String get(ModelMap modelMap) throws Exception { Map<String, String> test = Collections.singletonMap("name", "테스트"); Map<String, Object> result = Collections.singletonMap("test", test); modelMap.put("result", result); return "/hello/get"; } }
Controller 파일의 return 에서 "hello/get" 을 입력했고, 프로젝트 생성 시 Thymeleaf 을 선택했기 때문에 templates/hello/get.html 파일을 아래와 같이 만들어서 내용을 출력합니다.
<!DOCTYPE html> <html lang="ko" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Hello</title> </head> <body> Hello World : <span th:text="${result.test.name}">HTML</span> </body> </html>
프로그램을 실행해서 결과를 확인해봅니다.
Controller 에서 입력한 테스트라는 글자가 표시됨을 확인할 수 있습니다.
4. JdbcTemplate 로 질의하기
먼저 DB 에 질의하기 위해서 test 테이블을 만들고 아래와 같이 데이터를 입력해두었습니다.
DB 에 질의하기 위해 Controller 을 수정하고 Service 와 DAO 파일을 추가하였습니다.
HelloController
package com.example.demo.controller; import com.example.demo.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/hello") public class HelloController { @Autowired private HelloService helloService; @GetMapping("") public String get(ModelMap modelMap) throws Exception { modelMap.put("result", helloService.getTest()); return "/hello/get"; } }
HelloService
package com.example.demo.service; import com.example.demo.dao.TestDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.Map; @Service public class HelloService { @Autowired private TestDao testDao; public Map<String, Map<String, Object>> getTest() throws Exception { return Collections.singletonMap("test", testDao.getName(1)); } }
TestDao
package com.example.demo.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.util.Map; @Component public class TestDao { @Autowired private JdbcTemplate jdbcTemplate; public Map<String, Object> getName(int seq) throws Exception { return jdbcTemplate.queryForMap(" select name from test where seq = ?", seq); } }
그리고 프로그램을 재실행 한 뒤 웹페이지에 접속하면 다음과 같이 출력됩니다.
5. java.sql.Connection 획득하기
아주 간혹, 혹은 본인의 익숙함 때문에 java.sql.Connection 객체를 그대로 이용하고 싶은 경우도 있습니다. 예전처럼 객체지향 답지 않게 Connection 객체를 생성해서 Statmement/PreparedStatement 로 질의를 정의하고 ResultSet 으로 결과를 획득하여 값을 처리하는 것이 효율적인 경우도 분명 존재하기 때문에 별도로 설정을 하지 않고 Spring Boot 에서 Connection 을 획득할 수 있다면 더욱 좋을 것입니다.
위의 TestDao.java 파일의 getName() 메서더를 아래와 같이 변경해보았습니다. 실행해보면 결과는 이전과 동일합니다. 다만 코드 길이가 많이 차이남을 알 수 있습니다. JdbcTemplate 에서 Map 객체에 값을 주입해주기 때문에 ResultSet 에서 값을 가져와 객체를 생성해 값을 입력하는 과정을 생략할 수 있기 때문입니다. 주의할 점은 ResultSet 은 DBMS 의 커서를 받아 한 레코드씩 결과를 전송받아 전달해주는 객체이기 때문에 게시판처럼 수십 줄 정도를 불러와 처리하는 경우에는 별다른 차이가 없으나 수천, 수만 줄 이상의 레코드를 결과로 받아와 한 번에 처리해야 하는 경우라면 객체에 주입하기 위해, 그리고 주입 후 처리를 위해 덩치 큰 객체와 이를 처리하기 위한 객체 사용 등으로 GC 에 굉장한 부담을 줄 수 있습니다. 그러므로 Connection 객체를 이용해서 직접 ResultSet 결과를 처리해야 할 경우가 있기 때문에 아래와 같은 방법을 알고 있는 것이 좋습니다.
public Map<String, Object> getName(int seq) throws Exception { Connection conn = jdbcTemplate.getDataSource().getConnection(); PreparedStatement pstmt = conn.prepareStatement(" select name from test where seq = ? "); pstmt.setInt(1, seq); ResultSet rs = pstmt.executeQuery(); Map<String, Object> result; if (rs.next()) { String name = rs.getString("name"); result = Collections.singletonMap("name", name); } else { result = Collections.singletonMap("name", null); } return result; }
위의 코드에서는 JdbcTemplate 에서 DataSource 을 획득하여 Connection 을 획득하는 방법을 보여주고 있습니다.
JdbcTemplate 에서 이렇게 쉽게 DataSource 을 획득할 수 있지만, 사실 Spring 기반이기 때문에 Bean
으로 등록된 객체는 모두 주입(Inject) 받을 수 있기 때문에 직접 DataSource 객체를 획득할 수도 있습니다.
@Autowired private ApplicationContext applicationContext; public Map<String, Object> getName(int seq) throws Exception { DataSource ds = (DataSource) applicationContext.getBean("dataSource"); Connection conn = ds.getConnection(); // 이하 생략 }
'Programming > Spring Boot 시작하기' 카테고리의 다른 글
TaskExecutor 로 @Async 의 Thread 을 Pool 로 관리하기 (0) | 2019.01.22 |
---|---|
MyBatis 와 JOOQ 을 연동해보기 (0) | 2018.09.05 |
의존성을 추가하여 템플릿(Thymeleaf) 사용 환경 구축하기 (2) | 2018.09.05 |
application.properties 살펴보기 (0) | 2018.09.05 |
Spring Boot 로 Hello World 출력하기 (0) | 2018.09.04 |
- Total
- Today
- Yesterday
- Phabricator
- Redmine
- couchbase
- 내장 WAS
- messages.properties
- 도입기
- java config
- paging
- proxmox
- KDE
- Spring MVC
- 시니어 프로그래머
- Spring
- 프로젝트 규모
- SI
- boot
- RestTemplate
- manjaro
- 워드프레스
- Spring Boot
- jooq
- docker
- 페이징
- 클라우드플레어
- git
- OracleJDK
- 엘지
- 외장 WAS
- Nas
- NoSQL
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |