Today
-
Yesterday
-
Total
-

ABOUT ME

-

  • Spring Boot | JPA + lombok 사용하기
    ▼ Backend/스프링 (Spring) 2021. 7. 19. 21:50
    반응형

    ▶ JPA, 자바 지속성 API (Java Persistence API)

    자바 플랫폼 SE와 자바 플랫폼 EE를 사용하는 응용프로그램에서 관계형 데이터베이스의 관리를 표현하는 Java API이다.

     

    ▶ lombok(https://projectlombok.org/)

    getter, setter 등의 반복 메서드를 자동으로 연결하고 도구를 빌드하여 Java를 향상시키는 Java 라이브러리이다.

     

    테이블 생성 member with mariaDB

    CREATE TABLE member (
    	MBR_SEQ BIGINT(20) NOT NULL AUTO_INCREMENT,
    	ID VARCHAR(200) NULL DEFAULT NULL,
    	PWD VARCHAR(200) NULL DEFAULT NULL,
    	NAME VARCHAR(200) NULL DEFAULT NULL,
    	ADDR_LOAD VARCHAR(300) NULL DEFAULT NULL,
    	REG_ID VARCHAR(200) NULL DEFAULT NULL,
    	REG_DTM DATETIME NULL DEFAULT NULL,
    	MOD_ID VARCHAR(200) NULL DEFAULT NULL,
    	MOD_DTM DATETIME NULL DEFAULT NULL,
    	PRIMARY KEY (MBR_SEQ) USING BTREE
    )

     

    1. Dependency 추가 (jpa, lombok, mariadb)

    Maven의 경우 pom.xml에 추가

     

    <!-- JPA -->
    <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-data-jpa</artifactId> 
    </dependency>
    <!-- JPA -->
    
    <!-- lombok -->
    <dependency> 
      <groupId>org.projectlombok</groupId> 
      <artifactId>lombok</artifactId> 
      <optional>true</optional> 
    </dependency>
    <!-- lombok -->
    
    <!-- MariaDB --> 
    <dependency> 
      <groupId>org.mariadb.jdbc</groupId> 
      <artifactId>mariadb-java-client</artifactId> 
    </dependency> 
    <!-- MariaDB -->

     

     

    gradle의 경우 build.gradle에 추가

     

    dependencies {
        //Jpa
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        //lombok
        implementation 'org.projectlombok:lombok'
        //mariaDB
        implementation 'org.mariadb.jdbc:mariadb-java-client'
    }

     

    2. 데이터베이스 설정

    application.properties

     

    spring.datasource.driverClassName=org.mariadb.jdbc.Driver
    spring.datasource.url=jdbc:mariadb://localhost:3306/database
    spring.datasource.username=user
    spring.datasource.password=pwd!@#

     

    application.yml

     

    spring:
      datasource:
        driverClassName: org.mariadb.jdbc.Driver
        url: jdbc:mariadb://localhost:3306/database
        username: user
        password: pwd!@#

     

    3. 재사용될 컬럼을 추상 클래스로 작성

    CommonVo.java

     

    import java.time.LocalDateTime;
    import javax.persistence.Column;
    import javax.persistence.MappedSuperclass;
    import org.hibernate.annotations.CreationTimestamp;
    import lombok.Data;
    
    //Getter, Setter Auto Create
    @Data
    //공통 매핑 정보가 필요할 때, 부모 클래스에 선언하고 속성만 상속 받아서 사용하고 싶을 때 사용한다.
    @MappedSuperclass
    public abstract class CommonVo {
    
        // register id
        private String regId;
    
        // modify id
        private String modId;
    
        // register Date time
        @CreationTimestamp
        /* 보통 JPA는 SAVE시에 모든 칼럼을 INSERT한다.
        그럴 경우, NOT NULL로 설정된 칼럼은 기본값으로 삽입되는것이 아닌 NULL로 삽입을 시도한다.
        이로 인해 에러가 발생하는데, 이럴 경우에 아예 쿼리에서 빼버려서 실행이 안되게 만들 수 있다.
        쿼리에서 제외된 칼럼은 DB에 지정된 default값으로 삽입이 된다.
        특정 칼럼을 제외하고 save하는 방법은 다음과 같다. insertable = false, updatable = false*/
        @Column(updatable = false)
        private LocalDateTime regDtm;
    
        // modify Date time
        @CreationTimestamp
        private LocalDateTime modDtm;
    }

     

    4. CommonVo를 상속받은 MemberVo 작성

    MemberVo.java

     

    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import com.melon.boot.common.vo.CommonVo;
    import lombok.Data;
    
    //Getter, Setter Auto Create
    @Data
    //Table Mapping
    @Entity(name = "member")
    public class MemberVo extends CommonVo {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long mbrSeq;
        private String id;
        private String pwd;
        private String name;
        private String addrLoad;
    }

     

    5. JpaRepository를 상속받은 interface 작성

    MemberRepository.java

     

    package com.melon.boot.member.service.repository;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import com.melon.boot.member.vo.MemberVo;
    
    public interface MemberRepository extends JpaRepository<MemberVo, Long> {
    }

     

    6. Service Class 작성

    MemberService.java

     

    import java.util.List;
    import java.util.Optional;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import com.melon.boot.member.service.repository.MemberRepository;
    import com.melon.boot.member.vo.MemberVo;
    
    @Service
    public class MemberService {
    
        @Autowired
        private MemberRepository memberRepository;
    
        /* INSERT */
        public MemberVo save(MemberVo memberVo) throws Exception {
            return memberRepository.save(memberVo);
        }
    
        /* SELECT LIST */
        public List < MemberVo > findAll() throws Exception {
            return memberRepository.findAll();
        }
    
        /* SELECT BY ID */
        public Optional < MemberVo > findById(Long mbrSeq) throws Exception {
            return memberRepository.findById(mbrSeq);
        }
    
        /* UPDATE */
        public MemberVo updateById(MemberVo memberVo) throws Exception {
    
            Optional < MemberVo > e = memberRepository.findById(memberVo.getMbrSeq());
    
            MemberVo resultMember = null;
    
            if (e.isPresent()) {
                resultMember = memberRepository.save(memberVo);
            }
    
            return resultMember;
        }
    
        /* DELETE */
        public void deleteById(Long mbrSeq) throws Exception {
            memberRepository.deleteById(mbrSeq);
        }
    }

     

    7. Controller Class 작성

    테스트용으로 하드코딩 샘플 데이터가 들어가 있으니, 화면을 작성하고 실제로 사용할 때에는 샘플 데이터를 지우고 객체를 받아 사용한다.

     

    MemberController.java

     

    import java.time.LocalDateTime;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import com.melon.boot.member.service.MemberService;
    import com.melon.boot.member.vo.MemberVo;
    
    @Controller
    @RequestMapping("/member")
    public class MemberController {
    
        @Autowired
        MemberService memberService;
    
        @GetMapping("/insert")
        public void insertMember() throws Exception {
            try {
                MemberVo memberVo = new MemberVo();
    
                memberVo.setId("tester");
                memberVo.setPwd("pwd123!@#");
                memberVo.setName("tom");
                memberVo.setAddrLoad("seoul city");
                memberVo.setRegId("reg_id");
                memberVo.setModId("mod_id");
    
                memberService.save(memberVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @GetMapping("/selectList")
        public void selectMemberList() throws Exception {
            try {
                memberService.findAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @GetMapping("/select")
        public void selectMember() throws Exception {
            try {
                memberService.findById((long) 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @GetMapping("/update")
        public void updateMember() throws Exception {
            try {
                MemberVo memberVo = new MemberVo();
    
                memberVo.setMbrSeq((long) 1);
                memberVo.setId("update tester");
                memberVo.setPwd("update pwd123!@#");
                memberVo.setName("update name");
                memberVo.setAddrLoad("update seoul city");
                memberVo.setRegId("update reg_id");
                memberVo.setModId("update mod_id");
                memberVo.setModDtm(LocalDateTime.now());
    
                memberService.updateById(memberVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @GetMapping("/delete")
        public void deleteMember(MemberVo memberVo) throws Exception {
            try {
                memberService.deleteById((long) 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

     

    8. 테스트 URL

    • /member/insert
    • /member/selectList
    • /member/select
    • /member/update
    • /member/delete

    쿼리 실행 로그를 콘솔에 출력

    application.properties

     

    #쿼리 로그 설정
    spring.jpa.show-sql=true 
    
    #SQL문을 보기 좋게 출력
    spring.jpa.properties.hibernate.format_sql=true
    
    #바인딩되는 파라미터 값 출력
    logging.level.org.hibernate.type.descriptor.sql=trace

     

    application.yml

     

    spring:
      jpa: 
        show-sql: true #쿼리 로그 설정
        properties: 
          hibernate: 
            format_sql: true #SQL문을 보기 좋게 출력
    logging: 
      level:
        org: 
          hibernate: 
            type: 
             descriptor:
              sql: trace #바인딩되는 파라미터 값 출력

     

     

     

    그 외에 이름 안에서 지원되는 키워드

     

    And			findByLastnameAndFirstname	… where x.lastname = ?1 and x.firstname = ?2
    Or			findByLastnameOrFirstname	… where x.lastname = ?1 or x.firstname = ?2
    Is,Equals		findByFirstname,findByFirstnameIs,findByFirstnameEquals	… where x.firstname = 1?
    Between			findByStartDateBetween	… where x.startDate between 1? and ?2
    LessThan		findByAgeLessThan	… where x.age < ?1
    LessThanEqual		findByAgeLessThanEqual	… where x.age ⇐ ?1
    GreaterThan		findByAgeGreaterThan	… where x.age > ?1
    GreaterThanEqual	findByAgeGreaterThanEqual	… where x.age >= ?1
    After			findByStartDateAfter	… where x.startDate > ?1
    Before			findByStartDateBefore	… where x.startDate < ?1
    IsNull			findByAgeIsNull	… where x.age is null
    IsNotNull,NotNull	findByAge(Is)NotNull	… where x.age not null
    Like			findByFirstnameLike	… where x.firstname like ?1
    NotLike			findByFirstnameNotLike	… where x.firstname not like ?1
    StartingWith		findByFirstnameStartingWith	… where x.firstname like ?1(parameter bound with appended %)
    EndingWith		findByFirstnameEndingWith	… where x.firstname like ?1(parameter bound with prepended %)
    Containing		findByFirstnameContaining	… where x.firstname like ?1(parameter bound wrapped in %)
    OrderBy			findByAgeOrderByLastnameDesc	… where x.age = ?1 order by x.lastname desc
    Not			findByLastnameNot	… where x.lastname <> ?1
    In			findByAgeIn(Collection<Age> ages)	… where x.age in ?1
    NotIn			findByAgeNotIn(Collection<Age> age)	… where x.age not in ?1
    True			findByActiveTrue()	… where x.active = true
    False			findByActiveFalse()	… where x.active = false
    IgnoreCase		findByFirstnameIgnoreCase	… where UPPER(x.firstame) = UPPER(?1)

     

     

    직접 쿼리를 작성하여 사용할 경우 @Query 어노테이션을 사용한다.

     

    // 트랜잭션
    @Transactional
    // @Modifying 어노테이션은 @Query 어노테이션으로 작성된 수정, 삭제 쿼리 메소드를 사용할 때 필요하다. 
    // 조회 쿼리를 제외하고 데이터에 변경이 일어나는 INSERT, UPDATE, DELETE 쿼리에서 사용한다.
    @Modifying
    @Query(value="UPDATE MEMBER SET PWD=:#{#memberVo.pwd} WHERE MEM_SEQ = :#{#memberVo.seq}", nativeQuery = true)
    public int updateMemberPwd(MemberVo memberVo);

     


     

    프로젝트 Export Archive File

    melon.zip
    0.11MB

     

    프로젝트 import, export
     

    Spring Boot | 프로젝트 import, export

    import export

    kitty-geno.tistory.com

     

    Reference
    https://spring.io/projects/spring-data-jpa
    반응형

    댓글

Designed by Tistory.