[데이터베이스] SQL Mapper, ORM 정리 + MyBatis, JPA, Spring Data JPA, Hibernate
0. 영속성 (Persistence)
- 데이터들이 프로그램이 종료되어도 사라지지 않고 어떤 곳에 저장되는 개념
- 자바에서 이런 영속성을 지원해주는 도구가 JDBC
- 하지만, JDBC는 개발자가 SQL문을 직접 맵핑해야하는 번거로움이 있음.
- SQL Mapper, ORM은 개발자가 직접 맵핑하지 않도록 도와주는 Persistence Framework
- Persistence Framework : 데이터베이스와의 연동되는 시스템을 빠르게 개발하고 안정적인 구동을 보장해주는 프레임워크
1. SQL Mapper
- 객체 (Object)와 SQL를 Mapping하여 데이터를 객체화하는 기술.
- DB마다 SQL문이 다르므로 DBMS에 종속적임.
- 종류 : MyBatis
2. ORM (Object-relational Mapping)
- Object와 테이블을 Mapping해주는 기술.
- SQL 문이 아닌 관계형데이터베이스의 데이터에 직접 맵핑하기 때문에 SQL문을 작성할 필요가 없음.
- 해당 데이터베이스 객체와 직접 맵핑하기 때문에 필요한 SQL문을 알아서 만들어줌.
- 그래서 DBMS에 종속적이지 않음. 그래서 개발자는 비즈니스 로직에 집중할 수 있음.
- 또한 유지보수 및 재사용이 용이함.
- 종류 : JPA
3. SQL Mapper - MyBatis
- 쿼리 기반 웹 애플리케이션을 개발할 때 가장 많이 사용되는 SQL Mapper 프레임워크.
- SQL 문을 XML 파일에 작성하기 때문에, SQL의 변환이 자유로움.
- 우리나라의 시장은 대부분이 SI 또는 금융이기 때문에 비지니스가 매우 복잡하고, 안정성과 속도를 중요시하기 때문에 SQL문을 직접 작성하는 Mybatis을 많이 사용함.
<장점>
- JDBC를 직접 이용할 경우, 개발자가 반복적으로 작성해야할 코드가 많고, 서비스 로직 코드와 쿼리 분리가 어려움.
- 또한 커넥션 풀의 설정 등 개발자가 신경써야할 부분이 많다.
- 하지만 마이바티스는 JDBC를 통한 작업을 캡슐화하고, 일반 SQL 쿼리, 저장 프로 시저 및 고급 매핑을 지원하여 JDBC의 코드, 매개변수의 중복작업을 제거해줌.
- Java, C 등 어떤 프로그래밍 언어든 사용이 가능.
<단점>
- SQL을 개발자가 직접 작성해야함.
- 테이블이 변경되고 DTO가 변경될 때마다 매핑에 대한 부분을 다시 수정해야하는 번거로움이 존재.
- 위와 같은 이유로 어플리케이션과 데이터베이스간의 설계에 대한 부분을 수정해야하는 경우 많은 설정이 바뀌어야 한다.
- 런타임을 해야 오류를 확인할 수 있다.
4. ORM - JPA
- 자바 ORM 기술에 대한 API 표준 명세서로, 자바에서 제공하는 API.
- 즉, ORM을 사용하기 위한 표준 인터페이스를 모아둔 것
- 특정 기능을 하는 라이브러리가 아닌 인터페이스
- EntityManager를 통해 영속성 관리.
💡 EntityManager란, 영속성콘텍스트를 관리하며, 이는 특정 영속성 콘텍스트가 관리하는 Entity 인스턴스의 집합이다.
영속성 콘텍스트은 데이터를 영구 저장하는 환경이다. @Entity 어노테이션을 달고 있는 Entity 객체들을 관리하며 실제 DB 테이블과 매핑하여 데이터의 CRUD하는 중요한 기능을 수행한다. 즉 EntityManager는 Entity 객체들을 영속성 콘텍스트에 보관하고 관리한다.
- JPA를 구현한 라이브러리 : Hibernate
- JPA 기반으로 더 편리하게 사용가능한 라이브러리 : Spring Data JPA
5. Spring Data JPA
- Spring Data JPA는 JPA를 한 단계 더 추상화 한 인터페이스 제공.
- Spring framework에서 JPA를 편리하게 사용할 수 있도록 지원하는 라이브러리.
< JPA와 Spring Data JPA의 차이?>
- Spring Data JPA는 Repository 인터페이스를 제공하여 영속성을 관리하고 JPA는 EntityManager를 통해 영속성 관리.
- 즉 Spring Data JPA를 사용하면 Repository 인터페이스을 구현하여 JPA의 EntityManager 대신에 사용이 가능.
- Repository 인터페이스를 구현하면 기본적인 CRUD 작업이 가능.
- Repository 개발시 인터페이스만 작성하면 Spring Data JPA가 메서드 이름을 분석해서 JPQL을 생성한다.(쿼리 메서드)
- @Query 어노테이션을 사용하여 JPQL을 직접 작성한다.
코드 예시 - Spring Data JPA
@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;
}
public interface UserRepository extends JpaRepository <User, Long> {
//DB와 데이터를 Mapping 해주는 repository 클래스
// JpaRepository 의 조상 인터페이스에 Repository 인터페이스 존재.
//기본적인 CRUD를 제공해주는 JpaRepository 상속받아 구현
}
JpaRepository <- PagingAndSortingRepository <- CrudRepository <- Repository(최상위)
CrudRepository 인터페이스에서 CRUD 할 수 있는 메소드 정의.
PagingAndSortingRepository 에서는 페이지와 소트에 관련된 메소드 정의. SQL문에서 order by 기능이 여기서 사용 가능.
//JpaRepository는 기본적인 CRUD를 제공하고 있으므로 우리는 다음과 같이 UserRepository의 save만 호출해주면 데이터가 저장된다.
//그리고 findById를 이용하면 해당 객체를 꺼낼 수 있다.
@Service
@RequiredArgsConstructor
@Transactional(readonly = true)
public class UserService {
private final UserRepository userRepository;
@Transactional
public User findUserAndUpdateName(Long id) {
User user = userRepository.findById(id);
user.setName("변경된 이름");
}
}
<MyBatis 보다 장점> - 출처 : https://mangkyu.tistory.com/20
1) 엔티티에 맞는 테이블 생성 + DB 생성을 편리
- JPA는 설정에 따라 매핑된 객체를 바탕으로 테이블을 자동으로 만들어준다.
- 물론 자동 생성되는 이름이 가독성이 떨어져서 이대로 사용하기에는 부족하지만, 그래도 직접 모든 DDL을 작성하는 것보다는 편리함을 제공해준다.
2) 객체 지향 중심의 개발
- JPA는 객체를 이용하면 우리는 테이블에 매핑되는 클래스를 더욱 객체 지향적으로 개발할 수 있다.
- 그리고 이러한 방향은 객체 지향 언어인 Java에 더욱 잘 맞는다.
3) 테스트 작성이 용이
- JPA는 테이블을 자동으로 만들어주므로 테스트를 작성하기에 매우 좋다.
4) 기본적인 CRUD 자동화
- JPA는 테이블과 객체를 매핑시키는 기술이므로 기본적인 CRUD가 제공된다.
5) 복잡한 쿼리는 QueryDSL을 사용해 처리
- MyBatis는 직접 SQL문을 작성하여 복잡한 쿼리를 작성할 수 있다. JPA에서는 QueryDSL 이라는 오픈소스를 사용한다면 문제를 해결할 수 있다. 아래의 코드는 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;
}
}
6. 하이버네이트(Hibernate)
- JPA 인터페이스를 구현한 라이브러리.
- JPA의 모든 기능을 지원하여 직접 SQL문을 작성할 필요 없음.
- 그렇기 때문에 ORM의 장점인 유지보수에 용이.
출처
- https://velog.io/@hyunjong96/JPA-JDBC-JPAHibernate-MyBatis
- https://velog.io/@rladuswl/ORM%EC%9D%98-%EA%B0%9C%EB%85%90-JPA%EC%99%80-MyBatis-%EC%B0%A8%EC%9D%B4
- https://data-make.tistory.com/621