일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 다이어리
- DBMS
- Spring
- 오블완
- 티스토리챌린지
- 소켓
- 프로그래밍언어론
- AI
- 스프링
- 스프링부트 웹 소켓
- 인공지능
- libasm
- Xcode
- CI
- 42seoul
- IOS
- JPA
- jenkins
- 오라클
- 리눅스
- 네트워크
- swift
- springboot
- 아이패드다이어리
- MySQL
- 스프링부트
- javascript
- CD
- 데이터베이스
- sql
- Today
- Total
Hi yoahn 개발블로그
[Spring] #7 스프링 DB 접근 기술 2 본문
1. 스프링 JdbcTemplate
- 순수 Jdbc 와 동일한 환경설정
- 스프링 JdbcTemplate과 MyBatis 같은 라이브러리는 JDBC API에서 본 반복 코드를 대부분 제거
but, SQL 은 직접 작성
** 생성자가 하나인 경우에는, @Autowired 를 생략할 수 있다
hello.hellospring.repository/JdbcTemplateMemberRepository.java
public class JdbcTemplateMemberRepository implements MemberRepository {
private final JdbcTemplate jdbcTemplate; //injection XX
@Autowired
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();
}
@Override
public Optional<Member> findByName(String name) {
List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
return jdbcTemplate.query("select * from member", memberRowMapper());
}
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;
}
};
}
}
jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
- memberRowMapper()로 member리스트를 반환
- ? 에 해당하는 인자: name
SpringConfig
@Bean
public MemberRepository memberRepository() {
// return new JdbcMemberRepository(dataSource);
// return new MemoryMemberRepository();
return new JdbcTemplateMemberRepository(dataSource);
}
변경 후, MemberServiceIntegrationTest 로 테스트 진행
- h2 데이터베이스 서버 실행 중인 상태여야 함
2. JPA
- JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
(기본적인 sql 쿼리 jpa 가 만들어줌) - JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.
- JPA를 사용하면 개발 생산성을 크게 높일 수 있다.
- ORM 기술: 객체 Object + 관계형 Relational + Mapping
객체와 관계형 테이블을 매핑 (어노테이션 사용)
build.gradle 파일에 JPA, h2 데이터베이스 관련 라이브러리 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
// implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
application.properties 에 추가
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
1 : jpa가 날리는 sql 쿼리 볼 수 있음
2 : 자동으로 테이블 생성해주는 기능 끄기
(JPA 는 객체를 보고 자동으로 테이블 생성)
JPA 엔티티 매핑
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
...
}
@Id
해당 프로퍼티가 테이블의 primary key 역할을 한다는 것을 나타낸다
속성에 직접 @Id 를 붙여주면 실행시점에 객체의 필드를 통해 직접 접근하게 하는 것
getter 를 이용하려면 getter에 @Id 를 붙여준다
속성에 부여하게 되면 setter/getter 없이도 작업 가능, setter 에 붙이면 예외 발생
@GeneratedValue(strategy = GenerationType.IDENTITY)
primary key 의 자동 생성 전략을 명시하는데 사용
선택적 속성으로 generator와 strategy
strategy는 primary key 를 생성할 때 사용하는 전략 의미, IDENTITY 는 DB의 identity 컬럼을 이용하는 것
$ DB의 컬럼명과 코드의 변수명이 다른 경우,
@Column(name = "(DB 컬럼명)") 어노테이션을 추가하면 된다
JpaMemberRepository
public class JpaMemberRepository implements MemberRepository {
private final EntityManager em;
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
@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> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
}
JPA는 엔티티매니라는 것으로 모든 게 동작함
스프링부트가 자동으로 엔티티 매니저를 생성해줌 -> 인젝션 받으면 됌
(build.gradle에 dependencies 추가-> 라이브러리 받음, application.properties에 설정한 것과 현재 데이터베이스와 연결해서 엔티티매니저 생성)
> JPA 를 쓰려면 엔티티 매니저를 주입받아야 된다 <
- 저장, 조회, 업데이트, 삭제는 sql 쿼리를 짤 필요 없음
- PK기반이 아닌 나머지들은 jpql을 작성해야 함
-> jpa 를 spring에서 한번 감싸서 제공하는 기술 : 스프링 데이터 JPA
-> 사용하면 jpql 안써도 됨 - JPA 를 사용하면 항상 트랜잭션이 있어야 함
-> 서비스 계층이나 회원가입에 @Transactional 추가 - JPA는 모든 변경이 트랜잭션 안에서 실행되어야 함
@Transactional
public class MemberService {}
- Spring은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋
- 런타임 예외가 발생하면 롤백한다.
@Configuration
public class SpringConfig {
// private DataSource dataSource;
//
// @Autowired
// public SpringConfig(DataSource dataSource) {
// this.dataSource = dataSource;
// }
private EntityManager em;
@Autowired
public SpringConfig(EntityManager em) {
this.em = em;
}
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
// return new JdbcMemberRepository(dataSource);
// return new MemoryMemberRepository();
// return new JdbcTemplateMemberRepository(dataSource);
return new JpaMemberRepository(em);
}
}
3. 스프링 데이터 JPA
스프링 부트와 JPA만 사용해도 개발 생산성이 정말 많이 증가하고, 개발해야할 코드도 확연히 줄어듭니다. 여기에 스프링 데이터 JPA를 사용하면, 기존의 한계를 넘어 마치 마법처럼, 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 스프링 데이터 JPA가 모두 제공합니다.
스프링 부트와 JPA라는 기반 위에, 스프링 데이터 JPA라는 환상적인 프레임워크를 더하면 개발이 정말 즐거워집니다. 지금까지 조금이라도 단순하고 반복이라 생각했던 개발 코드들이 확연하게 줄어듭니다. 따라서 개발자는 핵심 비즈니스 로직을 개발하는데, 집중할 수 있습니다.
실무에서 관계형 데이터베이스를 사용한다면 스프링 데이터 JPA는 이제 선택이 아니라 필수 입니다.
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
//JPQL : select m from member m where m.name = ? -> SQL 로 번역되서 실행
@Override
Optional<Member> findByName(String name);
}
interface가 extends로 spring data가 제공하는 JpaRepository 를 하면, 구현체를 자동으로 만들어주고 스프링 빈에 자동으로 등록
-> 가져다가 쓰면 됨
간단한 쿼리는 스프링 데이타가 제공하는 JpaRepository에서 다 제공됨, 단순한 것들도 메서드 이름, 반환 타입, 매개변수를 가지고 해결 가능
참고: 실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용하고, 복잡한 동적 쿼리는 Querydsl이라는 라이브러리를 사용하면 된다. Querydsl을 사용하면 쿼리도 자바 코드로 안전하게 작성할 수 있고, 동적 쿼리도 편리하게 작성할 수 있다. 이 조합으로 해결하기 어려운 쿼리는 JPA가 제공하는 네이티브 쿼리를 사용하거나, 앞서 학습한 스프링 JdbcTemplate를 사용하면 된다.
ref.
inflearn
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
jsaver.tistory.com/entry/Id와-GeneratedValue-애노테이션
suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/
'Framework & Library > springboot' 카테고리의 다른 글
[spring] mysql 설치하기 (0) | 2021.02.06 |
---|---|
[Spring] #8 AOP (0) | 2021.01.29 |
[Spring] #6 스프링 DB 접근 기술1 (0) | 2021.01.25 |
[Spring] #5 회원 관리 예제 - 웹 MVC 개발 (0) | 2021.01.24 |
[Spring] #4 스프링 빈과 의존관계 (스프링 빈 등록 방법) (0) | 2021.01.22 |