Java Mybatis

๊น€์ •ํ›ˆยท2024๋…„ 5์›” 23์ผ

Java

๋ชฉ๋ก ๋ณด๊ธฐ
41/48

Mybatis

1. ์„ค์น˜

mybatis3.xx

2. ์„ค์ •

SqlSessionFactory ๐Ÿ‘‰ SqlSession ๊ฐ์ฒด ์ƒ์„ฑ
SqlSessionFactoryBuilder ๐Ÿ‘‰ ์„ค์ • ๐Ÿ‘‰ SqlSessionFactory ๊ฐ์ฒด์ƒ์„ฑ

public class DBConn {
    private static SqlSessionFactory factory;

    static{
        try {
            Reader reader = Resources.getResourceAsReader("configs/mybatis-config.xml"); //SqlSessionFactory ์„ค์ • XMLํŒŒ์ผ๊ฒฝ๋กœ
            factory = new SqlSessionFactoryBuilder().build(reader);
        }catch(IOException e){
            e.printStackTrace();
        }

    }

    public static SqlSession getSession(boolean autoCommit){ //์ปค๋ฐ‹์„ ์ œ์–ดํ• ์ˆ˜์žˆ๋Š” ๋ฉ”์„œ๋“œ

        return factory.openSession(autoCommit); //๊ธฐ๋ณธ๊ฐ’์€ false์ด๊ธฐ ๋•Œ๋ฌธ์— ์ปค๋ฐ‹ํ•˜์ง€์•Š๋Š”๋‹ค.
    }

    public static SqlSession getSession(){ //๋ฐ”๋กœ ์ปค๋ฐ‹์ด ๋˜๋Š” ๋ฉ”์„œ๋“œ
        return factory.openSession(true);
    }

}

1) XML์—์„œ SqlSessionFactory ๋นŒ๋“œํ•˜๊ธฐ

๋ณ€๊ฒฝ๋˜์ง€์•Š๋Š” ์ •์  ์„ค์ •ํŒŒ์ผ์€ resources์— ์ €์žฅํ•ด์•ผํ•œ๋‹ค.

XML์„ค์ •ํŒŒ์ผ์—์„œ ์ง€์ •ํ•˜๋Š” ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์˜ ํ•ต์‹ฌ์ด ๋˜๋Š” ์„ค์ •์€ ํŠธ๋žœ์žญ์…˜์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ TransactionManager๊ณผ ํ•จ๊ป˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค Connection์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ DataSource ๋ฅผ ํฌํ•จํ•œ๋‹ค.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mappers.MemberMapper"> <!--ํ˜„์žฌํŒŒ์ผ๊ฒฝ๋กœ-->
    <resultMap id="memberMap" type="member.Member"> <!--๋ฉค๋ฒ„ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜๋ช…์„ map์ฒ˜๋ฆฌํ•˜์—ฌ ์˜ค๋ผํด๊ณผ ๋™์ผํ•˜๊ฒŒ๋งŒ๋“ฌ-->
        <result column="USER_NO" property="userNo" />
        <result column="USER_ID" property="userId" />
        <result column="USER_PW" property="userPw" />
        <result column="USER_NM" property="userNm" />
        <result column="MOBILE" property="mobile" />
        <result column="REG_DT" property="regDt" />
        <result column="MOD_DT" property="modDt" />
    </resultMap>

    <select id="getList" resultMap="memberMap"><!--ํด๋ž˜์Šค๊ฒฝ๋กœ  or ๋งคํผ๋œ๋ณ€์ˆ˜์ด๋ฆ„-->
        SELECT * FROM MEMBER
    </select>
    <!--
    <insert>

    </insert>
    <update>

    </update>
    <delete>

    </delete>
    -->
</mapper>

2) SQL๋งคํ•‘ํ•˜๊ธฐ

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mappers.MemberMapper"> <!--ํ˜„์žฌํŒŒ์ผ๊ฒฝ๋กœ-->
    <select id="getList" resultType="member.Member"> <!--ํด๋ž˜์Šค๊ฒฝ๋กœ-->
        SELECT * FROM MEMBER
    </select>
    <!--
    <insert id="">

    </insert>
    <update id="">

    </update>
    <delete id="">

    </delete>
    -->
</mapper>

