[Spring Boot] Spring Data JPA

2021. 8. 19. 08:00ใ†Back-End ์ž‘์—…์‹ค/Spring Framework

728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”? ์ฃผ๋‹ˆํ•˜๋ž‘ ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ Spring Data JPA์—  ๋Œ€ํ•ด ๊ณต๋ถ€ ํ•ด ๋ณด๋„๋ก ํ•  ๊ฒƒ์ด์—์š”.

๋ฐ”๋กœ ์‹œ์ž‘ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

์ฝ”๋“œ์— ๊ด€๋ จํ•œ ๋‚ด์šฉ์€ ์ฃผ๋‹ˆํ•˜๋ž‘์˜ Github์—์„œ ํ™•์ธ ํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 

 

 

 


 

 

๐Ÿ“‹ ๋ชฉ์ฐจ


01.[Spring Boot] thymeleaf์™€ Spring Boot
02.[Spring Boot] Spring Web ๊ฐœ๋ฐœ ๊ธฐ์ดˆ
03.[Spring Boot] ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - Backend
04.[Spring Boot] Service ๊ฐœ๋ฐœ ๋ฐ Test Case ์ž‘์„ฑ
05.[Spring Boot] Spring Bean๊ณผ ์˜์กด๊ด€๊ณ„
06.[Spring Boot] Java Code๋กœ ์ง์ ‘ Spring Bean ๋“ฑ๋ก
07.[Spring Boot] ๋“ฑ๋ก, ๋ชฉ๋ก ๋ณด๊ธฐ ๊ตฌํ˜„ํ•˜๊ธฐ
08.[Spring Boot] ๊ธฐ์กด ์ฝ”๋“œ ์† ์•ˆ๋Œ€๊ณ , ์„ค์ •์œผ๋กœ ๊ตฌํ˜„ Class ๋ณ€๊ฒฝ
09.[Spring Boot] ํ†ตํ•ฉ Test
10.[Spring Boot] JPA
11.[Spring Boot] Spring Data JPA
12.[Spring Boot] AOP

 

 


 

 


๐Ÿ“Œ Spring Data JPA


Spring Boot์™€ JPA๋งŒ ์‚ฌ์šฉํ•ด๋„ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์ด ๋งŽ์ด ์ฆ๊ฐ€ํ•˜๊ณ , ๊ฐœ๋ฐœํ•ด์•ผ ํ•  Code์˜ Line๋„ ๋งŽ์ด ์ค„์–ด ๋“œ๋Š” ๊ฒƒ์ด์—์š”.

์—ฌ๊ธฐ์— ์˜ค๋Š˜์˜ ์ฃผ์ธ๊ณต์ธ Spring Data JPA๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๊ธฐ์กด์˜ ํ•œ๊ณ„๋ฅผ ๋„˜์–ด ๋งˆ์น˜ ๋งˆ๋ฒ•์ฒ˜๋Ÿผ, Repository์— ๊ตฌํ˜„ Class ์—†์ด Interface๋งŒ์œผ๋กœ ๊ฐœ๋ฐœ์„ ์™„๋ฃŒ ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

๊ทธ๋ฆฌ๊ณ  ๋ฐ˜๋ณต์ ์œผ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” CRUD ๊ธฐ๋Šฅ๋„ Spring Data JPA๊ฐ€ ๋ชจ๋‘ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์—์š”.

 

Spring Boot์™€ JPA๋ผ๋Š” ๊ธฐ๋ฐ˜ ์œ„์— Spring Data JPA๋ผ๋Š” Frame Work๋ฅผ ๋”ํ•˜๋ฉด ํ™˜์ƒ์˜ ์ฝค๋น„๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด์—์š”.

์™œ๋ƒํ•˜๋ฉด? ์ง€๊ธˆ๊นŒ์ง€ ์กฐ๊ธˆ์ด๋ผ๋„ ๋‹จ์ˆœ ๋ฐ˜๋ณต ์ž‘์—…์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜์—ˆ๋˜ ๋ถ€๋ถ„๋“ค์ด ์‚ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋ž๋‹ˆ๋‹ค.

 

๊ฐœ๋ฐœ์ž๋Š” ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ๋ฐœ์— ๋”์šฑ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ฒ ์ง€์š”?

 

๊ด€๊ณ„ํ˜• DB๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด Spring Data JPA๋Š” ํ•„์ˆ˜๋กœ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•œ๋‹ต๋‹ˆ๋‹ค!

 

 

         ๐Ÿ‘‰ Spring Boot JPA Config Insert

