Spring DB 접근 기술 (순수 JDBC, JdbcTemplate, JPA, Spring Data Jpa)

전승재·2023년 8월 12일

순수 JDBC란?

Jdbc란, Java DataBase Connectivity의 약자로 데이터베이스를 연결하기 위한 API이다.
과거 20년 전에 사용하는 방식이라고 한다.
connection을 열어주고 닫고, 결과를 ResultSet에 저장하는 등 일일히 처리해줘야 하는 부분이 많다.
이러한 불편한 부분을 해결하기 위해 Spring JdbcTemplate이 등장했다.
하지만 Spring JdbcTemplate 역시 sql문은 직접 작성해야 한다.
아래는 순수 JDBC의 코드이다.

public class JdbcMemberRepository implements MemberRepository {
   private final DataSource dataSource;
   public JdbcMemberRepository(DataSource dataSource) {
      this.dataSource = dataSource;
   }
   @Override
   public Member save(Member member) {
     String sql = "insert into member(name) values(?)"; // sql문
     Connection conn = null;
     PreparedStatement pstmt = null; 
     ResultSet rs = null; //결과를 저장하는 객체
     try {
       conn = getConnection();
       pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
       
       pstmt.setString(1, member.getName()); // 넣을 값
       pstmt.executeUpdate(); // 쿼리문 보내기
       rs = pstmt.getGeneratedKeys();//key를 꺼내줌
       if (rs.next()) { // 값이 있다면
          member.setId(rs.getLong(1));
       } else {
       throw new SQLException("id 조회 실패"); // 없다면
       }
    	 return member;
     } catch (Exception e) { //예외
    	 throw new IllegalStateException(e);
     } finally { //connection 닫아줌 
     	close(conn, pstmt, rs);
     }
 }

JdbcTemplate란?

순수 JDBC와 동일한 환경설정을 하면 된다.
스프링 JdbcTemplate과 MyBatis 같은 라이브러리는 순수 JDBC API에서 본 반복 코드를 대부분
제거해준다. 하지만 SQL은 직접 작성해야 한다.

public class JdbcTemplateMemberRepository implements MemberRepository {
   private final JdbcTemplate jdbcTemplate;
   public JdbcTemplateMemberRepository(DataSource dataSource) {
   		jdbcTemplate = new JdbcTemplate(dataSource);
   }
   @Override
   public Member save(Member member) {
     SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
     jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
     Map<String, Object> parameters = new HashMap<>();
     parameters.put("name", member.getName());
     
     Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
     member.setId(key.longValue());
   return member;
 }
 	@Override
   public Optional<Member> findById(Long id) {
   List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
   return result.stream().findAny();
 }

JDBC와 비교하면 findById부분에서 엄청난 차이를 보인다.

jdbcTemplate.query(select * from member where id = ?", memberRowMapper(), id)

JPA란?

JPA는 "Java Persistence API"의 약자로, 자바 언어를 위한 데이터 영속성 프레임워크이다.
전세계적으로 봤을 때 대부분이 JPA를 사용하고 있고, 국내에서도 증가하고 있는 추세이다.
JPA는 자바 애플리케이션에서 관계형 데이터베이스(RDBMS MYSQL)를 사용하는데 도움이 되는 기술로, 객체 지향 프로그래밍과 데이터베이스 간의 매핑을 간소화하고 표준화하는 목적을 가지고 있다.
JPA는 객체와 데이터베이스 간의 매핑을 위한 주요 어노테이션 및 기타 기능을 제공하여 개발자가 더 효율적으로 데이터베이스를 다룰 수 있도록 도와준다.

  • JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
  • JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.
  • JPA를 사용하면 개발 생산성을 크게 높일 수 있다.

사용법

Entity에 어노테이션을 추가해야한다.
Repository에서 단순한 CRUD는 지원되지만 나머지는 직접 쿼리문을 작성해야한다.
이러한 부분을 해결한 것이 Spring Data JPA이다.

Entity

package hello.hellospring.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity //JPA가 관리하는 엔티티임을 표시
public class Member {
 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // pk임을 표시, 자동생성되는 값임을 표시
 private Long id;
 @Column(name="username") // column명을 username으로 설정한다는 어노테이션
 private String name;
 public Long getId() {
 return id;
 }
 public void setId(Long id) {
 this.id = id;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
}

JpaRepository

package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Optional;
public class JpaMemberRepository implements MemberRepository {
 private final EntityManager em; //JPA는 EntityManager가 관리한다.
 public JpaMemberRepository(EntityManager em) { //생성자
 	this.em = em;
 }
 public Member save(Member member) {
 	em.persist(member);
 	return member;
 }
 public Optional<Member> findById(Long id) {
 	Member member = em.find(Member.class, id);
 	return Optional.ofNullable(member);
 }
 public List<Member> findAll() {
 	return em.createQuery("select m from Member m", Member.class).getResultList();//jpql 생성가능
 }
 public Optional<Member> findByName(String name) {
 	List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class) //jpql 생성가능
 		.setParameter("name", name)
 		.getResultList();
 	return result.stream().findAny();
 }
}

Spring Data Jpa

스프링 부트와 JPA만 사용해도 개발 생산성이 정말 많이 증가하고, 개발해야할 코드도 확연히 줄어든다.
여기에 스프링 데이터 JPA를 사용하면 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있다. 또한 반복 개발해온 기본 CRUD 기능도 스프링 데이터 JPA가 모두 제공한다.
개발자는 핵심 비즈니스 로직을 개발하는데 집중할 수 있게된다.
하지만 JPA를 정확히 알고 사용하는 것이 좋아보인다!~!

사용법

앞의 JPA설정을 그대로 사용한다.

Interface

놀랍게도 아래 코드가 구현 완료한것이라고 한다. 상위 인터페이스인 JpaRepository에 들어가보면 다 제공되는 메소드들이 있다.
따라서 그것들을 가져다가 쓰는 형식이다.
아래에 findByName은 없기 때문에 직접 넣어준것이다.
근데 이 findByName마저 인터페이스의 이름으로 자동으로 JPQL을 생성하여 처리해준다고 한다.
매우매우 편리한 기술이지만 JPA를 완전히 공부하고 사용하는게 좋아보인다!

public interface SpringDataJpaMemberRepository extends JpaRepository<Member,Long>, MemberRepository {
	// JPQL 자동생성 -> select m from Member m where m.name=?
    // 인터페이스 이름만으로 JPQL을 자동생성하여 처리한다.
	@Override
	Optional<Member> findByName(String name);
}

SpringConfig

@Configuration
public class SpringConfig {
 private final MemberRepository memberRepository;
 public SpringConfig(MemberRepository memberRepository) {
 	this.memberRepository = memberRepository;
 }
 @Bean
 public MemberService memberService() {
 	return new MemberService(memberRepository);
 }
}

기존의 JDBC와 JPA의 차이점

JDBC 사용 방식

저수준 API: JDBC는 데이터베이스와의 연결, 쿼리 실행, 결과 처리 등을 직접 관리해야 하는 저수준 API이다. SQL문을 직접 작성하고 ResultSet으로 결과를 받아 처리해야 한다.

반복적인 코드: 데이터베이스 연결 및 자원 관리, 예외 처리 등 반복적인 코드가 많이 필요하다. 이로 인해 코드 양이 많아지고 유지보수가 어려울 수 있다.

성능 최적화: JDBC를 사용하면 쿼리를 직접 작성하고 최적화해야 합니다. 이로 인해 데이터베이스에 대한 성능 튜닝이 필요할 수 있습니다.

JPA 사용 방식

객체 지향적: JPA는 객체 지향 프로그래밍의 관점에서 데이터베이스를 다룰 수 있도록 한다. 엔티티 클래스를 생성하고 어노테이션으로 매핑하면 SQL을 직접 작성하지 않고도 데이터베이스 연산이 가능하다.

높은 생산성: JPA를 사용하면 반복적인 CRUD 작업을 자동으로 처리할 수 있습니다. 데이터베이스와의 연결, 트랜잭션 관리, 예외 처리 등의 일을 JPA가 대신 처리해줘 편리하다.
유지보수 용이: 엔티티 클래스와 어노테이션을 사용하여 데이터베이스 스키마와 자바 객체 간의 매핑을 설정하므로, 스키마 변경 시에도 비교적 쉽게 대응할 수 있다.

JPQL: JPA는 JPQL(Java Persistence Query Language)을 제공하여 객체 지향적인 쿼리 작성을 가능하게 한다. SQL에 비해 엔티티 객체와 필드를 사용하므로 유지보수와 가독성이 좋다.

장단점

기존의 JDBC 사용 방식의 장점

세밀한 제어 가능: SQL을 직접 작성하고 최적화할 수 있다.
더 낮은 레벨의 접근: 특정한 성능 최적화가 필요한 경우에는 더 많은 제어권을 가질 수 있다.

JPA 사용 방식의 장점:

높은 생산성: CRUD 작업이 간소화되어 개발 시간을 단축할 수 있다.
객체 지향적: 객체와 데이터베이스 간의 매핑을 편리하게 처리할 수 있다.
유지보수 용이: 스키마 변경에 유연하게 대응할 수 있다.

둘 다 고려해야 할 단점:

학습 곡선: JPA는 학습이 필요한 새로운 기술일 수 있다.
일부 특정한 케이스에서의 성능: 특정한 상황에서는 기존의 JDBC 방식이 성능면에서 더 유리할 수 있다.

따라서 프로젝트의 요구사항, 개발 팀의 기술 수준, 성능 요구사항 등을 고려하여 JDBC 또는 JPA 중 어느 방식을 선택할지 결정해야 한다.

우리의 프로젝트에서 사용할 기술은?

우리의 프로젝트에서는 JPA를 사용해서 진행할 예정이다. Spring Data Jpa는 JPA를 학습 후에 나중에 사용해보고 싶은 기술이다.
순수 JDBC는 너무 과거의 기술이고 JdbcTemplate와 JPA를 비교했을 때 유지보수가 용이한 JPA를 사용하는 것이 좋을 것 같아서 JPA로 진행하려고 한다.

0개의 댓글