3) SqlSession : SQL ๊ตฌ๋ฌธ ์‹คํ–‰

  • insert(...)
  • delete(...)
  • update(...)
  • List<T> selctList(...)
  • T selectOne(...)
public class Member {
    private long USER_NO;
    private String USER_ID;
    private String USER_PW;
    private String USER_NM;
    private String MOBILE;
    private LocalDateTime REG_DT;
    private LocalDateTime MOD_DT;
}
//์˜ค๋ผํด๊ณผ ๋ณ€์ˆ˜๋ช…์ด ๋™์ผํ•ด์•ผํ•œ๋‹ค.

getMapper(Class class)

public class Ex01 {
    @Test
    void test1(){
        SqlSession session = DBConn.getSession();
        List<Member> members = session.selectList("mappers.MemberMapper.getList");
        members.forEach(System.out::println);

    }

    @Test
    void test2(){
        SqlSession session = DBConn.getSession();
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        //MemberMapper๊ณผ ๋™์ผํ•œ ์ด๋ฆ„์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ getList์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ฌ์ˆ˜๋„์žˆ๋‹ค.
        List<Member> members = mapper.getList();
        members.forEach(System.out::println);
    }
}

//MemberMapper๊ณผ ๋™์ผํ•œ ์ด๋ฆ„์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ getList์„ ํ•ด๋‹น ๋งคํผ๋ฅผ ๊ฐ€์ ธ์˜ฌ์ˆ˜๋„์žˆ๋‹ค.

4)์˜์กด์„ฑ ์„ค์ •

์˜์กด์„ฑ ์„ค์ •

5) ๋งคํผ ์ธํ„ฐํŽ˜์ด์Šค

@Select(...)
@Insert(...)
@Update(...)
@Delete(...)

//MemberMapper ์ธํ„ฐํŽ˜์ด์Šค
public interface MemberMapper {
    List<Member> getList();

	//๋ฉค๋ฒ„ํด๋ž˜์Šค์— ๋ณ€์ˆ˜๋ช…๊ณผ ์˜ค๋ผํด์˜ ๋ณ€์ˆ˜๋ช…์ด ๋‹ฌ๋ผ์„œ ์˜ค๋ผํด์˜ ๋ณ€์ˆ˜๋ช…๊ณผ ๋˜‘๊ฐ™์ด ํ•ด์•ผํ•˜๊ธฐ๋–„๋ฌธ์— ๋ณ„์นญ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ‘œํ˜„
    @Select("SELECT USER_NO userNo, USER_ID userId FROM MEMBER") 
    List<Member> getList2();
}

public class Ex01 {
    @Test
    void test3(){
        SqlSession session = DBConn.getSession();
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        List<Member> members = mapper.getList2();
        members.forEach(System.out::println);
    }
}

3. ์ ์šฉ

4. ๋กœ๊ทธ

SLF4J
slf4j.api : slf4j ๊ฐ€์ด๋“œ๋ผ์ธ(์ธํ„ฐํŽ˜์ด์Šค ์œ„์ฃผ) ๐Ÿ‘‰ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ตฌํ˜„(logback-class)์ด ํ•„์š”
logback-class : ๊ตฌํ˜„์ฒด

๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋Š” ๋‚ด๋ถ€ ๋กœ๊ทธ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊น… ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋‚ด๋ถ€ ๋กœ๊ทธ ํŒฉํ† ๋ฆฌ๋Š” ๋กœ๊น… ์ •๋ณด๋ฅผ ๋‹ค๋ฅธ ๋กœ๊ทธ ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์— ์ „๋‹ฌํ•œ๋‹ค.

์„ค์ •

1) ์˜์กด์„ฑ

slf4j.api, Logback Classic

implementation 'org.slf4j:slf4j-api:2.0.13' //slf4j.api
implementation 'ch.qos.logback:logback-classic:1.5.6'//Logback Classic Module

2) mybitis ์„ค์ • "mybatis-config.xml"

...
    <settings>
        <setting name="logImpl" value="SLF4J"/> <!--log์„ค์ •-->
    </settings>
...

3) LogBack์„ค์ • "logback,xml"

