본문 바로가기
Spring Boot (프로젝트)

스프링부트와 mySQL 연결

by Hoozy 2023. 3. 5.

이전 게시글 프로젝트 시작

https://hoozy.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91

 

[스프링 부트] 프로젝트 시작

국비 학원에서는 스프링 프레임워크와 오라클, 마이바티스, jquery를 했기 때문에 이제는 스프링 부트, mySql, 스프링 JPA, thymeleaf를 활용해 개인프로젝트를 하나 하려고 합니다. 비전공자이기 때문

hoozy.tistory.com

mySQL을 처음 써봐서 그런지 ORACLE보단 설정이 복잡해 보였다.

하지만, 스프링부트 설정은 스프링 프레임워크와 다르게 간편했다.

mySQL 설치와 스프링부트 연동

https://gyuwon95.tistory.com/167

먼저 스프핑부트가 스프링과 다른 점은

  1. 간편한 설정
  2. 편리한 의존성 관리 & 자동 권장 버전 관리
  3. 내장 서버로 인한 간단한 배포 서버 구축
  4. 스프링 Security, Data JPA 등의 다른 스프링 프레임워크 요소를 쉽게 사용할 수 있다.

여기서 사용할 JPA란?

https://hoozy.tistory.com/entry/JAVA-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC

 

[JAVA] 프레임워크

이전 게시글 JAVA 심화 2 https://hoozy.tistory.com/entry/JAVA-%EC%8B%AC%ED%99%94-2 카테고리 : 자바(프레임워크) 웹 애플리케이션을 만들고 유지하는데 사용되는 강력한 오픈소스 JAVA 프레임워크는 2가지가 있

hoozy.tistory.com

build.gradle 파일 추가

implementation 'mysql:mysql-connector-java:8.0.32' // 버전이 안들어갔을 때 에러가 뜰 경우 현재 mysql의 버전을 넣으면 된다.
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

MySQL application.yml 설정

server:  
address: localhost  
port: 8005  
servlet:  
encoding:  
charset: UTF-8  
enabled: true  
force: true

// 주소와 포트 http 인코딩 설정.

spring:  
datasource:  
driver-class-name: com.mysql.cj.jdbc.Driver  
url: jdbc:mysql://localhost:3306/{schema_name}?createDatabaseIfNotExist=true%useUnicode=true&serverTimezone=Asia/Seoul  
username: {username}  
password: {password}

// mySQL 기본 설정.

jpa:  
database: mysql  
show-sql: true  
hibernate:  
ddl-auto: update  
properties:  
hibernate:  
show\_sql: true  
format\_sql: true
  • ddl-auto 란?
    • create : 프로그램 시작할 때 스키마 drop 후 생성
    • none : 아무것도 안함
    • update : 변경된 스키마만 적용
    • create-drop : 프로그램 시작할 때 스키마 drop 후 생성 후 종료할 때 drop
    • validate : 엔티티와 테이블 정상 매핑 확인

JPA 사용법

JPA 객체 생성 방법

  • 객체 생성 방법에는 생성자, 정적 팩토리 메소드, Builder 패턴 3가지가 있다.
  • 엔티티 상황에 따라서 이 중 한가지를 선택하고, 파라미터에 객체 생성에 필요한 데이터를 다 넘기는 방법을 사용한다.
  • 정적 팩토리 메소드와 Builder 패턴을 사용할 때는 셍상자를 private 처리를 하는데 JPA가 사용하려면 protected로 처리해야 한다.
  • 객체 생성이 간단하면 단순 생성자를 이용하지만, 의미가 있거나 복잡하면 나머지 방법이 좋다.
  • @Setter를 지양한다.
    • 엔티티를 만들 때는 외부에서 값을 쉽게 변경할 수 없게 @Setter를 사용하지 않는다.
    • Setter는 의도가 분명하지 않고, 변경하면 안되는 중요한 값임에도 변경가능한 값으로 착각할 수 있다.(안정성 보장X)
    • 이때에는 Setter와 같은 기능을 하는 메소드를 만들면 된다.
