Spring Data JPA 가 나오기 전에는 순수 JPA를 이용하여 프로젝트를 진행했다.
자 봐라! DataJPA를 사용하지 않고
public static void main(String[] args) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("Factory");
// db connection
EntityManager manager = factory.createEntityManager();
EntityTransaction transaction = manager.getTransaction();
// 트랜잭션 시작
transaction.begin();
try {
Member member = new Member();
member.setUsername("Steven Gerrard");
manager.persist(member); // db 저장
Member findMember = manager.find(Member.class, member.getId()); // select 쿼리
System.out.println(findTeam.getName());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
manager.close();
factory.close();
}
}
실제로는 다음처럼 Repositorty를 선언하고 특정 기능들은 Repository에서 구현했다.
먼저 CRUD를 구현하기 위해 데이터 접근 계층인 Repository를 먼저 만든다.
특정 유저를 찾는 기능을 구현해보자
쿼리문을 이용해서 DB에 접근하여 해당 정보만 추출하는 방식을 이용한다.
@Repository
public class MemberRepository {
@PersistenceContext;
EntityManager em;
public void save(Member member) {
em.persist(member);
}
public void findByName(String name) {
return em.createQuery("SELECT m FROM Member m WHERE m.name = :name", Member.class)
.setParameter("name", name)
.getResult();
}
}
나같이 게으른 사람들을 위해 매번 같은 함수를 생성하기 귀찮아서 해당 기능을 제공하기 위해 Spring Data JPA가 탄생했따아아아!
그래서 기존 기능은 쿼리문을 날려서 값을 받아왔지만 JPQL ( 일단 JPA 에서 사용한 Query라고 생각하자 - 차후에 이 내용은 따로포스팅 하도록 하겠다.)
사용은 JpaRepository 인터페이스를 상속 받으면 된다.
그래서 아래와 같은 기능을 제공한다.
- findAll() : 해당 엔티티 테이블에 있는 모든 데이터를 조회한다.
- save() : 대상 엔티티를 DB에 저장한다.
- saveAll() : Iterable 가능한 객체를 저장한다.
- delete() : 데이터베이스에서 대상 엔티티를 삭제한다.
이외에도 더 많은 기능들이 존재하는데, JpaRepository 는 아래와 같이 다양한 기능이 정의된 인터페이스를 상속 받게 되는데, 이 인터페이스들 덕분에 우리는 단순 CRUD 외에 다양한 기능(Paging, Sorting)을 수행할 수 있다.
이걸 사용하기 위해 인터페이스의 계층 구조를 알아보자.
위에서 언급한 상속을 실제 코드와 함께 보자
public interface UserRepository extends JpaRepository<User, Long>{
}
위와 같이 제네릭 타입으로 지정한다.
데이터 생성, 조회 기능을 구현해보자.
User.class
엔티티 클래스
UserRepository.interface
데이터 접근 계층인 Repository 인터페이스
SpringDataJpa 의 힘을 빌리기 위해 JpaRepository를 상속 받는다.
UserRepositoryTest.class
조회 쿼리를 테스트할 테스트 클래스
이 3개를 구현해보자
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
}
@GeneratedValue(strategy = GenerationType.IDENTITY) 는 해당 id가 자동으로 생성해주는 어노테이션이라고 이해하면 된다.
위에서 계속 말한 JpaRepository 를 상속 받자.
public interface UserRepository
extends JpaRepository<User, Long{}
@SpringBootTest
@Transactional
@Rollback(false)
class UserRepositoryTest {
@Autowired
UserRepository userRepository;
@Test
void querySingleRowTest() {
// given
List<User> generatedUsers = generateUsersForTest();
userRepository.saveAll(generatedUsers);
// when
Optional<User> selectedUser = userRepository.findById(1L);
// then
assertEquals(selectedUser.get().getId(), 1L);
}
@Test
void queriesMultipleRowTest() {
// given
List<User> generatedUsers = generateUsersForTest();
userRepository.saveAll(generatedUsers);
// when
List<User> selectedAllUsers = userRepository.findAll();
// then
selectedAllUsers.forEach(selectedUser -> {
System.out.println(selectedUser.toString());
});
// then 혹은
assertAll(
() -> assertEquals(selectedAllUsers.get(0).getId(), 1L),
() -> assertEquals(selectedAllUsers.get(1).getId(), 2L),
() -> assertEquals(selectedAllUsers.get(10).getId(), 11L)
);
}
List<User> generateUsersForTest() {
List<User> users = new ArrayList<>();
for (long i = 1; i < 40; i++) {
User user = User.builder().id(i).username("사용자 " + i).build();
users.add(user);
}
return users;
}
}
이와 같이 테스트할 수 있겠다.
아래 포스팅을 가져온 것입니다.
다음 포스팅은 JPA, ORM 내용을 다뤄보겠습니다.
Reference
https://wonit.tistory.com/469