Java application은 JDBC API를 이용하여 데이터 계층과 통신
과정
Connection
획득
Statement
를 이용한 질의
ResultSet
을 이용한 질의 결과 사용
Statement
, Connection
반납
try {
Class.forName(JDBC_DRIVER); // Driver 불러오기
Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
log.info("Connection 획득");
Statement statement = connection.createStatement();
log.info("Statement 획득");
log.info("쿼리 실행");
statement.executeUpdate(DROP_TABLE_SQL);
statement.executeUpdate(CREATE_TABLE_SQL);
statement.executeUpdate(INSERT_SQL);
ResultSet resultSet = statement.executeQuery("SELECT id, first_name, last_name FROM customers WHERE id = 1");
while(resultSet.next()) {
log.info(resultSet.getString("first_name"));
}
log.info("반납");
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
기존 JDBC를 이용했을 때의 반복적인 작업(위의 과정)을 JDBC Template이 대신 수행
Select문
결과가 여러 개일 경우
jdbcTemplate.query("query", customerRowMapper);
결과가 하나일 경우
Object
try {
return Optional.ofNullable(jdbcTemplate.queryForObject(
"select * from customers where customer_id = UUID_TO_BIN(?)",
customerRowMapper,
customerId.toString().getBytes()));
}catch (EmptyResultDataAccessException e) {
logger.error("Got empty result", e);
return Optional.empty();
}
int
jdbcTemplate.queryForObject("query", Integer.class);
Insert문 & Update문 & Delete문
var update = jdbcTemplate.update("UPDATE customers SET name = ?, last_login_at = ? WHERE customer_id = UUID_TO_BIN(?)",
customer.getName(),
customer.getLastLoginAt() != null ? Timestamp.valueOf(customer.getLastLoginAt()) : null,
customer.getCustomerId().toString().getBytes());
if(update != 1) throw new RuntimeException("Noting was updated");
return customer;
JDBC Template의 문제점인 자바 코드와 SQL문의 분리가 안된다는 점을 해결 -> MyBatis와 같은 Query Mapper
쿼리 수정으로 자바 코드 수정 이나 컴파일 하는 작업 X
설정
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
mybatis:
type-aliases-package: org.prgms.kdt.order.repository.domain # ResultSet을 Mapping해줄 Pojo 객체의 위치
configuration:
map-underscore-to-camel-case: true
default-fetch-size: 100 # SELECT문에서 최대로 가져올 수
default-statement-timeout: 30
mapper-locations: classpath:mapper/*.xml
Mapping Query
방법1. Annotation
@Mapper
public interface CustomerMapper {
@Insert("INSERT INTO customers (id, first_name, last_name) VALUES(#{id}, #{firstName}, #{lastName})")
void save(Customer customer);
@Update("UPDATE customers SET first_name=#{firstName}, last_name=#{lastName} WHERE id=#{id}")
void update(Customer customer);
@Select("SELECT * FROM customers")
List<Customer> findAll();
@Select("SELECT * FROM customers WHERE id = #{id}")
Customer findById(@Param("id") long id);
}
방법2. XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kdt.lecture.repository.CustomerMapper"> <!-- Mapping 받을 interface -->
<insert id="save">
INSERT INTO customers (id, first_name, last_name)
VALUES (#{id}, #{firstName}, #{lastName})
</insert>
<update id="update">
UPDATE customers
SET first_name=#{firstName},
last_name=#{lastName}
WHERE id = #{id}
</update>
<select id="findById" resultType="customers">
SELECT *
FROM customers
WHERE id = #{id}
</select>
<select id="findAll" resultType="customers">
SELECT *
FROM customers
</select>
</mapper>
Mapper Interface
@Mapper
public interface CustomerXmlMapper {
void save(Customer customer);
void update(Customer customer);
Customer findById(long id);
List<Customer> findAll();
}
Entity
import org.apache.ibatis.type.Alias;
@Alias("customers")
public class Customer {
private long id;
private String firstName;
private String lastName;
// 테스트 용
public Customer(long id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
// MyBatis는 getter, setter 이용
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Reference
프로그래머스 백엔드 데브코스