day82 πŸŒ•

μž₯λ―ΈΒ·2022λ…„ 9μ›” 4일
0

였늘의 μ„±κ³Ό

λͺ©λ‘ 보기
82/129

μŠ€ν”„λ§ DB 2편 - 데이터 μ ‘κ·Ό ν™œμš© 기술 μ„Ήμ…˜ 4 μˆ˜κ°•

μ„Ήμ…˜ 4. 데이터 μ ‘κ·Ό 기술 - MyBatis μˆ˜κ°• μ™„λ£Œ!!

MyBatis μ†Œκ°œ

MyBatisλŠ” JdbcTemplate보닀 더 λ§Žμ€ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” SQL Mapper이닀.
MyBatisλŠ” SQL을 XML에 νŽΈλ¦¬ν•˜κ²Œ μž‘μ„±ν•  수 있고, 동적 쿼리λ₯Ό 맀우 νŽΈλ¦¬ν•˜κ²Œ μž‘μ„±ν•  수 μžˆλ‹€λŠ” μž₯점이 μžˆλ‹€.

μ„€μ •μ˜ μž₯단점
JdbcTemplate은 μŠ€ν”„λ§μ— λ‚΄μž₯된 κΈ°λŠ₯이라 λ³„λ„μ˜ 섀정없이 μ‚¬μš©ν•  수 μžˆλ‹€. 반면 MyBatisλŠ” μ•½κ°„μ˜ 섀정이 ν•„μš”ν•˜λ‹€.

정리
ν”„λ‘œμ νŠΈμ—μ„œ 동적 쿼리와 λ³΅μž‘ν•œ 쿼리가 λ§Žλ‹€λ©΄ MyBatisλ₯Ό μ‚¬μš©ν•˜κ³ , λ‹¨μˆœν•œ 쿼리듀이 많으면 JdbcTemplate을 μ‚¬μš©ν•˜λ©΄ λœλ‹€. λ¬Όλ‘  λ‘˜μ„ ν•¨κ»˜ μ‚¬μš©ν•΄λ„ λœλ‹€.

μ„€μ •

  • mybatis.type-aliases-package: MyBatisμ—μ„œ νƒ€μž… 정보λ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” νŒ¨ν‚€μ§€ 이름을 적어야 ν•˜λŠ”λ°, 여기에 λͺ…μ‹œν•˜λ©΄ νŒ¨ν‚€μ§€ 이름을 μƒλž΅ν•  수 μžˆλ‹€.

  • mybatis.configuration.map-underscore-to-camel-case: JdbcTemplate의 BeanPropertyRowMapper처럼 언더바λ₯Ό 카멜 μΌ€μ΄μŠ€λ‘œ μžλ™ λ³€κ²½ν•΄μ£ΌλŠ” κΈ°λŠ₯을 ν™œμ„±ν™”ν•œλ‹€.

μ°Έκ³  - κ΄€λ‘€μ˜ 뢈일치

μžλ°” κ°μ²΄μ—λŠ” 주둜 카멜 μΌ€μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜κ³ , κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œλŠ” 주둜 μŠ€λ„€μ΄ν¬ μΌ€μ΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€.
μ΄λ ‡κ²Œ κ΄€λ‘€λ‘œ 많이 μ‚¬μš©ν•˜λ‹€ λ³΄λ‹ˆ map-underscore-to-camel-case κΈ°λŠ₯을 ν™œμ„±ν™”ν•˜λ©΄ μŠ€λ„€μ΄ν¬ μΌ€μ΄μŠ€λ₯Ό 카멜 μΌ€μ΄μŠ€λ‘œ μžλ™ λ³€ν™˜ν•΄μ€€λ‹€. λ”°λΌμ„œ DBμ—μ„œ select item_name으둜 μ‘°νšŒν•΄λ„ 객체의 itemName(setItemName()) 속성에 값이 정상 μž…λ ₯λœλ‹€.
ν•΄λ‹Ή μ˜΅μ…˜μ„ 켜면 μŠ€λ„€μ΄ν¬ μΌ€μ΄μŠ€λŠ” μžλ™μœΌλ‘œ ν•΄κ²°λ˜κ³ , 컬럼 이름과 객체 이름이 μ™„μ „νžˆ λ‹€λ₯Έ κ²½μš°μ—λŠ” 쑰회 SQLμ—μ„œ 별칭(as)을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.


