jpa 잘 (하는 척) 하기
TRANSCRIPT
JPA 잘 (하는 척) 하기
SLiPP-JPA 이경원
목차
● JPA 소개
● JDBC부터 JPA까지
● 객체와 테이블
● 엔티티 생명주기
● 영속성 컨텍스트
● Spring Data JPA
● 참고 자료
● QnA
JPA(Java Persistence API) 소개
● Java ORM(Object-Relational Mapping) 표준 F/W
● RDB를 객체로 표현(매핑), 사용
● Hibernate, Eclipse Link, TopLink Essensials 구현체
JDBC부터 JPA까지
요구 사항
단순 CRU(입력, 조회, 수정)
public class User {
private int userId;
private String name;
private String password;
}
JDBC
// connection…
1. 쿼리 생성String insertQuery = "insert into User(userId, name, password) values(?, ?, ?)";
2. parameter 매핑pstmt.setInt(1, user.getUserId());pstmt.setString(2, user.getName());pstmt.setString(3, user.getPassword());
3. 쿼리 실행pstmt.executeUpdate(insertQuery);
// close...
// connection…
1. 쿼리 생성String selectQuery = "select userId, name, password from User where userId =" +
user.getUserId();
2. 쿼리 실행ResultSet rs = stmt.executeQuery(selectQuery);
3. 데이터 매핑user.setUserId(rs.getInt("userId"));user.setName(rs.getString("name"));user.setPassword(rs.getString("password"));
// close...
// connection…
1. 쿼리 생성String updateQuery = "update User set name = ?, password = ? where userId = ?";
2. parameter 매핑pstmt.setString(1, user.getName());pstmt.setString(2, user.getPassword());pstmt.setInt(3, user.getUserId());
3. 쿼리 실행pstmt.executeUpdate(updateQuery);
// close...
Query 생성, 실행, 데이터 매핑 반복
Connection, close 코드 반복
MyBatis
1. insert<insert id="inser" parameterType="User">
insert into User(userId, name, password) values (#{userId}, #{name}, #{password})</insert>
2. select<select id="select" parameterType="java.lang.Integer" resultType="User">
select userId, name, password from User where userId = #{userId}</select>
3. update<update id="update" parameterType="User">
update User set name = #{name}, password = #{password} where userId = #{userId}</update>
Connection, close 위임
parameter 매핑, 데이터 매핑 위임
하지만 여전히 Query 작성 반복
JPA
EntityManager em = entityManagerFactory.createEntityManager();
// Insertem.persist(user);
// SelectUser user = em.find(User.class, user.getUserId());
// Updateuser.setName("update Name");user.setPassword("1111");
// Deleteem.remove(user);
Connection, close 위임
쿼리 자동 생성, 실행
User 테이블에
“nickName” 컬럼이 추가 된다면?
public class User {
private int userId;
private String name;
private String password;
// nickName 컬럼 추가private String nickName;
}
JDBC
1. insert 쿼리 생성String insertQuery = "insert into User(userId, name, password, nickName) values(?, ?, ?, ?)";
2. parameter 매핑pstmt.setInt(1, user.getUserId());pstmt.setString(2, user.getName());pstmt.setString(3, user.getPassword());pstmt.setString(4, user.getNickName());
3. 쿼리 실행pstmt.executeUpdate(insertQuery);
1. select 쿼리 생성String selectQuery = "select userId, name, password, nickname from User where userId = " +
user.getUserId();
2. 쿼리 실행ResultSet rs = stmt.executeQuery(selectQuery);
3. 데이터 매핑user.setUserId(rs.getInt("userId"));user.setName(rs.getString("name"));user.setPassword(rs.getString("password"));user.setNickName(rs.getString("nickName"));
1. update 쿼리 생성String updateQuery = "update User set name = ?, password = ?, nickName = ? where userId = ?";
2. parameter 매핑pstmt.setString(1, user.getName());pstmt.setString(2, user.getPassword());pstmt.setString(3, user.getNickName());pstmt.setInt(4, user.getUserId());
3. 쿼리 실행pstmt.executeUpdate(updateQuery);
Query 수정, 데이터 매핑 코드 추가
MyBatis
1. insert<insert id="inser" parameterType="User">
insert into User(userId, name, password, nickName) values (#{userId}, #{name}, #{password}, #{nickName})
</insert>
2. select<select id="select" parameterType="java.lang.Integer" resultType="User">
select userId, name, password, nickName from User where userId = #{userId}</select>
3. update<update id="update" parameterType="User">
update User set name = #{name}, password = #{password}, nickName = #{nickName} where userId = #{userId}
</update>
Query 수정
JPA는 얼마나 변경됐을까요?
// insertem.persist(user);
// selectem.find(User.class, user.getUserId());
// updateuser.setName("update Name");user.setPassword("1111");
// deleteem.remove(user);
// insertem.persist(user);
// selectem.find(User.class, user.getUserId());
// updateuser.setName("update Name");user.setPassword("1111");user.setNickName("update nickName");
// deleteem.remove(user);
요구사항 변경 전 요구사항 변경 후
모든 Domain은 변경된다.
● type safe 하지 않고
● 실수할 확률이 높고
● 수정해야 할 코드가 많아지며
● 단순 CRUD 코드를 반복한다.
객체와 테이블
테이블 지향 엔티티public class User {
private int userId;
private String name;
private String password;
private String nickName;
}
public class Board {
private int boardId;
// foreign keyprivate int userId;
private String title;
private String content;
}
객체 지향 엔티티public class User {
private int userId;
private String name;
private String password;
private String nickName;
}
public class Board {
private int boardId;
// object referenceprivate User user;
private String title;
private String content;
}
● 객체 그래프 탐색
● 테이블과 객체 간 연관 관계 불일치
● Query 작성 증가
엔티티 생명주기
● New(비영속) : DB에 반영 되지 않고 영속성 컨텍스트와 관
계 없는 엔티티
● Managed(영속) : 영속성 컨텍스트에 저장된 엔티티
● Detached(준영속) : 영속성 컨텍스트에서 분리된 엔티티
● Removed(삭제) : 삭제된 엔티티
비영속 그리고 준영속
// 비 영속User newUser = new User(“name”, “password”, “nickName”);
// 준 영속User detachUser = new User(1, “name”, “password”, “nickName”);
detachUser.userId가
DB에 있는 경우 “준영속”
영속성 컨텍스트
● 쓰기 지연 SQL
● 자동 변경 감지
● 1차 캐시
● 엔티티 동일성
● 지연 로딩
영속성 컨텍스트는 어떻게 동작할까?
@Entity@Table(name = "User")public class User {
@Id @GeneratedValueprivate Integer userId;
@Column(name = "name", nullable = true)private String name;
@Column(name = "password", nullable = true)private String password;
@Column(name = "nickName", nullable = true)private String nickName;
}
입력(persist)
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 비 영속 상태User user = new User("wons", "12345", "woniper");
// 영속 상태 // 1차 캐시 저장em.persist(user);
// 준영속 상태// SQL 저장소 쿼리 반영em.getTransaction().commit();em.close();
조회(find)
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 영속 엔티티// 1차 캐시 저장User user = em.find(User.class, user.getUserId());
// 준영속 상태em.getTransaction().commit();em.close();
수정(자동 변경 감지)
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 영속 상태// 1차 캐시 저장User user = em.find(User.class, user.getUserId());
// 자동 변경 감지user.setName("updateName");user.setPassword("1111");user.setNickName("updateNick");
// 준영속 상태// SQL 저장소 쿼리 반영em.getTransaction().commit();em.close();
삭제(remove)
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 영속 상태, 1차 캐시 저장User user = em.find(User.class, user.getUserId());
// 삭제 상태em.remove(user);
// SQL 저장소 쿼리 반영em.getTransaction().commit();em.close();
지금까지 모든 일은 트랜젝션
작업 단위에서 동작
사실 commit은
EntityManager.flush()를 먼저 호출
flush()는 영속성 컨텍스트와 DB를 동기화
merge
준 영속 엔티티 -> 영속 엔티티
merge를 알아보기 전에
영속 엔티티 -> 준 영속 엔티티
● em.clear();
● em.detach(user);
● em.getTransaction().commit();
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 1. 영속 상태User user1 = em.find(User.class, 1);// 2. 준영속 상태em.detach(user1);// 3. name 속성 변경user1.setName("lee-kyung-won");// 4. 영속 상태em.merge(user1);
em.getTransaction().commit();em.close();
EntityManager em = emf.createEntityManager();em.getTransaction().begin();
// 5. name 속성 값은?User user2 = em.find(User.class, 1);
em.getTransaction().commit();em.close();
● 속성이 변경된 준영속 엔티티 merge : update
● 비영속 엔티티 merge : insert
즉 merge는 영속 엔티티로 만들기도 하지
만
update 또는 insert 하기도 함
준 영속 상태는 영속성 컨텍스트
특징을 사용하지 못하는 것
● 쓰기 지연 SQL
● 자동 변경 감지
● 1차 캐시
● 엔티티 동일성
● 지연 로딩
Spring Data JPA
소개 정도만 할게요.
@Entity@Table(name = "User")public class User {
@Id @GeneratedValue private Integer userId;
@Column(name = "name", nullable = true) private String name;
@Column(name = "password", nullable = true) private String password;
@Column(name = "nickName", nullable = true) private String nickName;}
Repository Interface
public interface UserRepository extends JpaRepository<User, Integer> {}
Repository 만 추가 하면
● save(T);● delete(T);● findOne(ID);● findAll();● findAll(Pageable);
CRUD 그 외 조회 Query가
필요하다면?
method 이름으로 Query생성
정확히 말하면 JPQL 생성
물론 규칙을 지켜 method 이름 설정
public interface UserRepository extends JpaRepository<User, Integer> {
// where u.name = ?nameUser findByName(String name);
// where u.name = ?name and u.password = ?password;User findByNameAndPassword(String name, String password);
}
참고자료
● http://www.tutorialspoint.com/jpa/● http://www.objectdb.com/● https://en.wikibooks.
org/wiki/Java_Persistence
● http://goo.gl/xzpTdK● https://goo.gl/sqmO9p● https://goo.gl/GhsI4Q● https://goo.gl/GpQzeL
QnA