학습 04.24

한강섭·2025년 4월 24일
0

학습 & 숙제

목록 보기
74/103
post-thumbnail

🏗️ Spring Model과 MyBatis 정리


📊 Model - Enterprise Application의 일반적인 Model 계층 구조

🔹 Service Layer

  • High-level의 기능을 외부(클라이언트)에게 노출시킴
  • Use-case, 비즈니스 로직이 구현되는 곳
  • 업무의 단위로 Transaction 처리 필요

🔹 Data Access Layer (Repository)

  • 애플리케이션에서 데이터 저장소(RDB 등)에 접근하기 위한 계층
  • 단일 쿼리 단위

💬 모델을 왜 이렇게 복잡하게 구현해야 하나요? ㅠㅠ
➡️ 변경에 자유롭게 만들기 위해! (유지보수)

🚨 기존 Model의 문제점

기술 별로 단계적인 작업 필요 → cross cutting concern 발생
1. SQLException을 잡긴 하고 던지긴 했는데 귀찮다..
2. 비즈니스 로직이 한줄 밖에 없고 다른 것들은 다 횡단관심사네
3. Connection, PreparedStatement 등 리소스 관리 너무 귀찮다..

🌱 Model을 위한 Spring

  • 사실 Spring JDBC가 있긴 한데 MyBatis, JPA가 너무 쎄다..
  • MyBatis Spring, Spring Data JPA로 Spring과 결합!
  • @Transactional: DB 접근 기술과 무관한 선언적 Transaction 처리 (PSA)
  • 리소스 자동 관리 - 사용 후 자동 close
  • 범용적인 예외 처리: DB마다의 차이를 Spring이 흡수, 별도로 분석할 필요가 없음

🔄 MyBatis

  • 내부적으로 PreparedStatement 사용
  • ResultSet 내용을 DTO에 저장하기 위한 코드가 필요 없음
  • 전통적으로 XML에서 SQL을 관리 (@ 사용 기능 추가)

🔹 MyBatis 선택 이유

  • 기본적으로 PreparedStatement를 사용해서 SQL Injection을 방지할 수 있다
  • 동적 쿼리가 강력함

🔹 구조

MyBatis 구조

➡️ 우리가 작성해야 하는 건 mapper.xml!

🔹 Spring - MyBatis 연동

  • Dao interface
  • Connection에 대한 관리는 Spring Framework가 담당 - 코드적으로 Connection을 전달하지 않음
  • DB 관련 예외는 RuntimeException 계열로 전달
  • Dao는 mapper로써 runtime에 구현체에 대한 proxy 생성
  • <mapper> : mapper 파일의 root element
  • <insert> : 처리하려는 작업의 성격에 따라 insert, update, delete, select 태그
  • @Configuration
  • @MapperScan으로 @Mapper 검색

⚠️ insert나 update Test 시에 조심!

@Transactional // test에서는 자동 rollback

📝 Mapper 작성

  • parameterType은 메서드에서 추정 가능하므로 생략 가능

🔹 SQL 내에서의 파라미터 표기법

  • #{parameterName} → 결과적으로 PreparedStatement의 ? 로 대체

🔹 조회 결과 매핑

  • 일반적으로 컬럼/변수 이름에 DB는 스네이크 표기법, 프로그래밍은 CamelCase 사용한다.
  • 그래서 camelCase true를 통해서 하긴 하지만 문제가 있긴 있음
  • resultMap을 이용해서 결과를 매핑!

🔗 Join 결과 처리

🔹 Has-one 관계 처리

association 활용!

<resultMap type="Address" id="addressMemberMap" extends="addressMap">
    <association property="member" column="mno" resultMap="com.ssafy.live.model.dao.MemberDao.memberMap"></association>
</resultMap>

🔹 Has-many 관계의 처리

  • collection : resultMap의 하위 태그
  • property : 연동할 객체의 속성 명
  • column : join 관계에서 사용된 컬럼 명
  • ofType : List에 담길 N에 해당하는 객체의 타입
  • resultMap : 다른 resultMap을 재사용할 때 (다른 mapper를 사용할 경우 namespace 포함)
  • columnPrefix : 두 테이블의 컬럼 이름이 동일해서 구별해야 할 경우 prefix 적용
  • notNullColumn : 해당 값이 null일 경우 collection에 추가하지 않음
<resultMap type="Member" id="memberAddressMap" extends="memberMap">
    <collection property="addresses" column="mno" ofType="Address" notNullColumn="ano"
        resultMap="com.ssafy.live.model.dao.AddressDao.addressMap"></collection>
</resultMap>

⚠️ notNullColumn="ano"를 안해줄 경우 null 값으로 채워진 list가 한번은 도착해서 문제가 된다!

profile
기록하고 공유하는 개발자

0개의 댓글