SpringDataJpaMemberRepository.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository{

    @Override
    // JPQL ๋ฒˆ์—ญ : select m from Member m where m.name = ?
    Optional<Member> findByName(String name);
} // Interface ๋

 

์ž! ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฒˆ ์‹œ๋ฆฌ์ฆˆ์—์„œ ๊ณ„์† ๋ณ€๊ฒฝ์ด ์ด๋ค„์กŒ์—ˆ๋˜ Jdbc์™€ JPA ์ฝ”๋“œ๋“ค์„ ๋ชจ๋‘ ๋น„๊ต ํ•ด ๋ณผ๊นŒ์š”?

 

         ๐Ÿ‘‰ JDBC

JdbcMemberRepository.java

package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

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(?)";
        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);
        }
    }

    @Override
    public List<Member> findAll() {
        String sql = "select * from member";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            List<Member> members = new ArrayList<>();

            while(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                members.add(member);
            }

            return members;

        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

    @Override
    public Optional<Member> findByName(String name) {
        String sql = "select * from member where name = ?";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, name);
            rs = pstmt.executeQuery();

            if(rs.next()) {
                Member member = new Member();
                member.setId(rs.getLong("id"));
                member.setName(rs.getString("name"));
                return Optional.of(member);
            }

            return Optional.empty();

        } catch (Exception e) {
            throw new IllegalStateException(e);

        } finally {
            close(conn, pstmt, rs);
        }
    }

    private Connection getConnection() {

        return DataSourceUtils.getConnection(dataSource);
    }

    private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
    {
        try {
            if (rs != null) {
                rs.close();
            }

        } catch (SQLException e) {
            e.printStackTrace();

        } try {
        if (pstmt != null) {
            pstmt.close();
        }

    } catch (SQLException e) {
        e.printStackTrace();
    }

        try {
            if (conn != null) {
                close(conn);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    private void close(Connection conn) throws SQLException {
        DataSourceUtils.releaseConnection(conn, dataSource);
    }
}

 

์šฐ์™€! ์—„์ฒญ ๊ธด ๊ฒƒ์ด์—์š”!

 

 

         ๐Ÿ‘‰ JDBC Template

JdbcTemplateMemberRepository.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class JdbcTemplateMemberRepository implements MemberRepository{

    private final JdbcTemplate jdbcTemplate;

    @Autowired  // ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜์ผ ๋•, ์ƒ๋žต ๊ฐ€๋Šฅ
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        this.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;
    } // save() ๋

    @Override
    public Optional<Member> findById(Long id) {
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    } // findById() ๋

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    } // findByName() ๋

    @Override
    public List<Member> findAll() {
        return jdbcTemplate.query("select * from member", memberRowMapper());
    } // findAll() ๋

    private RowMapper<Member> memberRowMapper() {
//        return new RowMapper<Member>() {
//            @Override
//            public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
//
//                Member member = new Member();
//                member.setId(rs.getLong("id"));
//                member.setName(rs.getString("name"));
//
//                return member;
//            }
//        }

        // ์œ„์˜ ์ฝ”๋“œ ๋žŒ๋‹ค ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜

        return (rs, rowNum) -> {

            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));

            return member;
        }; // mapRow() ๋
    } // memberRowMapper() ๋
} // Class ๋

 

์กฐ๊ธˆ ์ค„์–ด๋“ค๊ธด ํ–ˆ์ง€๋งŒ, ์•„์ง๋„ ์ •์‹ ์ด ์—†๋Š” ๊ฒƒ์ด์—์š”. ๊ทธ๋ฆฌ๊ณ , ์ง์ ‘ SQL Query๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ๊ณ  ์žˆ๋‹ต๋‹ˆ๋‹ค!

 

         ๐Ÿ‘‰ JPA

JpaMemberRepository.java

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;

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    } // JpaMemberRepository() ๋

    @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);
    }

    @Override
    public Optional<Member> findByName(String name) {
        List<Member> reulst = em.createQuery("select m from Member m where m.name = :name", Member.class).setParameter("name", name).getResultList();
        return reulst.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
//        List<Member> result = em.createQuery("select m from Member m", Member.class).getResultList();
//        return result;

        // ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ™” ํ•œ ๊ฒƒ
        return em.createQuery("select m from Member m", Member.class).getResultList();
    }
}

 

์ด์ œ๋Š” ์–ด๋Š์ •๋„ ๊ฐ€๋…์„ฑ๋„ ์ข‹์•„์ง„ ๊ฒƒ ๊ฐ™์ง€ ์•Š์œผ์„ธ์š”?

 

 

    ๐Ÿ“ Spring Data JPA ํšŒ์› Repository๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก Spring Config Modifie

 

