07/01 54일차 Spring/ JPA
JPA란
ORM 기술의 표준 인터페이스
장점
1.객체와 데이터베이스 간의 패러다임 불일치 해결
테이블간 매핑을 설정하여, JPA가 객체의 상태를 데이터베이스에 맞춰서 저장하고 관리
2.생산성향상
기본적인 SQL 쿼리 생성, 메서드 호출만으로 데이터베이스 작업 수행
3.유지보수성 향상
SQL 쿼리가 여러 곳에 흩어져 있다면 데이터베이스 변경때마다 모든 SQL 쿼리를 찾아 수정 필요
데이터베이스 구조가 변경되어도 대부분의 경우 알아서 처리 --> 수정 X
4.데이터베이스 독립성
JPA는 데이터베이스 변경시 코드 수정이 최소화된다.
5.성능향상
5-1 지연로딩
필요할 때까지 관련된 엔티티 로딩하지 않음
사용자 정보 조회시 해당 사용자의 모든 정보를 로딩하지 않고 정보가 필요할 때만 데이터베이스에서 조회
5-2 1차 캐시 유지
영속성 콘테스트내에 1차 캐시를 유지
반복 조회시 데이터베이스에 여러번 접근하는 것을 방지
5-3 쓰기 지연
트랜잭션이 커밋되기 전까지 변경된 엔티티를 메모리에 저장
커밋시점에 변경 사항을 데이터베이스에 저장
데이터베이스와의 불필요한 연결과 데이터 전송 최소화
5-4 배치 처리
여러 개의 쿼리를 하나의 배치 작업으로 묶어서 작업 가능
네트워크 비용 감소, 데이터베이스 처리 기능 향상
5-5 쿼리 캐시
자주 사용되는 쿼리 결과를 캐시에 저장, 동일한 쿼리 요청시 캐시에서 결과를 가져옴
동작원리
1. 애플리케이션과 JDBC사이에서 동작, JDBC API를 사용하여 데이터베이스와 통신
2. Entity 객체 분석 및 SQL 생성
3. 생성된 SQL --> JDBC API를 통해 데이터베이스에 전송되어 실행
4. 객체 - 관계 맵핑
pom.xml
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.33.Final</version>
</dependency>
<!-- Hibernate EntityManager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.33.Final</version>
</dependency>
<!-- Hibernate JPA API
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency> -->
<!-- JPA API -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
spring-context.xml 설정 예시
- 데이터 소스, 엔티티 매니저 팩토리, 트랜잭션 매니저 등 설정
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 스캔할 패키지를 지정 -->
<context:component-scan base-package="com.example"/>
<!-- JPA를 위한 데이터 소스 설정 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="username" value="it"/>
<property name="password" value="0000"/>
</bean>
<!-- JPA EntityManagerFactory 설정 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<!-- 트랜잭션 매니저 설정 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- 트랜잭션 어노테이션 활성화 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
PA로 코드를 작성 후 추가 기능 구현 시 Hibernate의 추가 API 활용 예
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
@Table(name = "users3")
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users3_seq_gen")
@SequenceGenerator(name = "users3_seq_gen", sequenceName = "users3_seq", allocationSize = 1)
@Column(name = "user_seq")
private Long userSeq;
@Column(name = "user_id", nullable = false, length = 20)
private String userId;
@Column(name = "user_pw", nullable = false, length = 20)
private String userPw;
@OneToMany(mappedBy = "user3", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<HabitEntity> habits;
// getters and setters
}
import javax.persistence.*;
@Entity
@Table(name = "reply")
public class HabitEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "hseq")
private Long hseq;
@Column(name = "hname")
private String hname;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userSeq", nullable = false)
private UserEntity user;
// Getters and Setters
}
JpaRepository 기본 메서드들
//select count(1) from users3;
userRepository.count();
//delete from users3 where userSeq= ?
userRepository.delete(Long id);
//delete from users3 where userId= ? and userPw=? and userName=?
userRepository.delete(UserEntity entity);
//delete from users3;
userRepository.deleteAll();
//select * from users3 wehre userSeq=?
userRepository.exists(Long id);
//select * from users3;
userRepository.findAll()
//sub.. sub.. sub..select * from users3 where~~~ rnum between 1 and 10;
userRepository.findAll(Pageable);
//select * from users3 order by userName asc, userSeq desc;
userRepository.findAll(Sort)
//select * from users3 where userSeq=?
userRepository.findOne(Long id);
userRepository.getOne(Long id);
//insert into users3 (...)
//update users3 set (...)
userRepository.save(UserEntity entity);