<insert id="save" useGeneratedKeys="true" keyProperty="id">
	insert into item (item_name, price, quantity)
	values (#{itemName}, #{price}, #{quantity})
</insert>
  • InsertSQL은 <insert>λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  • νŒŒλΌλ―Έν„°λŠ” #{} 문법을 μ‚¬μš©ν•˜λ©΄ λœλ‹€. 그리고 λ§€νΌμ—μ„œ λ„˜κΈ΄ 객체의 ν”„λ‘œνΌν‹° 이름을 적어주면 λœλ‹€.
  • #{} 문법을 μ‚¬μš©ν•˜λ©΄ PreparedStatementλ₯Ό μ‚¬μš©ν•œλ‹€. JDBC의 ?λ₯Ό μΉ˜ν™˜ν•œλ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€.

void update(@Param("id") Long id, @Param("updateParam") ItemUpdateDto updateParam);

<update id="update">
	update item
	set item_name=#{updateParam.itemName},
	price=#{updateParam.price},
	quantity=#{updateParam.quantity}
	where id = #{id}
</update>
  • UpdateSQL은 <update>λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  • νŒŒλΌλ―Έν„°κ°€ 1개만 있으면 @Param을 μ§€μ •ν•˜μ§€ μ•Šμ•„λ„ λ˜μ§€λ§Œ, νŒŒλΌλ―Έν„°κ°€ 2개 이상이면 @Param으둜 이름을 μ§€μ •ν•΄μ„œ νŒŒλΌλ―Έν„°λ₯Ό ꡬ뢄해야 ν•œλ‹€.

<select id="findById" resultType="Item">
	select id, item_name, price, quantity
	from item
	where id = #{id}
</select>
  • Select SQL은 <select>λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  • resultType은 λ°˜ν™˜ νƒ€μž…μ„ λͺ…μ‹œν•˜λ©΄ λœλ‹€. μ—¬κΈ°μ„œλŠ” κ²°κ³Όλ₯Ό Item 객체에 λ§€ν•‘ν•œλ‹€. SELECT SQL의 κ²°κ³Όλ₯Ό νŽΈλ¦¬ν•˜κ²Œ λ°”λ‘œ 객체둜 λ³€ν™˜ν•΄μ€€λ‹€.
  • μžλ°” μ½”λ“œμ—μ„œ λ°˜ν™˜ 객체가 ν•˜λ‚˜λ©΄ Item, Optional<Item>κ³Ό 같이 μ‚¬μš©ν•˜λ©΄ 되고, λ°˜ν™˜ 객체가 ν•˜λ‚˜ 이상이면 μ»¬λ ‰μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λœλ‹€. 주둜 Listλ₯Ό μ‚¬μš©ν•œλ‹€.

<select id="findAll" resultType="Item">
	select id, item_name, price, quantity
	from item
	<where>
		<if test="itemName != null and itemName != ''">
			and item_name like concat('%',#{itemName},'%')
		</if>
		<if test="maxPrice != null">
			and price &lt;= #{maxPrice}
		</if>
	</where>
</select>
  • MyBatisλŠ” <where>, <if> 같은 동적 쿼리 문법을 톡해 νŽΈλ¦¬ν•œ 동적 쿼리λ₯Ό μ§€μ›ν•œλ‹€.
  • <if>λŠ” ν•΄λ‹Ή 쑰건이 λ§Œμ‘±ν•˜λ©΄ ꡬ문을 μΆ”κ°€ν•œλ‹€.
  • <where>λŠ” μ μ ˆν•˜κ²Œ where λ¬Έμž₯을 λ§Œλ“€μ–΄μ€€λ‹€.
    • μ˜ˆμ œμ—μ„œ <if>κ°€ λͺ¨λ‘ μ‹€νŒ¨ν•˜κ²Œ 되면 SQL whereλ₯Ό λ§Œλ“€μ§€ μ•ŠλŠ”λ‹€.
    • μ˜ˆμ œμ—μ„œ <if>κ°€ ν•˜λ‚˜λΌλ„ μ„±κ³΅ν•˜λ©΄ 처음 λ‚˜νƒ€λ‚˜λŠ” andλ₯Ό where둜 λ³€ν™˜ν•œλ‹€.

MyBatis μŠ€ν”„λ§ 연동 λͺ¨λ“ˆ μ„€μ • 원리

MyBatis μŠ€ν”„λ§ 연동 λͺ¨λ“ˆ μ„€μ • 원리

  1. μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‘œλ”© μ‹œμ μ— MyBatis μŠ€ν”„λ§ 연동 λͺ¨λ“ˆμ€ @Mapperκ°€ 뢙은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‘°μ‚¬ν•œλ‹€.

  2. ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€κ°€ 발견되면 동적 ν”„λ‘μ‹œ κΈ°μˆ μ„ μ‚¬μš©ν•΄μ„œ ItemMapper μΈν„°νŽ˜μ΄μŠ€μ˜ κ΅¬ν˜„μ²΄λ₯Ό λ§Œλ“ λ‹€.

  3. μƒμ„±λœ κ΅¬ν˜„μ²΄λ₯Ό μŠ€ν”„λ§ 빈으둜 λ“±λ‘ν•œλ‹€.

맀퍼 κ΅¬ν˜„μ²΄

MyBatis μŠ€ν”„λ§ 연동 λͺ¨λ“ˆμ΄ λ§Œλ“€μ–΄μ£ΌλŠ” ItemMapper의 κ΅¬ν˜„μ²΄ 덕뢄에 μΈν„°νŽ˜μ΄μŠ€λ§ŒμœΌλ‘œ νŽΈλ¦¬ν•˜κ²Œ XML의 데이터λ₯Ό μ°Ύμ•„ ν˜ΈμΆœν•  수 있게 됐닀.
맀퍼 κ΅¬ν˜„μ²΄λŠ” μ˜ˆμ™Έ λ³€ν™˜κΉŒμ§€ μ²˜λ¦¬ν•΄μ€€λ‹€. MyBatisμ—μ„œ λ°œμƒν•œ μ˜ˆμ™Έλ₯Ό μŠ€ν”„λ§ μ˜ˆμ™Έ 좔상화인 DataAccessException에 맞게 λ³€ν™˜ν•΄μ„œ λ°˜ν™˜ν•œλ‹€.

λ¬Έμžμ—΄ λŒ€μ²΄(String Substitution)

#{} 문법은 ?λ₯Ό λ„£κ³  νŒŒλΌλ―Έν„°λ₯Ό λ°”μΈλ”©ν•˜λŠ” PreparedStatementλ₯Ό μ‚¬μš©ν•œλ‹€.
νŒŒλΌλ―Έν„° 바인딩이 μ•„λ‹ˆλΌ 문자 κ·ΈλŒ€λ‘œλ₯Ό μ²˜λ¦¬ν•˜κ³  싢을 땐 ${}λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. λ‹€λ§Œ ${}λ₯Ό μ‚¬μš©ν•˜λ©΄ SQL Injection 곡격을 λ‹Ήν•  수 있기 λ•Œλ¬Έμ— 가급적 μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€.

μž¬μ‚¬μš© κ°€λŠ₯ν•œ SQL 쑰각

<sql>을 μ‚¬μš©ν•˜λ©΄ SQL μ½”λ“œλ₯Ό μž¬μ‚¬μš©ν•  수 μžˆλ‹€.

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<select id="selectUsers" resultType="map">
	select
		<include refid="userColumns"><property name="alias" value="t1"/></include>,
		<include refid="userColumns"><property name="alias" value="t2"/></include>
	from some_table t1
		cross join some_table t2
</select>

<include>λ₯Ό 톡해 <sql> 쑰각을 μ°Ύμ•„μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

Result Maps

κ²°κ³Όλ₯Ό 맀핑할 λ•Œ ν…Œμ΄λΈ”μ€ user_idμ΄μ§€λ§Œ κ°μ²΄λŠ” id일 λ•Œ, 컬럼λͺ…κ³Ό 객체의 ν”„λ‘œνΌν‹°λͺ…이 λ‹€λ₯΄λ‹€. 이 λ•Œ 별칭(as)을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.
ν•˜μ§€λ§Œ 별칭을 μ‚¬μš©ν•˜μ§€ μ•Šκ³ λ„ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλŠ”λ°, λ°”λ‘œ λ‹€μŒκ³Ό 같이 resultMap을 μ„ μ–Έν•˜λ©΄ λœλ‹€.

<resultMap id="userResultMap" type="User">
	<id property="id" column="user_id" />
	<result property="username" column="username"/>
	<result property="password" column="password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
	select user_id, user_name, hashed_password
	from some_table
	where id = #{id}
</select>

인쀀, 지원이 λ§Œλ‚˜μ„œ ν† ν”½ λ°œν‘œ 및 토이 ν”„λ‘œμ νŠΈ κ΄€λ ¨ νšŒμ˜ν•˜κΈ°

+) 22. 09. 05. 기둝 μΆ”κ°€

λ‚΄κ°€ λ°œν‘œν•œ λ‚΄μš©μ€ μŠ€ν”„λ§ νŠΈλžœμž­μ…˜!! μ›λž˜ 전에 DB νŠΈλžœμž­μ…˜ λ°œν‘œν•˜κ³  κ·Έ λ‹€μŒμ— λ°”λ‘œ μ΄μ–΄μ„œ μŠ€ν”„λ§ νŠΈλžœμž­μ…˜μ— λŒ€ν•΄ λ°œν‘œν•˜λ € ν–ˆμœΌλ‚˜ λ‚΄κ°€ μŠ€ν”„λ§μ— λŒ€ν•΄ 정말 λ¬΄μ§€ν•΄μ„œ... μ΄λ²ˆμ— μΈν”„λŸ° κ°•μ˜λ‘œ μŠ€ν”„λ§ νŠΈλžœμž­μ…˜μ— λŒ€ν•΄ μ’€ 배운 뒀에 λ°œν‘œν•˜κ²Œ 됐닀.

κ°•μ˜ λ“€μœΌλ©΄μ„œ κ³΅λΆ€ν–ˆμ—ˆλ˜ λ‚΄μš©μœΌλ‘œ μ§„ν–‰ν–ˆλ‹€. pages둜 λ§Œλ“  간단 λ°œν‘œ 자료 λ³΄μ—¬μ£Όλ©΄μ„œ 전에 짰던 μ½”λ“œλ„ 같이 보여주고. 덕뢄에 λ‚˜ 혼자 두 μ‹œκ°„μ€ μž‘μ•„ λ¨Ήμ—ˆμ§€λ§Œ... κ·Έλž˜λ„ 이왕 λ°œν‘œν•˜λŠ” κ±° νŠΈλžœμž­μ…˜μ— λŒ€ν•΄ A to Z λ‹€ μ•Œλ €μ£Όκ³  μ‹Άμ–΄μ„œ! λ‚΄μš©μ„ μ’€ 길게 μ§°λ‹€.

κ·Έλž˜μ„œ κ·ΈλŸ°μ§€ ν”Όλ“œλ°±λ„ μ’‹κ²Œ λ°›μ•˜λ‹€! ν•˜μ§€λ§Œ λ‚΄κ°€ 생각해도 μ’€... λ£¨μ¦ˆν•΄μ§€λŠ” 감이 μ—†μ§€μ•Šμ•„ μžˆμ—ˆμŒ. λ‹€μŒμ—” μ’€ 더 λ‚˜μ€ λ°œν‘œλ₯Ό λͺ©ν‘œλ‘œ... λ£¨μ¦ˆν•΄μ§€μ§€ μ•Šκ²Œ ꡬ성을 잘 μ§œλ΄μ•Όκ² λ‹€.

인쀀이가 λ°œν‘œν•œ λ‚΄μš©μ€ IPv4와 IPv6. 이건 전에 λ„€νŠΈμ›Œν¬ IP에 λŒ€ν•΄ κ³΅λΆ€ν–ˆμ„ λ•Œ μŠ€μ³μ§€λ‚˜κ°€λ“― λ°°μ› λ˜ 건데... μ˜€λžœλ§Œμ— λ‹€μ‹œ λ°°μš°λ‹ˆ λ³΅μŠ΅ν•˜λŠ” λŠλ‚Œμ΄λΌ μ’‹μ•˜λ‹€. 근데 사싀 μ„œλΈŒλ„· λ§ˆμŠ€ν¬μ— λŒ€ν•΄μ„ ... 아직 잘 이해가 μ•ˆ 감. λ°œν‘œ λ“£λŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” 이해가 잘 μ•ˆ 됐닀. λ‚΄κ°€ 직접 곡뢀해봐야 μ•Œ λ“―...

지원이가 λ°œν‘œν•œ λ‚΄μš©μ€ μžλ°” 컴파일 κ³Όμ •. 이건 전에 인쀀이가 λ°œν‘œν–ˆμ—ˆλ˜ 건데 이 주제 μ—­μ‹œ μ˜€λžœλ§Œμ— λ“€μœΌλ‹ˆ μƒˆλ‘œμ› λ‹€. μ—­μ‹œ... μ„ μƒλ‹˜λ‹΅κ²Œ ν•΅μ‹¬λ§Œ 쏙쏙 μ•Œλ €μ€˜μ„œ μ’‹μ•˜μŒ. κ°„κ²°ν–ˆμ§€λ§Œ 듀을 건 λ‹€ 듀은 λŠλ‚Œ...!

μ–΄μ¨Œλ“  이번 λ°œν‘œλŠ” 양이 λ§Žμ•„ μ€€λΉ„ν•˜κΈ° νž˜λ“€μ—ˆμ§€λ§Œ κ·Έλž˜λ„ 그만큼 λΏŒλ“―ν•˜λ‹€. λ‹€λ“€ 잘 이해해 μ€€ 것 κ°™μ•„ 기뻐...

토이 ν”„λ‘œμ νŠΈ κ΄€λ ¨ νšŒμ˜λ‘œλŠ” μ£Όμš” κΈ°λŠ₯λ“€μ΄λž‘, λͺ…μ„Έμ„œ μ–΄λ–»κ²Œ 지지에 λŒ€ν•΄ μ–˜κΈ° λ‚˜λˆ΄λ‹€. 그리고 μŠ€ν„°λ””λ£Έ μ‹œκ°„ λ‹€ λΌμ„œ 저녁 먹으러 감...^^

회의 λλ‚˜κ³  먹은 λˆκ°€μŠ€μΈλ° μ’λ§›μ΄μ—ˆλ‹€. μΉ˜μ¦ˆκ°€... 짱 λΆ€λ“œλŸ¬μ›Œ! λ§›μžˆμ—ˆλ‹€! 또 λ¨Ήκ³  μ‹Άλ‹€!

profile
김뉴비

0개의 λŒ“κΈ€

κ΄€λ ¨ μ±„μš© 정보