๋กœ๊ทธ๋ ˆ๋ฒจ : ๋ ˆ๋ฒจ๋ณ„๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

  • FATAL :
  • ERROR :
  • WARN : ๊ฒฝ๊ณ (์˜ค๋ฅ˜ โŒ, ๋ฌธ์ œ ์†Œ์ง€๊ฐ€ ์ƒ๊ธธ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ)
  • INFO : ์ผ๋ฐ˜์ •๋ณด
  • DEBUG : ์ž์„ธํ•œ ์ •๋ณด
  • TRACE : DEBUG๋ณด๋‹ค ๋” ์ž์„ธํ•œ ์ •๋ณด

<pattern> : ๋กœ๊ทธ ๊ธฐ๋ก ํŒจํ„ด

  • %d : ๋กœ๊ทธ ๊ธฐ๋ก ์‹œ์ (๋‚ ์งœ, ์‹œ๊ฐ„)
  • %p : ๋กœ๊ทธ ๋ ˆ๋ฒจ, %5p ๐Ÿ‘‰ 5๊ธ€์ž๋‚ด์—์„œ ๋กœ๊ทธ๋ ˆ๋ฒจ์„ ํ‘œ๊ธฐ
  • %t : ์“ฐ๋ ˆ๋“œ
  • %m : ๋กœ๊ทธ ๋ฉ”์„ธ์ง€
  • %n : ์ค„๊ฐฑ
  • %c: ํŒจํ‚ค์ง€๋ช…์„ ํฌํ•จํ•œ ์ „์ฒด ํด๋ž˜์Šค๋ช…, %c{2} : ํŒจํ‚ค์ง€๋ช…์€ ํ•œ ์ž๋กœ ์ถ•์•ฝ, ํด๋ž˜์Šค๋ช…์€ ์ „์ฒด์ด๋ฆ„
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration>

    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%5level [%thread] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO"><!--๋กœ๊ทธ๋ ˆ๋ฒจ-->
        <appender-ref ref="stdout"/>
    </root>

    <logger name="mappers">  <!--๋งคํผ๊ฒฝ๋กœ-->
        <level value="DEBUG"/> <!--๋กœ๊ทธ๋ ˆ๋ฒจ-->
    </logger>

</configuration>

insert update delete ๋นŒ๋”์‚ฌ์šฉ

(1) MemberMapper ์ธํ„ฐํŽ˜์ด์Šค

package mappers;

import member.Member;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface MemberMapper {
    List<Member> getList();

    @Select("SELECT USER_NO userNo, USER_ID userId FROM MEMBER")
    List<Member> getList2();

    int register(Member member);
    int register2(Member member); //์‹œํ€€์Šค ๊ฐ’ ๋„ฃ๋Š”๊ฑฐ

    int modify(Member member);

    int delete(String userId);

    @Delete("DELETE FROM MEMBER WHERE USER_ID = #{userID}")
        //๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ๋Š” mappers.membermappe์— ์ •์˜ํ•˜๊ธฐ๋ณด๋‹ค๋Š” ๋‘๊ณณ์— ์ •์˜ํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์—ฌ๊ธฐ์„œ ์ •์˜ํ•˜์—ฌ ๋ฐ”๋กœ ์‚ฌ์šฉ
    int delete2(String userId);


}

