아래의 코드는 사용자 데이터를 추가하는 코드이며, Java Object와 RDB가 Mapping 되지 않기 때문에 각각의 쿼리 파라미터에 사용자 데이터를 직접 Set해서 DB에 저장한다.
public void insertUser(User user) {
String query = "INSERT INTO user (email, name, pw) VALUES (?, ?, ?)";
PreparedStatement preparedStmt = conn.prepareStatement(query);
preparedStmt.setString (1, user.getEmail());
preparedStmt.setString (2, user.getName());
preparedStmt.setString (3, user.getPW());
// execute the preparedstatement
preparedStmt.execute();
}
@Mapper
@Repository
public interface UserMapper {
insertUser(User user);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dam.blog.user.userMapper">
<insert id="insertUser" parameterType="user">
INSERT USER(
email, name, pw,
)VALUES(
#{email}, #{name}, #{pw}
)
</insert>
</mapper>
JPA는 Java 객체와 테이블을 매핑시키는 ORM 기술이므로 다음과 같이 Java 클래스에 매핑 정보를 넣어주어야 한다.
@Entity
@Table(name = "user")
@Getter
@Builder
@NoArgsConstructor(force = true)
@AllArgsConstructor
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String name;
private String pw;
}
그러면 다음과 같이 DB에 데이터를 저장하기 위한 Repository를 구현할 수 있다.
public interface UserRepository extends JpaRepository <User, Long> {
}
JpaRepository는 기본적인 CRUD를 제공하므로 UserRepository의 save만 호출해주면 데이터가 저장된다. 그리고 findById를 이용하면 해당 객체를 꺼낼 수 있다.
@Service
@RequiredArgsConstructor
@Transactional(readonly = true)
public class UserService {
private final UserRepository userRepository;
@Transactional
public User findUserAddUpdateName(Long id) {
User user = userRepository.findById(id);
user.setName("변경된 이름");
}
}
위의 예제에서는 id 값으로 사용자를 조회하고 갱신하는데, 별도의 Update 쿼리를 해주고 있지 않다. 이러한 이유는 JPA라는 ORM 기술에 의해 DB에서 조회한 데이터들이 객체로 연결되어 있고, 객체의 값을 수정하는 것은 DB의 값을 수정하는 것이기 때문이다.
해당 메소드가 종료될 때 Update 쿼리가 JPA 값의 변경 유무를 감지하는 Dirty Checking 이후에 나가게 된다.
1. 엔티티에 맞는 테이블 생성 + DB 생성이 편리
JPA는 설정에 따라 매핑된 객체를 바탕으로 테이블을 자동으로 만들어준다. 자동 생성되는 이름의 가독성이 떨어져서 그대로 사용하기에는 부족하지만, 직접 모든 DDL을 작성하는 것보다는 편리하다.
2. 객체 지향 중심의 개발
JPA는 객체를 이용하여 우리가 테이블에 매핑되는 클래스를 더욱 객체 지향적으로 개발할 수 있다.
3. 테스트 작성이 용이
Spring은 Repository 테스트를 위한 @DataJpaTest를 제공하고 있는데, @DataJpaTest를 이용하면 기본적으로 인메모리 데이터베이스(h2)로 연결이 된다. 그리고 테이블 생성 옵션을 주면 손쉽게 Repository 계층을 테스트할 수 있다.
4. 기본적인 CRUD 자동화
JPA는 테이블과 객체를 매핑시키는 기술이므로 기본적인 CRUD가 제공된다. MyBatis를 이용할 경우, 간단한 CRUD 쿼리들도 모두 작성해주어야 하지만 JPA를 이용하면 생산성을 높일 수 있다.
5. 복잡한 쿼리는 QueryDSL을 사용해 처리
MyBatis의 장점 중 하나는 직접 쿼리를 작성하므로 복잡한 쿼리를 다루기 유용하다는 것이다. 실제로 JPA를 이용하다보면 동적 쿼리를 처리하기가 매우 어렵다. 하지만 QueryDSL 이라는 오픈소스를 사용하면 문제를 해결할 수 있다. QueryDSL을 이용하면 자바 언어로 매우 직관적인 쿼리를 작성할 수 있다.
@Repository
@RequiredArgsConstructor
public class QuizRepositoryImpl {
private final JPAQueryFactory query;
@Override
public User search(final String email) {
final QUser qUser = QUser.user;
final User user = query.selectFrom(qUser)
.where(qUser.email.equalsIgnoreCase(email))
.fetch();
return user;
}
}