public void setName(String name) {
    this.name = name;
}

public void changeName(String name) {
    this.name = name;
}

1. 생성자

public Member(Long id, String name) {
    this.id = id;
    this.name = name;
}

2. 정적 팩토리 메소드

// Setter 메소드를 고친 정적 팩토리 메소드
public static Member createMember(Long id, String name) {
    Member member = new Member();
    member.changeId(id);
    member.changeName(name);
    return member;
{
  • 여기서 외부에서 생성할 수 없는 private 생성자를 생성하여 값을 변경하여 반환한다?
  • 이런 상황에서는 사실상 객체를 생성할 때 Setter 메소드를 사용한거나 다름이 없다.
  • Member를 생성할 때 id와 name 값을 파라미터로 넘겨줘서 3가지 생성 방법 중 하나로 생성하면 Setter 메소드를 제거할 수 있다.
  • 즉, 생성 시점에서 전부 끝낼 수 있다.
// Setter를 제거한 정적 팩토리 메소드 1
public static Member createMember(Long id, String name) {
    return new Member(id, name);
}

// Setter를 제거한 정적 팩토리 메소드 2
public static Member createMember(Long id, String name) {
    return Member.builder()
            .id(id)
            .name(name)
            .build();
}

@Builder
public Member(Long id, String name) {
    this.id = id;
    this.name = name;
}

3. Builder 패턴

// Builder 패턴
@Builder
public Member(Long id, String name) {
    this.id = id;
    this.name = name;
}
  • 위에 패턴은 생성자와 비슷하지만, 매개변수가 많아질수록 힘들어지게 된다.
  • 이럴 경우 점층적 생성자 패턴을 쓰게 된다.
  • 예를 들면 필수 매개변수 id, name 과 선택 매개변수 city, street가 있다면,
public Member(Long id, String name) {
    this.id = id;
    this.name = name;
}

public Member(Long id, String name, String city) {
    this.id = id;
    this.name = name;
    this.city = city;
}

public Member(Long id, String name, String city, String street) {
    this.id = id;
    this.name = name;
    this.city = city;
    this.street = street;
}
  • 이렇게 선택 매개변수가 없는 생성자부터 선택 매개변수를 전부 받는 생성자까지 늘려나가는 방식을 점층적 생성자 패턴이라고 한다.
  • 이 경우 street를 넣기 위해 city도 넣어줘야 하는 불편함이 생긴다. 즉, 원하지 않는 매개변수까지 값을 생성해야 한다.
  • 이럴때 다른 디자인 패턴인 자바빈즈 패턴을 사용할 수 있다.
// 자바빈즈 패턴
Member member = new Member();
member.setId(id);
member.setName("이름");
member.setCity("시티");
member.setStreet("스트릿");
  • 하지만 이 패턴은 함수 호출 한 번으로 객체 생성을 끝내지 못하고 여러번 메소드를 호출해야한다.
  • 따라서 객체 일관성이 깨진다 -> 불변성 객체를 만들 수 없다는 단점이 생긴다.

위 두가지 패턴의 단점을 보완한 것이 빌더 패턴이다.

  • 점층적 생성자 패턴의 안전성 과 자바빈즈 패턴의 가독성을 합친 빌더 패턴이다.
@Builder
public class Member {
    private Long id; // 필수
    private String name; // 필수

    @Builder.Default
    private String city = "city"; // 선택
    @Builder.Default
    private String street = "street"; // 선택
}
  • @Builder 어노테이션은 class와 생성자 위치에 따라 차이점이 있다.
  • 위 코드처럼 class 위치에 쓴다면 @AllArgsConstructor 를 붙인 것과 같은 효과이다.
    • @AllArgsConstructor : 모든 필드에 대한 매개변수를 받는 기본 생성자를 만든다는 것이다.
    • 즉, 위에선 id, name, city, street 4가지의 모든 매개변수로 한 생성자가 생성된다는 것이다.
  • 만약 id가 자동으로 숫자가 매겨지는 필드(숫자형 PK)라면 좋지 않으므로 매개변수를 최소화 해주는 것이 좋다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
    private Long id;
    private String name;
    private String city = "city";
    private String street = "street";

    @Builder(builderMethodName = "createMember")
    public Member(String name, String city, String street) {
        this.name = name;
        this.city = city;
        this.street = street;
    }
}
  • @NoArgsConstructor(access = AccessLevel.PROTECTED) 로 기본 생성자 접근 제한자를 protected로 바꿔준다.
    • 외부에서 개발자는 직접 호출 못하지만 JPA가 접근 가능하게 만들어 주는 것이다.
  • 최종적으로 위와 같이 기본 생성자를 제한해주고, Class위가 아닌 생성자에 @Builder 를 붙여주는 것이 좋다.
  • @Builder 속성인 builderMethodName 을 지정하여 해당 Builder의 이름을 부여하여 쓸 수 있다.
// @Builder 패턴 - 생성자 호출
Member member = new createMember()
        .name("이름")
        .city("시티")
        .street("스트릿")
        .build();

빌더 패턴에서 제일 중요한 것은 생성자에 파라미터를 넘겨서 변경이 필요없는 객체를 생성하는 것이 핵심이다.

JPA 어노테이션 종류

객체와 테이블 매핑

  1. @Entity
    • 데이터베이스의 테이블과 1:1로 매칭되는 객체 단위이며, Entity 객체의 인스턴스 하나가 테이블에서 하나의 레코드 값을 의미하며 테이블과 매핑할 클래스에 필수로 붙여줘야한다.
    • 그래서 객체의 인스턴스를 구분하기 위한 유일한 키값을 가지는데 이것은 테이블 상의 Primary Key와 같은 의미를 가지며 @Id 어노테이션으로 표기된다.
    • name 을 설정하지 않으면 클래스 이름을 그대로 사용한다. -> 테이블 명과 같으면 name 쓸 필요 없다.
@Entity
@Table(name = "tbl_member")
public class Member {
    ...
}
- 주의 사항
    1. 기본 생성자는 필수다.
    2. final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
    3. 저장할 필드에 final을 사용하면 안된다.
  1. @Table
    • name : 매핑할 테이블 이름
    • catalog : catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다.
    • schema : schema 기능이 있는 데이터베이스에서 schema를 매핑한다.
      • MySQL에서는 table 과 schema 와 같은 의미이지만, Oracle에서는 schema를 table의 집합, database를 schema의 집합인 의미이다.
    • uniqueConstraints(DDL) : DDL 생성 시에 유니크 제약조건을 만든다. 2개 이상의 복합 유니크 제약조건도 만들 수 있다. 이 기능은 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용된다.

기본 키 매핑

  1. @Id
    • Entity 클래스 상에 PK를 명시적으로 표시해야 하는데 그것을 이 이노테이션을 이용해 이것이 PK임을 지정한다.
    • ddl-auto 속성이 create로 되어 있고, 아직 해당 테이블이 데이터베이스 상에 존재하지 않는다면 EntityManager가 DDL을 통해 테이블을 생성하면서 PK를 같이 생성해 준다.
  • @GeneratedValue
    • PK 컬럼의 데이터 형식은 정해져 있지는 않으나 구분이 가능한 유일한 값을 가지고 있어야하고, 데이터 경합으로 인해 발생되는 데드락 같은 현상을 방지하기 위해 대부분 BigInteger 즉 JAVA의 Long을 주로 사용한다.
      • 데드락 : 동일한 시점에 요청이 유입되었을 때 데이터베이스는 테이블 혹은 레코드를 lock을 걸어 데이터가 변경되지 않도록 막아 놓고 다른 작업을 진행한다. 이 때 1번째 요청이 A 테이블의 값을 변경하고, lock을 걸어둔 상태에서 B 테이블을 사용하려고 하고, 2번째 요청이 B 테이블의 값을 변경하고 lock 을 걸어둔 상태에서 A 테이블을 사용하려고 할 때 데이터베이스는 우선순위를 판단 할 수 없어 교착상태에 빠진다. -> 이 때 어쩔 수 없이 강제로 시스템을 재시작하여 데이터베이스 커넥션을 초기화 해야한다.
    1. MySQL
      • Long 타입의 키 값을 생성하는 방식이 auto increment 방식이다.
      • auto increment : 숫자형의 PK 컬럼 속성을 auto increment로 지정하면 자동으로 새로운 레코드가 될 때마다 마지막 PK 값에서 자동으로 +1 해주는 방식이다. 이를 위해 @GenerateValue 어노테이션의 strategy 속성을 GenerationType.IDENTITY로 지정해 auto increment 컬럼인 것을 EntityManager에 알려준다.
      • 이 때 자동으로 생성되는 값을 가지는 PK 컬럼의 이름은 명시적으로 id로 지정하는 것이 관례이다.
@id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
2. Oracle
    - Long 타입의 키 값을 생성하는 방식이 sequence 방식이다.
    - sequence : sequence Oracle 객체를 생성해두고 해당 sequence를 호출할 때마다 기존 값의 +1 이 된 값을 반환해 주는 방식이다. 이를 위해 @GeneratedValue 어노테이션의 strategy 속성을 GenerationType.SEQUENCE로 지정해 sequence를 사용해 PK 값을 사용하겠다고 지정한다.
@Id
@SequenceGenerator(name="seq", sequenceName="id_sequence")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private Long id;
  1. @EmbeddedId
    • 일반적인 경우에는 PK를 단일 @Id로 구성하지만 경우에 따라선 복합키로서 테이블의 PK를 정의하기도 한다.
      • 복합키 : 두 개 이상의 @Id로 구성이 되는데 직접 Entity에 정의하는 것이 아니라 별도의 Value를 사용해 복합키를 정의한다.
    • 먼저 Value를 생성한 다음 @Embeddable 어노테이션을 이용해 이 Value 가 Entity에 삽입이 가능함을 명시하고 Entity에서는 @EmbeddedId 어노테이션을 이용해 이 Entity에 해당 Value를 PK로 사용한다고 지정한다.
@Embeddable
public class CompanyOrganizationKey implements Serializable {
    @Column(name = "company_code")
    private String companyCode;

    @Column(name = "organization_code")
    private String organizationCode;
}

@Entity(name = "company_organization")
public class CompanyOrganization {
    @EmbeddedId
    protected CompanyOrganizationKey companyOrganizationKey;
}

필드와 컬럼 매핑

  1. @Column
    • 테이터베이스의 테이블에 있는 컬럼과 동일하게 1:1로 매핑되기 때문에 Entity 클래스 안에 내부변수로 정의 된다.
    • 이 어노테이션은 별다른 옵션을 설정하지 않는다면 생략이 가능하다. -> Entity 클래스에 정의된 모든 내부변수는 기본적으로 이 어노테이션을 포함한다고 볼 수 있다.
    • 스프링부트 application 설정에서 ddl-auto 설정이 create 일때는 최초에 한 번 컬럼이 생성이 되고, update 일때는 Entity 클래스에 있지만 해당 테이블에 존재하지 않는 컬럼을 추가로 생성해 준다.
    • 하지만, 컬럼의 데이터 타입이 변경되었거나 길이가 변경되었을 때 자동으로 데이터베이스에 반영을 해주지는 않기 때문에 속성이 변경되면 기존 테이블을 drop 후 create 하던지 개별로 alter table을 통해 직접 DDL 구문을 적용하는 것이 좋다.
    • create - drop 일때는 프로젝트가 시작될 때 자동으로 기존 테이블을 drop 한 후 create를 해준다. 하지만, 기존 스키마가 전부 삭제되기 때문에 시스템 설계와 개발 시점에만 사용해야하며 운영시점에 create, update, create-drop을 사용하지 않아야 한다.
    • @Entity 와 동일하게 name 속성을 명시하지 않으면 Entity 클래스에 정의한 컬럼 변수의 이름으로 생성이 된다.
    • 이 때문에 만약 컬럼 이름과 다르다면 name 속성을 넣어야 한다.
@Column
private String code;

@Column(length = 100)
private String name;

//@Column 은 생략이 가능하다.
private String desctiption;

@Column(precision = 11, scale = 2)
private BigDecimal amount;

@Column
private Integer size;

@Column(name = "register_date")
private LocalDateTime registerDate;

연관관계 매핑

  • 실제로 서비스되는 웹 어플리케이션에서 하나의 엔티티 타입만을 이용하는 경우는 많이 안습니다.
    • EX) Member 엔티티와 Team 엔티티가 있을 때, 하나의 Team은 여러 Member를 갖는 관계를 가지고 있다.
    • 이처럼 엔티티들이 서로 어떤 연관관계를 갖는지 파악하는 것은 매우 중요하다.
  • 연관관계 매핑 : 객체의 참조와 테이블의 외래 키를 매핑하는 것을 의미.
    • JPA에서는 연관관계에 있는 상대 테이블의 PK를 멤버 변수로 갖지 않고, 엔티티 객체 자체를 통째로 참조합니다.
    • 물론 단순히 참조하는 것만으로는 연관관계를 맺을 수 없습니다.
    • 먼저, 연관관계 매핑을 이해하기 위한 3가지 키워드를 알아보겠습니다.
    1. 방향
      • 단방향 관계 : 두 엔티티가 관계를 맺을 때, 한 쪽의 엔티티만 참조하고 있는 것
      • 양방향 관계 : 두 엔티티가 관계를 맺을 때, 양 쪽이 서로 참조하고 있는 것
      • 데이터 모델링에서는 관계를 맺어주기만 하면 자동으로 양방향 관계가 되어 서로 참조하지만, 객체지향 모델링에서는 구현하고자 하는 서비스에 따라 단방향 관계인지, 양방향 관계인지 적절한 선택을 해야한다.
    2. 다중성
      • 관계에 있는 두 엔티티는 다음 중 하나의 관계를 갖습니다.
      • ManyToOne : 다대일 -> N : 1
      • OneToMany : 일대다 -> 1 : N
      • OneToOne : 일대일 -> 1 : 1
      • ManyToMany : 다대다 -> N : N
      • EX) 하나의 Team은 여러 Member를 구성원으로 갖고 있으므로 Team 입장에서는 Member와 일대다 관계이며, Member의 입장에서는 하나의 Team에 속하므로 다대일 관계입니다.
    3. 연관관계의 주인 (Owner)
      • 객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야한다.
      • 연관관계를 갖는 두 테이블에서 외래키를 갖게되는 테이블이 연관관계의 주인이다.
      • 주인만이 외래 키를 관리(등록, 수정, 삭제) 할 수 있고, 주인이 아닌 엔티티는 읽기만 할 수 있다.
  1. @ManuToOne - 단방향
