Spring boot JPA (1) - JPA Annotations

임쿠쿠·2022년 2월 1일
0

SpringBoot

목록 보기
5/6
post-thumbnail

0. setting for dependency

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.springjpa</groupId>
	<artifactId>spring-data-jpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-data-jpa</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

1. Different JPA Annotations

Entity

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(
        name = "tbl_student",
        uniqueConstraints = @UniqueConstraint(
                name = "emailid_unique",
                columnNames = "email_address"
        )
    ) - (1)
public class Student {

    @Id
    @SequenceGenerator(
            name = "student_sequence",
            sequenceName = "student_sequence",
            allocationSize = 1
    ) - (2)
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "student_sequence"
    ) - (3)
    private Long studentId;
    private String firstName;
    private String lastName;

    @Column(
            name = "email_address",
            nullable = false
    ) - (4)
    private String emailId;
    private String guardianName;
    private String guardianEmail;
    private String guardianMobile;
}

(1) @Table

  • table명 / unique 컬럼 설정

(2) @SequenceGenerator

  • 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트 이다.
  • 주로 Oracle, PostgreSQL, H2 등에서 사용한다.
  • 엔티티를 persist 하는 시점에 데이터베이스 INSERT SQL 을 날리지 않고, 시퀀스 값만 얻어 영속성 컨텍스트에 저장한 뒤 트랜잭션 커밋시점에 INSERT SQL 을 날린다.
  • 엔티티 별로 시퀀스를 별도로 관리하고 싶다면 @SequenceGenerator 를 사용해야 한다.

name : 식별자 생성기의 이름 (필수)
sequenceName : 데이터베이스에 등록된 시퀀스 명 (DEFAULT: hibernate_sequence)
initialiValue : 시퀀스의 시작값, 최초 생성시에 사용된다. (DEFAULT: 1)
allocationSize : 시퀀스 호출시마다 증가하는값, 성능최적화에 사용되며 데이터베이스 시퀀스값이 1 씩 증가한다면 반드시 1로 지정해야한다.

(3) @GeneratedValue

  • @GeneratedValue 애노테이션을 통해 strategy 속성을 GenerationType.SEQUENCE로 하여 식별자를 할당하는 전략을 시퀀스 방식으로 하겠다는 설정과, 식별자를 생성해줄 식별자 생성기를 student_sequence로 사용하겠다는 설정을 generator 속성을 통해 설정한다.

(4) @Column

  • Column명 설정 및 not null 적용

2. Understanding Repositories and their methods

Repository

테스팅

@Repository
// generic에 엔티티와 PK의 타입 지정
public interface StudentRepository extends JpaRepository<Student, Long> {

}
@SpringBootTest
//@DataJpaTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void saveStudent() {
        Student student = Student.builder() - (1)
                .emailId("test@gmail.com")
                .firstName("lim")
                .lastName("jisub")
                .guardianName("Heedo")
                .guardianEmail("heedo@gmail.com")
                .guardianMobile("01012345678")
                .build();

        studentRepository.save(student);
    }

    @Test
    public void printAllStudent() {
        List<Student> studentList =
                studentRepository.findAll();
        System.out.println("studentList = " + studentList);
    }
}

(1) Builder pattern
참고 : https://mangkyu.tistory.com/163

3. @Embeddable and @Embedded

Entity

Guardian CLASS

@Embeddable - (1)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@AttributeOverrides({
        @AttributeOverride(
                name = "name",
                column = @Column(name = "guardian_name")
        ),
        @AttributeOverride(
                name = "email",
                column = @Column(name = "guardian_email")
        ),
        @AttributeOverride(
                name = "mobile",
                column = @Column(name = "guardian_mobile")
        )
}) - (2)
public class Guardian {

    // student 테이블에서만 사용하기
    // 컬럼명 변경
    private String name;
    private String email;
    private String mobile;
}
STUDENT CLASS

public class Student {

	...
    // private String guardianName;
    // private String guardianEmail;
    // private String guardianMobile;
    
    // Embeding
     @Embedded - (3)
    private Guardian guardian;
}

