▼ Backend/스프링 (Spring)
Spring Boot | JPA + lombok 사용하기
Valar
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
반응형