@Entity
@Getter
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String username;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

@Entity
@Getter
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;
}
  • 단방향은 한 쪽의 엔티티가 상대 엔티티를 참조하고 있는 상태입니다. -> Member 엔티티에만 @ManyToOne 어노테이션이 있다.
  • 연관관계를 매핑할 때 다중성을 나타내는 어노테이션을 필수로 사용해야 하며, 엔티티 자신을 기준으로 다중성을 생각해야 한다.
  • JoinColum(name = "TEAM_ID")
    • JoinColumn 어노테이션은 외래 키를 매핑할 때 사용합니다. name 속성에는 매핑할 외래 키 이름을 지정한다.
    • Member 엔티티의 경우 Team 엔티티의 id 필드를 외래 키로 가지므로, TEAM_ID로 작성하였습니다.
  • 데이터 모델링에서는 1:N 관계만 설정해주면 자동으로 양방향 관계가 되기 때문에 어느 테이블에서든 JOIN만 해주면 원하는 컬럼들을 가져올 수 있지만, JPA에서는 양방향 관계를 맺음으로서 해결할 수 있다.
  1. OneToMany 로 양방향 관계 맺기
@Entity
@Getter
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>(); 
}
  • Team은 Member를 List로 가지며, 연관관계의 주인을 정하기 위해 @OneToMany에 mappedBy 속성을 추가했습니다.
  • 연관관계의 주인을 정하는 방법은 mappedBy 속성을 지정하는 것.
    • 주인은 mappedBy 속성을 사용하지 않고, @JoinColumn을 사용
    • 주인이 아닌 엔티티 클래스는 mappedBy 속성을 사용해 주인을 정할 수 있다.
  • 주인은 mappedBy 속성을 사용할 수 없으므로 연관관계의 주인이 아닌 Team 엔티티에서 members 필드에 mappedBy 속성으로 Member 테이블의 Team 필드 이름을 명시해준다.
  • mappedBy의 속성으로 Member 테이블의 Team 필드 이름을 명시해준다 (Team DB에 members FK 컬럼을 만들지 안헥 하기 위해)
  1. OneToOne
  • 한 유저는 한 개의 블로그만 만들 수 있는 블로그 서비스가 있다고 가정하면, 유저와 블로그는 1:1 관계입니다.
  • 유저 엔티티 입장에서 블로그의 @Id를 외래 키로 가져서 블로그를 참조할 수 있고, 그 반대 경우인 블로그 엔티티를 가져서 유저를 참조하는 것도 가능합니다. 여기서 외래 키를 갖고 있는 테이블을 주 테이블이라고 합니다.
  • 여기서 만약 한 유저가 여러 개의 블로그를 가질 수 있도록 확장(OneToMany) 될 수 있음을 고려한다면, 블로그에서 유저의 외래 키를 갖는 것이 좋을 것입니다.
  • 반대로 유저를 조회 했을 때 자동으로 블로그 엔티티도 조회되는 것이 좋겠다고 생각하면 유저에서 블로그의 외래 키를 갖는 것이 좋을 것입니다.
  1. ManyToMany (실무 사용 금지)
  • 중간 테이블이 숨겨져 있기 때문에 자기도 모르는 복잡한 조인의 쿼리가 발생하는 경우가 생길 수 있기 때문에 실무에선 사용 금지입니다.
  • 다대다로 자동 생성된 중간 테이블은 두 객체의 테이블의 외래 키만 저장되기 때문에 문제가 될 확률이 높습니다.
  • 중간 테이블에 외래 키에 다른 정보가 들어가는 경우가 많기 때문에, 다대다를 일대다, 다대일로 풀어서 만드는 것(중간에 매핑 테이블을 만드는 것)이 추후 변경에도 유연하게 대처할 수 있습니다.