(1) @Embeddable - 기존 Entity의 특정 컬럼들을 하나의 객체로 묶는다.
(2) @AttributeOverrides - 기존 Entity와 컬럼 명이 같을 시, @AttributeOverride 속성을 통해 해당 컬럼의 컬럼명을 오버라이드 한다.
(3) @Embedded - Guardian 객체로 컬럼 설정

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void saveStudentWithGuardian() {
        Guardian guardian = Guardian.builder()
                .name("Heedo1")
                .email("heedo1@gmail.com")
                .mobile("01012345678")
                .build();


        Student student = Student.builder()
                .emailId("test1@gmail.com")
                .firstName("lim1")
                .lastName("jisub1")
                .guardian(guardian)
                .build();

        studentRepository.save(student);
    }
}

4. Creating JPA Repositories & methods

Repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    // camelCase 적용
    List<Student> findByFirstName(String firstName);

    // Like 적용
    List<Student> findByFirstNameContaining(String name);

    List<Student> findByLastNameNotNull();

    List<Student> findByGuardianName(String guardianName);

    Student findByFirstNameAndLastName(String firstName,
                                       String lastName);
}

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

     @Test
    public void  printStudentByFirstName() {
        List<Student> students =
                studentRepository.findByFirstName("lim1");
        System.out.println("students = " + students);
    }

    @Test
    public void  printStudentByFirstNameContaining() {
        List<Student> students =
                studentRepository.findByFirstNameContaining("li");
        System.out.println("students = " + students);
    }

    @Test
    public void  printStudentBasedOnGuardianName() {
        List<Student> students =
                studentRepository.findByGuardianName("Heedo1");
        System.out.println("students = " + students);
    }

    @Test
    public void  printStudentFindByFirstNameAndLastName() {
        Student students =
                studentRepository.findByFirstNameAndLastName("lim1", "jisub1");
        System.out.println("students = " + students);
    }
}

5. @Query Annotation

Repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    // JPQL
    @Query("select s from Student s where s.emailId = ?1")
    Student getStudentByEmailAddress(String EmailId);

    @Query("select s.firstName from Student s where s.emailId = ?1")
    String getStudentFirstNameByEmailAddress(String EmailId);
}

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void  printStudentByEmailAddress() {
        Student student =
                studentRepository.getStudentByEmailAddress("test1@gmail.com");
        System.out.println("student = " + student);
    }

    @Test
    public void  printStudentFirstNameByEmailAddress() {
        String firstName =
                studentRepository.getStudentFirstNameByEmailAddress("test1@gmail.com");
        System.out.println("firstName = " + firstName);
    }
}

6. Native Queries

Repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    // Native
    @Query(
            value = "select * from tbl_student s where s.email_address = ?1",
            nativeQuery = true
    )
    Student getStudentByEmailAddressNative(String emailId);
}

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void  printGetStudentByEmailAddressNative() {
        Student student =
                studentRepository.getStudentByEmailAddressNative("test1@gmail.com");
        System.out.println("student = " + student);
    }
}

7. Query Named Params

Repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    // Native Named Param
    @Query(
            value = "select * from tbl_student s where s.email_address = :emailId",
            nativeQuery = true
    )
    Student getStudentByEmailAddressNativeNamedParam(@Param("emailId") String emailId);
}

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void  printGetStudentByEmailAddressNativeNamedParam() {
        Student student =
                studentRepository.getStudentByEmailAddressNativeNamedParam("test1@gmail.com");
        System.out.println("student = " + student);
    }
}

8. @Transactional and @Modifying Annotation

Repository

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    @Modifying // @Query Annotation으로 작성 된 변경, 삭제 쿼리 메서드를 사용할 때 필요
    @Transactional // 트랜잭션 처리
    @Query(
            value = "update tbl_student set first_name = ?1 where email_address = ?2",
            nativeQuery = true
    )
    int updateStudentNameByEmailId(String firstName, String emailId);
}

테스팅

@SpringBootTest
class StudentRepositoryTest {

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void updateStudentNameByEmailIdTest() {
        studentRepository.updateStudentNameByEmailId("lim33", "test1@gmail.com");
    }
}

참고
Spring Data JPA Tutorial | Full In-depth Course - Daily Code Buffer
https://ncucu.me/191
https://dololak.tistory.com/479

profile
Pay it forward

0개의 댓글