MyBatis를 사용하여 프로젝트를 진행중인데 다음과 같은 문제를 만났으며 이와 관련되어 고민을 하고 있어요.
insert()를 성공하여 db에 값을 저장하였고, PK를 지정해두었는데, 왜 반환값이 항상 1일까?
insert()를 실행하면 반환해야 할 값이 무엇일까?
두 고민을 해결하기 위해 MyBatis 대한 간단한 설명과 INSERT 작업, 속성 그리고 옵션에 대해 공부하려고 해요.
MyBatis는 Java 프로그래밍 언어를 기반으로 한 데이터베이스 연동을 위한 오픈 소스 ORM(Object-Relational Mapping) 프레임워크에요. MyBatis SQL 기반의 데이터베이스 액세스를 단순화하고, 개발자가 SQL 쿼리를 직접 작성하고 관리할 수 있게 해주는 도구입니다. 또한 데이터베이스 연동 계층을 자동으로 생성하거나 복잡한 매핑을 수행하지 않으므로 개발자에게 높은 유연성을 제공합니다.
MyBatis는 전통적인 ORM 프레임워크와 다른 점이 있습니다. 대표적인 ORM 프레임워크로는 Hibernate와 Java Persistence API (JPA)가 있습니다. MyBatis의 주요 특징은 다음과 같아요.
MyBatis는 SQL을 중심으로 하는 간단한 설정과 유연한 SQL 작성을 통해 데이터베이스 액세스를 효율적으로 수행할 수 있으며, 많은 Java 어플리케이션에서 사용되고 있습니다.
Select
Insert
Update
delete
이제 알 수 있어요. 내가 설정한 타입과 별개로 Mybatis 자체에서 insert가 성공하면 1을 반환해줘요.
Mybatis를 사용하여 데이터베이스에 새로운 레코드를 추가하려면 SQL 매퍼(XML 파일)에 해당 INSERT 쿼리를 정의해야 해요. 아래는 간단한 예제에요
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO users (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
위의 예제에서 save
는 매퍼에서 사용할 고유한 ID이며, parameterType
은 매개변수로 받을 객체의 타입이에요. SQL 쿼리는 <insert>
요소 안에 정의되며, #{}
를 사용하여 파라미터 값을 바인딩해야 해요.
데이터베이스에서 자동으로 생성된 키 (예: Primary Key)를 처리하려면 SELECTKey
를 사용할 수도 있어요. 아래는 자동 생성된 키를 처리하는 예제에요
<insert id="save" parameterType="User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO users (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
위의 예제에서 selectKey
요소를 사용하여 keyProperty
에 자동 생성된 키를 설정하고 resultType
으로 반환 타입을 설정해요. order
속성은 BEFORE
또는 AFTER
중 하나를 선택하여 자동 생성된 키를 언제 설정할지 지정할 수 있어요. BEFORE
로 설정하면 INSERT 쿼리 실행 전에, AFTER
로 설정하면 INSERT 쿼리 실행 후에 자동 생성된 키를 설정 반환해줘요.
PK가 자동생성 되기는 하지만 모두 삽입된 레코드의 id를 반납하는 것이 아니라 MyBatis의 insert가 성공되었다고 여전히 '1'을 반납했어요.
그래서 레코드를 삽입한 후의 값을 가져오는 방법을 선택했어요. 다음과 같은 순서를 생각했어요.
제가 작성한 코드는 다음과 같아요.
public int signUp(SignUpRequest request) {
checkUserValidity(request);
String encryptedPassword = passwordEncoder.encode(request.getPassword());
User user = request.toEntity(encryptedPassword);
// 포인트 적립, 유저 Role 변경 등의 작업...
userMapper.save(user);
return user.getId();
}
드디어 원하던 결과가 나와요 !!!
useGeneratedKeys
속성useGeneratedKeys
속성을 사용하면 데이터베이스가 자동으로 생성한 키(primary key)를 사용하여 자동으로 생성된 키를 처리할 수 있어요. 이 속성을 설정하면 자동 생성된 키를 사용하도록 데이터베이스 드라이버에 지시하게 되요. 아래는 useGeneratedKeys
를 사용하는 예제에요:
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO users (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
useGeneratedKeys
를 true
로 설정하면 keyProperty
에 지정된 속성에 자동 생성된 키가 할당됩니다.
keyProperty
및 keyColumn
속성keyProperty
속성은 자동 생성된 키를 매핑할 객체의 속성 이름을 지정해줘요. keyColumn
은 데이터베이스에서 자동 생성된 키의 열 이름을 지정하게 되요. 이렇게 데이터베이스와 자바 객체 간의 매핑을 설정하는 거에요.
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id" keyColumn="user_id">
INSERT INTO users (username, email, age)
VALUES (#{username}, #{email}, #{age})
</insert>
위의 예제에서 keyProperty
는 자바 객체(User)의 속성 이름을, keyColumn
은 데이터베이스에서 사용하는 열 이름을 지정하면 되요.
INSERT 작업의 반환 타입을 선택하는 것은 어떻게 하는 것이 좋을까요?
두 가지 상황을 가정해 보았어요.
이런 경우 리턴 타입을 void로 해도 상관 없을 것 같아요. 회원가입한 유저의 id를 사용할 필요가 없으면 굳이 id를 반환할 필요가 없어요.
예를 들어, 계좌를 생성하면 기존 유저가 갖고 있는 필드 account_id에 생성된 계좌 id를 넣어야 한다고 가정해봐요. 그렇다면 계좌를 생성하면서 자동 증가한 id를 유저의 account_id 필드 값에 넣어주어야 해요. 이런 경우는 return type을 int 혹은 long 으로 해두어 가지고 와야 해요.
즉, 이에 대한 결론은 없으며 요구사항에 맞게 선택해야 해요.
이것으로 저의 고민을 마칠게요.
감사합니다 !! 👋
mybatis에서 selectKey 사용법
mybatis 공식문서
Get the id of last inserted record in mybatis