© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📻
MyBatis JdbcTemplate을 이용하면 쿼리문과 코드가 섞이게 됨 → 유지보수가 힘들어짐 쿼리와 코드를 구분하기 위해 사용하는 것이 MyBatis
Getting Started 의존성, config 설정 mybatis.org — mybatis spring boot autoconfigure, config 설명
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.1'
Mapper 코드 작성
xml 작성
XML 작성법 <mapper> tag에 namespace에는 @Mapper
인터페이스의 풀 경로를 입력 select
, insert
, update
, delete
의 id
에 매핑할 method의 이름을 작성INSERT, UPDATE useGeneratedKeys
: MyBatis에게 DB의 auto increment 기능으로 부터 키값을 가져오는 기능을 활성화 하겠다 라는 옵션 설정keyProperty
: getGeneratedKeys의 value를 어느 프로퍼티에 설정할 것인지. 즉 키값이 어떤 필드인지insert
호출하고 나면 파라미터로 들어간 객체의 pk
값에 DB에서 auto_increment
된 값 할당됨ResultMapping resultMap을 이용하여 sql에 의해 반환되는 결과를 class에 매핑시킬 수 있음(컬럼명과 프로퍼티명이 다른 경우) id
값은 객체 인스턴스를 비교할 때 사용되는 구분자 프로퍼티로 처리됨Auto-mapping 위의 경우, id와 userName은 컬럼과 클래스 필드의 이름이 같아서 자동매핑이 진행되고, hashed_password의 경우 수동 매핑으로 처리됨 자동매핑에는 3가지가 있음 PARTIAL(default) : 조인 내부에 정의한 내포된 결과매핑을 제외하고 자동매핑 자동매핑 설정에 상관없이 구문 별로 autoMapping
속성을 추가해서 자동 매핑을 사용하거나 사용하지 않을 수도 있음
Parameters 디폴트 설정으로 #{}
을 사용하게 되면 MyBatis에서는 PreparedStatement를 생성하고 거기에 파라미터를 대입함 메서드의 parameter가 클래스 일 때, 클래스의 프로퍼티를 파라미터로 넘겨줄 수 있음 String Substitution String Substitution은 sql의 metadata(테이블 이름, 컬럼 이름)가 동적이어야 할 때 매우 유용함 ${column}
은 바로 값이 대치가 되고, #{value}
는 PreparedStatement
로 대입됨spring:
datasource:
username: "root"
password: "1234"
url: "jdbc:mysql://localhost:3306/weareone"
mybatis:
type-aliases-package: com.example.springjpa.repository.domain # 해당 pojo object에 resultSet을 자동으로 매핑해줌
type-handlers-package: com.kdt.lecture.repository.typehandler
configuration:
map-underscore-to-camel-case: true # first_name, last_name -> firstName, lastName
default-fetch-size: 100 # 한번에 몇개 가져올 거냐
default-statement-timeout: 30 #statement가 RDB와 통신하는 객체인데 여기서 timeout을 얼마로 할거냐
mapper-locations: classpath:mapper/*.xml
application.yaml // Using 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);
}
...
// Using XML
@Mapper
public interface CustomerXmlMapper {
void save(Customer customer);
void update(Customer customer);
Customer findById(long id);
List<Customer> findAll();
}
<?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.CustomerXmlMapper">
<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>
<?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.CustomerXmlMapper">
<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>
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
<typeAlias type="com.someapp.model.User" alias="User"/>
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select
user_id as "id",
user_name as "userName",
hashed_password
from some_table
where id = #{id}
</select>
<resultMap id="userResultMap" type="User">
<result property="password" column="hashed_password"/>
</resultMap>
<resultMap id="userResultMap" type="User" autoMapping="false">
<result property="password" column="hashed_password"/>
</resultMap>
#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}
null값이 들어올 때를 대비하여 jdbcType을 명시하는 정도는 필요할 수 있다 <insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);