Repository 사용법

  • Repository 생성
    • 실제 DB에 접속하여 쿼리를 수행하는 등의 역할을 하는 인터페이스 입니다.
    • @Repository 어노테이션을 추가하고, JpaRepository 를 상속합니다.
    • 또한 정해진 규칙과 단어를 조합한 이름으로 메소드명을 작성하는 것만으로 다양한 쿼리를 생성할 수 있습니다.
  • Repository 예제
// <엔티티 클래스 이름, PK 타입>
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 메소드명(findAllBy) 뒤에 필드명을 넣는다. List로 구현한다.
    // @Query(value = "select * from table") -> 쿼리문을 직접 넣을 수 있다.
    List<User> findAllById(Long id);
}    

메소드

method 기능
save() 레코드 저장(insert, update)
findOneBy() PK로 레코드 하나 찾기
findBy() 뒤에 필드명 붙여 레코드 찾기
findAllBy() 전체 레코드 불러오기. 정렬, 페이징 기능
countBy() 레코드 개수
deleteBy() 레코드 삭제

키워드 (쿼리 대신)

메소드 키워드 예제 설명
And, Or findByIdAnd(Or)Name(Long id, String name) Id 가 id 인 값, Name이 name 인 값 찾음
Between findByBetween(String fromDate, Date toDate) from 과 toDate 사이 값 찾음
LessThan findByAgeLessThan(int age) Age 가 age 보다 작은 값 찾음
GreaterThanEqual findByAgeGreaterThanEqual(int age) Age가 age 보다 크거나 같은 값 찾음
Like, NotLike findByIdLike(Long id) Id가 id인 값 찾음
IsNull, IsNotNull findByNameIsNull() null 값 찾음
In findByName(String a, String b, String c) a, b, c 중 있는 것 찾음
OrderBy findByNameOrderByAgeAsc(String name) name을 찾아 오는데 age가 오름차순으로 찾음
StartingWith, EndingWith findByNameStartingWith("A") A로 시작하는 name 찾음
Before, After findByDateBefore(new Date()) Date가 Date타입인 경우 이전 것만 찾음
First, Last findFirst2ByNameOrderByAgeAsc(String name) 찾아온 값 중에 처음 2개를 찾음
  • Service 예제