(2) member.mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mappers.MemberMapper"> <!--ํ˜„์žฌํŒŒ์ผ๊ฒฝ๋กœ-->
    <resultMap id="memberMap" type="member.Member"> <!--๋ฉค๋ฒ„ํด๋ž˜์Šค์˜ ๋ณ€์ˆ˜๋ช…์„ map์ฒ˜๋ฆฌํ•˜์—ฌ ์˜ค๋ผํด๊ณผ ๋™์ผํ•˜๊ฒŒ๋งŒ๋“ฌ-->
        <result column="USER_NO" property="userNo" />
        <result column="USER_ID" property="userId" />
        <result column="USER_PW" property="userPw" />
        <result column="USER_NM" property="userNm" />
        <result column="MOBILE" property="mobile" />
        <result column="REG_DT" property="regDt" />
        <result column="MOD_DT" property="modDt" />
    </resultMap>

    <select id="getList" resultMap="memberMap"><!--ํด๋ž˜์Šค๊ฒฝ๋กœ  or ๋งคํผ๋œ๋ณ€์ˆ˜์ด๋ฆ„-->
        SELECT * FROM MEMBER
    </select>
    <insert id="register">
        INSERT INTO MEMBER (USER_NO, USER_ID, USER_PW, USER_NM, MOBILE)
        VALUES (SEQ_MEMBER.NEXTVAL, #{userId}, #{userPw}, #{userNm}, #{mobile})
    </insert>
    <insert id="register2">
        <selectKey keyProperty="userNo" order="BEFORE" resultType="long">
            <!-- ์‹œํ€€์Šค๊ฐ์ฒด์— ๊ฐ’์„ ๋„ฃ์„์ˆ˜ ์žˆ๊ฒŒํ•จ.  insert์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ „์— ๋จผ์ € ์ˆ˜ํ–‰ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— BEFORE -->
            SELECT SEQ_MEMBER.NEXTVAL FROM DUAL
        </selectKey>
        INSERT INTO MEMBER (USER_NO, USER_ID, USER_PW, USER_NM, MOBILE)
        VALUES (#{userNo}, #{userId}, #{userPw}, #{userNm}, #{mobile})
        <!-- SELECT SEQ_MEMBER.NEXTVAL FROM DUAL์„ํ†ตํ•ด ๊ฐ€์ ธ์˜จ ์‹œํ€€์Šค๊ฐ’์„ userno์— ๋„ฃ์Œ -->
    </insert>
    <update id="modify">
        UPDATE MEMBER
        SET
            USER_PW = #{userPw},
            USER_NM = #{userNm},
            MOBILE = #{mobile},
            MOD_DT = SYSDATE
        WHERE USER_ID = #{userId}
    </update>
    <delete id="delete">
        DELETE FROM MEMBER
        WHERE USER_ID = #{userId}
    </delete>

</mapper>
public class Ex02 {

    private SqlSession session = DBConn.getSession();

    @Test
    void test1(){ //insert
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        Member member = Member.builder()
                .userId("USER" + System.currentTimeMillis())
                .userPw("123456").
                userNm("์‚ฌ์šฉ์ž..").
                mobile("01000000000").
                build();//๋นŒ๋”ํŒจํ„ด ์‚ฌ์šฉ

        //int cnt = mapper.register(member);
        //int cnt = session.insert("mappers.MemberMapper.register", member);
        int cnt = mapper.register2(member);
        System.out.println(cnt);
        System.out.println(member);
    }

    @Test
    void test2(){ //update
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        Member member = Member.builder()
                .userId("USER01")
                .userPw("123456").
                userNm("(์ˆ˜์ •)์‚ฌ์šฉ์ž..").
                mobile("01000000000").
                build();//๋นŒ๋”ํŒจํ„ด ์‚ฌ์šฉ


        int cnt = mapper.modify(member);
        //int cnt = session.update("mappers.MemberMapper.modify", member);
        System.out.println(cnt);
    }

    @Test
    void test3(){
        Member member = Member.builder()
                .userId("USER01")
                .build();
        int cnt = session.delete("mappers.MemberMapper.delete",member);
        System.out.println(cnt);
    }

    @Test
    void test4(){
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        int cnt = mapper.delete("USER02");
        int cnt2 = mapper.delete2("USER03");
        System.out.println(cnt);
        System.out.println(cnt2);
    }
}

5. ๋™์  SQL

1) if

<update id="modify2"> <!--๋™์  SQL-->
        UPDATE MEMBER
        SET
            <if test="userPw != null"> <!--๋™์  SQL-->
                USER_PW = #{userPw},
            </if>
            <if test="userNm != null"> <!--๋™์  SQL-->
            USER_PW = #{userNm},
            </if>
            <if test="mobile != null"> <!--๋™์  SQL-->
            MOBILE = #{mobile},
            </if>
            MOD_DT = SYSDATE
        WHERE USER_ID = #{userId}
    </update>

2) choose, when, otherwise

3) trim, where, set

trim

