본문 바로가기

Spring/etc

[Spring Boot] ORM과 JDBC, JPA

728x90
반응형

 

이번 시간에는 ORM와 JDBC, JPA에 대해서 배워보고자 합니다.

 

위의 ORM, JDBC, JPA는 모두 데이터베이스와 관련된 내용들인데요,

하나씩 차근차근 다뤄보겠습니다.

 

 

 

 

JDBC

 

 

 

JDBC는 JAVA에서 DB 접근을 하기 위해 java에서 제공하는 API입니다.

Persistence Layer를 구현하기 위해서 사용되는데,

이 때 Persistence Layer란 프로그램의 아키텍쳐에서 데이터를 생성한 프로그램이 종료되더라도 사라지지 않도록 하는 영속성을 데이터에 부여하기 위해 존재하는 Layer입니다.

 

 

모든 Java Data Access 기술들은 JDBC를 기본적으로 사용하고 있고, 현재 사용되는 Java Data Access 기술들은 순수하게 JDBC만 사용했을 때의 단점들을 보완한 형식입니다.

JDBC는 아래와 같은 방식으로 동작합니다.

 

 

출처 : https://thefif19wlsvy.tistory.com/249

 

 

먼저 순수하게 JDBC를 사용했을 때 DB 연결 코드를 살펴보겠습니다.

 

    @Override
    public Member save(Member member) {
        String sql = "insert into member(name) values(?)";
        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();
            if (rs.next()) {
                member.setId(rs.getLong(1));
            } else {
                throw new SQLException("id 조회 실패");
            }
            return member;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs); }
    }

    @Override
    public Optional<Member> findById(Long id) {
        String sql = "select * from member where id = ?";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.setLong(1, id);
            rs = pstmt.executeQuery();
            if(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return Optional.of(member);
            } else {
                return Optional.empty();
            }
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

 

위의 코드를 보면 굉장히 반복되는 코드가 많다는 것을 확인할 수 있습니다.

계속 반복되는 try catch 문 부터 connection 부분까지 하나의 파일 안에서 Data Access를 해결해야 하기 때문에 중복 코드가 굉장히 많습니다.

 

 

 

JdbcTemplate과 SqlSessionTemplate

 

 

이것보다 조금 더 발전한 것이 JdbcTemplate 입니다.

JdbcTemplate을 사용하면 아래와 같이 조금 더 중복되는 코드가 줄어듭니다.

 

    @Override
    public Member save(Member member) {
        // sql을 직접 짜지 않는 방법
        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를 사용했던 것 보다는 중복된 코드가 많이 줄었습니다.

그런데 이렇게 JdbcTemplate을 사용하거나 순수 JDBC를 사용하게 되면 datasource를 설정하고 JdbcTemplate를 생성하여 class를 구현하는 방식으로 DB 연동을 해야합니다.

 

 

 

이러한 DB 연동을 class를 사용하지 않고 다른 방법으로 기존의 코드와 분리시켜서 하는 방법으로 개발하는 것이 바로 

SqlSessionTemplate 입니다.

 

SqlSessionTemplate을 사용하는 라이브러리는 대표적으로 MyBatis가 있으며 아래와 같이 xml 형식으로 Data Access을 할 수 있습니다.

 

<select id = "test" resultType="test.team.vo.UserVO">
  SELECT 	ID, PASSWD
  FROM	USER
  WHERE	ID = #{id}
</select>

 

이렇게 xml 파일을 따로 만들어 DB 관련된 mapping 코드들을 따로 구분지을 수 있습니다.

 

 

 

지금까지 소개한 Java Data Access 는 SQL 을 작성함으로써 이루어져 있습니다.

즉, SQL과 Object를 맵핑한 것으로, SQL문을 이용해 DB를 조작한 것이죠.

 

그러나 이렇게 SQL을 사용하지 않고 바로 DB 데이터와 Object를 맵핑할 수 있는 방식이 있습니다.

그것이 바로 ORM입니다.

 

 

ORM

 

 

ORM 또한 jdbc를 기본으로 하되 SQL 맵핑이 아닌 object relational DB를 맵핑하는 방식을 사용하여 개발자가 SQL을 적어줄 필요가 없는, 좀 더 객체 지향적인 Java Data Access 방식입니다.

따라서 SQL을 작성하지 않는 대신 메서드를 이용하여 데이터를 조작하게 되고, 객체간의 관계를 바탕으로 하여 ORM이 알아서 sql을 자동으로 생성해줍니다.

 

 

대표적인 ORM으로는 JPA가 있습니다.

 

JPA는 ORM을 구현하기 위한 표준 인터페이스입니다.

즉, 인터페이스라는 말은 이를 구현할 수 있는 기술들이 필요하다는 뜻이고, 가장 대표적으로는 hibernate가 있습니다.

 

그러면 JPA를 쓰면 위의 코드가 어떻게 바뀔까요?

 

    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

 

 

위에서 소개한 방법에 비해서 정말 간단합니다!

그리고 메서드를 통해서 data access 가 가능하기 때문에 더 깔끔하고, 객체 지향적이죠.

또한 아주 간단한 메소드로도 CRUD가 가능합니다.

어떻게 이런 것이 가능할까요?

 

 

이는 아래의 그림을 통해 쉽게 이해할 수 있습니다.

아래는 JPA를 이용하여 persist(저장) 메소드를 통해 entity object를 넘겨주었을 때의 동작입니다.

 

 

출처 : https://velog.io/@adam2/JPA%EB%8A%94-%EB%8F%84%EB%8D%B0%EC%B2%B4-%EB%AD%98%EA%B9%8C-orm-%EC%98%81%EC%86%8D%EC%84%B1-hibernate-spring-data-jpa

 

 

728x90
반응형