SpringConfig.java

package hello.hellospring;

import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.repository.JdbcTemplateMemberRepository;
import hello.hellospring.repository.JpaMemberRepository;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.sql.DataSource;

@Configuration
public class SpringConfig {

    private final MemberRepository memberRepository;

    @Autowired      // ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜๋ผ๋ฉด ์ƒ๋žต ๊ฐ€๋Šฅ
    public SpringConfig(MemberRepository memberRepository) {
    
        this.memberRepository = memberRepository;
    } // ์ƒ์„ฑ์ž ๋

    // @Bean : Bean์„ ๋‚ด๊ฐ€ ์ง์ ‘ ๋งŒ๋“ค๊ฒ ๋‹ค๋Š” ์˜๋ฏธ; ์Šคํ”„๋ง์€ ์ด๊ฒƒ์„ ๋ณด๊ณ , Bean์„ ๋“ฑ๋กํ•˜๋ผ๋Š” ๋ช…๋ น์œผ๋กœ ์ธ์‹
    @Bean
    // ์•„๋ž˜ Method๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ Bean์— ๋“ฑ๋ก
    public MemberService memberService() {
        // MeberService๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ memberRepository๋ฅผ Spring Bean์— ๋“ฑ๋ก ๋œ ์ฃผ์ž…ํ•˜์—ฌ ์ค€๋‹ค.
        return new MemberService(memberRepository);
    } // memberService() ๋

 

์ด๋ ‡๊ฒŒ ํ•ด ๋‘๋ฉด Spring Data JPA๊ฐ€ SpringDataJpaMemberRepository๋ฅผ Spring Bean์œผ๋กœ ์ž๋™ ๋“ฑ๋ก ํ•˜์—ฌ ์ค€๋‹ต๋‹ˆ๋‹ค!

 

 

์ถœ์ฒ˜ : ์ธํ”„๋Ÿฐ: ์Šคํ”„๋ง ์ž…๋ฌธ - ์ฝ”๋“œ๋กœ ๋ฐฐ์šฐ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ

 

์œ„์— ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ๊ฐ Interface๋“ค์€ ์šฐ๋ฆฌ๊ฐ€ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ธฐ๋Šฅ๋“ค์„ ๋ชจ๋‘ ์ด๋ฏธ ๋งŒ๋“ค์–ด ๋†“์€ ๊ฒƒ์ด์—์š”. ์ €๊ธฐ PagingAndSortingRepository๋ฅผ ๋ณด์„ธ์š”! Paging ์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ๊นŒ์ง€ ๋งŒ๋“ค์–ด์ ธ ์žˆ์–ด์š”!

 

    ๐Ÿ“ Spring Data JPA ๊ธฐ๋Šฅ

  • Interface๋ฅผ ํ†ตํ•œ ๊ธฐ๋ณธ CRUD ๊ธฐ๋Šฅ
  • findByName(), findByEmail()๊ณผ ๊ฐ™์ด Method ์ด๋ฆ„ ๋งŒ์œผ๋กœ ์กฐํšŒ ๊ธฐ๋Šฅ ์ œ๊ณต
  • Paging ๊ธฐ๋Šฅ ์ž๋™ ์ œ๊ณต

 

๐Ÿ’ก ์ฐธ๊ณ 
๊ธฐ๋ณธ์ ์œผ๋กœ Spring์—์„œ๋Š” JPA์™€ Spring Data JPA๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋ณต์žกํ•œ ๋™์  Query์˜ ๊ฒฝ์šฐ Querydsl์ด๋ผ๋Š” Library๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค. Querydsl๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด Query๋„ Java Code๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ณ ,
๋™์  Query๋„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์กฐํ•ฉ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด Query์˜ ๊ฒฝ์šฐ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” Native Query(SQL Query)๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, Jdbc Template ์‚ฌ์šฉ

 

 

 


 

์ฃผ๋‹ˆํ•˜๋ž‘์˜ ๊ธ€์ด ๋งˆ์Œ์— ๋“œ์…จ๋‚˜์š”? ๊ตฌ๋…๊ณผ ๊ณต๊ฐ! ๊ทธ๋ฆฌ๊ณ , ๋Œ“๊ธ€์€ ์ฃผ๋‹ˆํ•˜๋ž‘์—๊ฒŒ ๋งŽ์€ ํž˜์ด ๋ฉ๋‹ˆ๋‹ค

728x90
๋ฐ˜์‘ํ˜•