포스트

(Day 89)

PDF

MyBatis

1
2
3
4
5
6
  @Override
  public void add(Member member) { //매번 세션 받아야 한다.. 커넥션을 공유하지 않도록 하기 위함이다. 내부적으로 DB커넥션풀을 쓴다. mybatis-config.xml 을 보면 <dataSource type="POOLED"> 라는 부분이 있다. 같은 스레드는 같은 커넥션을 계속 쓴다는 것이다. 이 말은 트랜잭션을 구현하기 위해 커넥션을 공유하는 방법이 이미 적용되어 있다는 것이다. (물론 그럴 일은 없겠지만 이 프로그램을 단 한사람만 사용 하는 경우라면 클라를 구분하기 위해 매번 세션을 받지 않아도 된다.) 커밋/롤백 이전까지 같은 클라는 openSession() 에서 받은 같은 세션을 쓸 것이다.
    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
      sqlSession.insert("MemberDao.add", member);
    } //catch 하지 않아도 된다. 예외 발생시 컨트롤러가 받고 예외페이지를 클라에게 줄 것이다. try를 쓰는 것은 try-with-resource 문법을 써서 자원 할당/해제를 편하게 쓰려는 것이다.
  }

SqlSession, Connection, Transaction

Transaction 을 시작하지 않았을 때

트랜잭션을 시작하지 않았을 때

  • openSession() 메서드를 호출해 DataSource에서 Connection 을 받을 것이다.
  • SqlSession은 각각의 Connection을 받을 것이다.
  • SqlSession이 close() 로 반환하면, 그 세션이 가지고 있던 커넥션이 DataSource에 반납될 것이다.

트랜잭션을 시작했을 때

  • SqlSession이 close() 로 반환해도, 그 세션이 가지고 있던 커넥션은 반납되지 않는다.!
  • 해당 스레드의 작업이 종료되었을 때, 그 세션이 가지고 있던 커넥션을 반납한다.

가능하면 MyBatis 애너테이션 문법 사용을 줄이자

원래 목적이 sql문과 java코드를 분리하는 것이었으므로..

동적 SQL (Dynamic SQL)

MyBatis에서도 조건에 따라 SQL문을 다이나믹하게 구성할 수 있도록 지원한다. MyBatis는 JSTL의 영향을 많이 받았다고 한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?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">

<!--하나의 DAO를 위해서 매퍼를 작성하고, 그 DAO의 인터페이스 이름과 일치시켜 어떤 DAO를 위한 것인지 바로 알아볼 수 있게 하자
    그리고 id를 메서드 이름과 일치시켜 그 DAO의 어떤 메서드가 해당 SQL문을 사용하는지 바로 알 수 있게 하자.-->
<mapper namespace="MemberDao">
  <insert id="add" parameterType="bitcamp.myapp.vo.Member">
    insert into members(email,name,password,photo)
    values(#{email}, #{name}, sha2(#{password},256),#{photo})

  </insert>

  <delete id="delete" parameterType="int">
    delete from members where member_no=#{value}
    <!--원시값(오토박싱), 스트링은 단 한개의 파라미터가 오는 경우 이름 마음대로 적어도 됨
        일반적으로는 value 라고 적음. number라고 적는 경우도 있음-->
  </delete>

  <select id="findAll" resultType="bitcamp.myapp.vo.Member">
    SELECT
    member_no as no,
    email,
    name,
    photo,
    created_date as createdDate
    FROM
    members
  </select>

  <select id="findBy" resultType="bitcamp.myapp.vo.Member" parameterType="int">
    SELECT member_no as no,
    email,
    name,
    photo,
    created_date as createdDate
    FROM members
    where member_no=#{no}
  </select>


  <update id="update" parameterType="bitcamp.myapp.vo.Member">
    UPDATE members
    SET
    email=#{email},
    name=#{name},
    photo=#{photo}
    <if test="password != ''"> <!-- Dynamic SQL !! -->
      , password=sha2(#{password}, 256)
    </if>
    WHERE member_no=#{no}
  </update>

  <select id="findByEmailAndPassword" resultType="bitcamp.myapp.vo.Member" parameterType="int">
    SELECT member_no as no,
    email,
    name,
    created_date as createdDate
    FROM members
    WHERE
    email=#{email} AND password=sha2(#{password},256)


  </select>
iu
</mapper>

resultMap을 설정하는 이유

VO 필드와 DB 컬럼 이름의 차이를 해소하기 위해 별명을 따로 부여할 필요가 없음.

한번 resultMap을 잡아주면 type을 설정하기 위해 매번 FQName을 작성하지 않아도 됨

  • FQName이 변경되면 resultMap 에서 한번만 변경해주면 됨
  • 만약 resultMap에 담지 않았더라면 모든 코드에서 다 변경해줘야 함

더 편하게 하는 방법

mybatis-config.xml에서 패키지 내 모든 클래스에 대해서 별명을 자동부여할 수 있다.

1
2
3
  <typeAliases>
    <package name="bitcamp.myapp.vo"/>
  </typeAliases>

이렇게하면 FQName을 적지 않고 클래스 이름만 적어도 자동 부여된 별명으로 잡혀서 클래스를 잡는다. 동일한 이름을 갖는 클래스가 많다면 주의해야 한다. 다만 그 중에서 한 패키지만 쓰는 경우라면 이 설정으로 유지보수를 더 편하게 할 수 있을 것이다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.