@Service
@RequiredArgsConstructor // final, 필드들을 매개변수로 하는 생성자를 자동으로 생성해주는 어노테이션
public class UserService {

    private final UserRepository userRepository;

    public List<Users> getUsersService(String name){
        if(name.isBlank()) // name 파라미터가 Null이면 전체 user를 리턴
            return userRepository.findAll();
        else  // name 이 존재를 하면, Like 쿼리로 2개만 리턴
            return userRepository.findFirst2ByUsernameLikeOrderByIDDesc(name); // 유저이름이 들어간 유저 중 내림차순하고 그 중 상위 2개 추출
    }

    public String createUserService(Users user){
         userRepository.save(user); // User Insert 쿼리 수행
         return "등록 완료";
    }
}
  • Controller 예제
@RestController
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping(value = "/users")
    public List<Users> getUsers( @RequestParam(required = false, defaultValue = "") String name ){
        return userService.getUsersService( name );
    }

    @PostMapping(value = "/user")
    public String createUser(@RequestBody Users user){
        return userService.createUserService(user);
    }

}
- @RestController
    - @Controller + @ResponseBody
    - @ResponseBody : xml 이나 json 기반의 메시지를 사용하는 요청의 경우 유용 -> Ajax

연관관계에서는 ToString()을 주의

