2021. 8. 19. 08:00ใBack-End ์์ ์ค/Spring Framework
์๋ ํ์ธ์? ์ฃผ๋ํ๋ ์ ๋๋ค.
์ค๋์ 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 ์ฌ์ฉ
์ฃผ๋ํ๋์ ๊ธ์ด ๋ง์์ ๋์ จ๋์? ๊ตฌ๋ ๊ณผ ๊ณต๊ฐ! ๊ทธ๋ฆฌ๊ณ , ๋๊ธ์ ์ฃผ๋ํ๋์๊ฒ ๋ง์ ํ์ด ๋ฉ๋๋ค
'Back-End ์์ ์ค > Spring Framework' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋์ ๊ธฐ์ !] Web Layer (0) | 2021.08.23 |
---|---|
[Spring Boot] AOP (0) | 2021.08.20 |
[Spring Boot] JPA (0) | 2021.08.18 |
[Spring Boot] ํตํฉ Test (0) | 2021.08.17 |
[Spring Boot] ๊ธฐ์กด ์ฝ๋ ์ ์๋๊ณ , ์ค์ ์ผ๋ก ๊ตฌํ Class ๋ณ๊ฒฝ (0) | 2021.08.15 |