<trim..>
	prefix = "WHERE" : trim ํƒœ๊ทธ ๋‚ด๋ถ€์— ์œ ํšจํ•œ ์กฐ๊ฑด์‹์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์ถœ๋ ฅ
  	suffix
  	prefixOverrides = "AND | OR" : ๊ฐ€์žฅ ์•ž์ชฝ์— ๋‚˜์™€ ์žˆ๋Š” (WHERE ๋ฐ”๋กœ ๋’ค ) AND ๋˜
  ๋Š” OR์ œ๊ฑฐ
  	suffixOverrides="," : ๋งˆ์ง€๋ง‰","๋Š” ์ œ๊ฑฐ
</trim>
<select id="getList3" resultMap="memberMap">
        SELECT * FROM MEMBER
        <trim prefix="WHERE" prefixOverrides="AND | OR">
            <if test="userId != null">
                USER_ID = #{userId}
            </if>
            <if test="userNm != null">
                AND USER_NM LIKE #{userNm}
            </if>
            <if test="mobile != null">
                AND MOBILE LIKE #{mobile}
            </if>
        </trim>
    </select>
package exam01;

import configs.DBConn;
import mappers.MemberMapper;
import member.Member;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class Ex03 {

    private SqlSession session = DBConn.getSession();
  
    @Test
    void test2(){
        MemberMapper mapper = session.getMapper(MemberMapper.class);
        Member member = Member.builder()
                //.userId("USER99")
                .userNm("%์‚ฌ์šฉ%")
                .mobile("%010%")
                .build();
        List<Member> members = mapper.getList3(member);
        members.forEach(System.out::println);
    }
}

where

<where>
  
</where>
 <select id="getList3" resultMap="memberMap">
        SELECT * FROM MEMBER
        <where>
            <if test="userId != null">
                USER_ID = #{userId}
            </if>
            <if test="userNm != null">
                AND USER_NM LIKE #{userNm}
            </if>
            <if test="mobile != null">
                AND MOBILE LIKE #{mobile}
            </if>
        </where>
    </select>

set

<update id="modify2"> <!--๋™์  SQL-->
        UPDATE MEMBER
        <set>
            <if test="userPw != null"> <!--๋™์  SQL-->
                USER_PW = #{userPw},
            </if>
            <if test="userNm != null"> <!--๋™์  SQL-->
            USER_PW = #{userNm},
            </if>
            <if test="mobile != null"> <!--๋™์  SQL-->
            MOBILE = #{mobile},
            </if>
            MOD_DT = SYSDATE
        </set>
        WHERE USER_ID = #{userId}
    </update>

4) foreach

 <select id="getList4" resultMap="memberMap">
        SELECT * FROM MEMBER
        <where>
            <foreach item="item" index="index" collection="list" open="USER_ID IN (" close=")" separator=",">
                #{item}
            </foreach>
        </where>
    </select>

5) bind

USER_NM LIKE 'ํ‚ค์›Œ๋“œ%' : ์‚ฌ์šฉ์ž๋ช…์ด ํ‚ค์›Œ๋“œ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŒจํ„ด
USER_NM LIKE '%ํ‚ค์›Œ๋“œ' : ์‚ฌ์šฉ์ž๋ช…์ด ํ‚ค์›Œ๋“œ๋กœ ๋๋‚˜๋Š” ํŒจํ„ด
USER_NM LIKE '%ํ‚ค์›Œ๋“œ%' : ์‚ฌ์šฉ์ž๋ช…์ด ํ‚ค์›Œ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ํŒจํ„ด
_parameter : MemberMapper์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค*

<<select id="getList3" resultMap="memberMap">
        <bind name="P_userNm" value="'%' + _parameter.getUserNm() + '%'" />
<!--        '_parameter'์€ MemberMapper์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค.-->
        <bind name="P_mobile" value="'%' + _parameter.getMobile() + '%'" />
        SELECT * FROM MEMBER
        <where>
            <if test="userId != null">
                USER_ID = #{userId}
            </if>
            <if test="userNm != null">
                AND USER_NM LIKE #{P_userNm}
            </if>
            <if test="mobile != null">
                AND MOBILE LIKE #{P_mobile}
            </if>
        </where>
    </select>
    </select>

6) <![CDATA[]]

<select id = "getList5">
        SELECT * FROM MEMBER WHERE 
        <![CDATA[USER_NO > #{userNo}
        ]]>
</select>
profile
์•ˆ๋…•ํ•˜์„ธ์š”!

0๊ฐœ์˜ ๋Œ“๊ธ€