@ToString()

- 클래스의 필드를 생성하고 출력하면 문자열 형태로 나온다.
- EX) User(id = 아이디, name = 이름)
  • 엔티티 간에 연관관계를 지정하는 경우엔 항상 @ToString() 어노테이션을 주의해야 합니다.
  • @ToString()은 해당 클래스의 모든 멤버 변수를 출력하는데, 연관관계 매핑이 되어있을 경우 그 객체 역시 출력해야 하기 때문에 이때 데이터베이스 연결이 필요하게 됩니다.
  • 이런 문제로 인해 연관관계가 있는 엔티티 클래스의 경우 @ToString() 할 때 습관적으로 exclude 속성을 사용하는 것이 좋습니다.
  • exclude는 해당 속성값으로 지정된 필드는 @ToString()에서 제외해줍니다.

다음 게시글 프로젝트 1

https://hoozy.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%A4%EC%A0%95-1

 

프로젝트 1 설정 (Spring Boot, MySQL)

이전 게시글 스프링 부트와 MySQL 연결 https://hoozy.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8%EC%99%80-mySQL-%EC%97%B0%EA%B2%B0 기본 설정 mySQL, jpa, lombok, Thymeleaf 등 GRADLE 추가 home.html 홈페이지 resources

hoozy.tistory.com

참고 자료

https://blog.naver.com/PostView.nhn?blogId=ka28&logNo=222355010576
https://ssdragon.tistory.com/78
https://gwonbookcase.tistory.com/37
https://dev-coco.tistory.com/106
https://geonoo.tistory.com/149
https://kim-oriental.tistory.com/20

댓글