Java Spring Boot 004-3 | JPA 활용하기

Yunny.Log ·2022년 2월 18일
0

Spring Boot

목록 보기
21/80
post-thumbnail

JPA 활용하기

프로젝트 생성, 디펜던시 저 세개 추가하기
root계정에서 스키마 새로 만들어주기 => 이거 localhost에서 진행하기

아이디 ; demo_jpa / 비번 ; 늘쓰던애..
- 특권 설정 들어가서 특권 all 선택
- 커넥션 만들기
- 그리고 이와 같은 새로운 mysql 아이 만들기

=> mybatis 사용할 때는 테이블 값 미리 지정해뒀어야 하는데 jpa는 알아서 작성ㅇ

Entity 작성 & JPA Relationships

  • 위와 같이 spring 파일 만들어주기

  • application.yml 파일 작성

spring:
  datasource:
    driver-class-name:com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.01:3306/demo_jpa_scheme
    username : demo_jpa
    passsword : qpqpqp0614@
jpa :
  hibernate :
    ddl-auto : create
  show-sql : false
  properties :
    hibernate :
      dialect:org.hibernate.dialect.MYSQL8DiaLect

위에거 잘못됐고 아래처럼 jpa앞에 indentation 있었어야 함 ^^..

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_jpa_scheme?serverTimezone=UT
    username : demo_jpa
    passsword : qpqpqp0614
  jpa :
    hibernate :
      ddl-auto : create
    show-sql : false
    properties :
      hibernate :
        dialect: org.hibernate.dialect.MYSQL8Dialect

=> 복습 설명 : jpa는 annotation들의 라이브러리, 이걸 사용하는 건 하이버네이트

  • ddl auto : 테이블 생성, 삭제 자동으로 해주는 아이
  • but 보통 상용환경에서는 create로 사용 x , 높게 써봐야 update, 일반 상황은 none
  • show sql : jpa가 실제로 작동하면서 사용할 sql문이 있는데 이를 보여줄 지 말지 여부
  • dialect는 hibernate에게 우리가 사용할 mysql 이거야~라고 참고하라 알려주는 것
    • db별로 문법이 쪼매씩 다를텐데 배티스를 쓴다면 직접 해야 하지만 하이버네이트는 대신해주기 때문에 우리가 어떤 db를 사용할 것인지는 알려주어야 한다.

1) PostEntity 클래스 작성

@Entity
public class PostEntity {
    @Id //jpa에게 아래의 아이기 pk라는 것임을 알려주는 것
    private Long id;
    //jpa 사용하면 프리미티브 타입 말고 클래스 기반 오브젝트 사용
    private String title;
    private String content;
    private String writer;
}
  • @Entity 를 PostEntity 클래스 위에 붙여주기
  • @Id 를 붙여서 pk가 무엇인지 알려주기

그리고 밑에 작성한 수많은 에러들을 거친 채^^ run을 해주니

이렇게 잘 생기게 된다!

  • 이렇듯 jpa는 yml같은 설정에 명시된 것에 따라서 mysql을 만들어주는 역할을 수행한다옹

2) BoardEntity 작성

package jsbdy.jpa.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/*
  id int
  name varchar
 */
@Entity
public class BoardEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

}

3) Entity 생성자, getter, setter, toString() 작성

4) PostEntity는 BoardEntity에 속해져있는 관계임 설정

    /*boarentity와의 관계 명시를 위해 추가*/
    @ManyToOne(
            /*어떠한 관계를 대상으로 관계맺나?*/
            targetEntity = BoardEntity.class,
            fetch = FetchType.LAZY
    ) /*다대일관계*/
    private BoardEntity boardentity;
    /* 여러개의 post,게시글은 한개의 board,게시판에 소속돼있는 것*/
  • 다만 지금 돌리면 db랑 mysql이랑 다르면 에러 발생하기도 한다
  • 그래도 일단은 괜찮으니 진행해보자, 그리고 postentity 그리고 foreignkey 까지 workbench에 성공적으로 생겼음을 알 수 있음

5) 하나의 BoardEntity 여러개의 PostEntity를 가지고 있음 알리기

  • 그리고 추가적으로 좀 바꿨으니깐 getter, setter ,cosntructor도 수정수정
    @OneToMany(
            targetEntity = PostEntity.class,
            fetch = FetchType.LAZY,
            mappedBy = "boardentity"
            /*PostEntity에 정의된 BoardEntity의 이름*/
    )
    private List<PostEntity> postentitylist = new ArrayList<>();

  • 여기까지가 테이블에 등록시키는 단계, 이제 이를 직접 활용하기 위해서 Repository 이요해줄 것임

6) BoardRepository (CRUD 레포지토리 확장)

package jsbdy.jpa.repository;

import jsbdy.jpa.entity.BoardEntity;
import org.springframework.data.repository.CrudRepository;

/*
T : 이 레포지토리가 어떤 엔티티 위한 것인지
ID : 아이디가 어떤 타입으로 작성이 되는지
*/

public interface BoardRepository extends CrudRepository<BoardEntity,Long> {
}

(+) CRUDRepository

7) TestComponent 작성

방금 만든 아이가 잘 생성됐음을 잘 알 수 있삼

@Component
public class TestComponent {
    public TestComponent(
            @Autowired BoardRepository boardrepository
            ){
        BoardEntity boardentity = new BoardEntity();
        boardentity.setName("new board");
        BoardEntity newboardentity = boardrepository.save(boardentity);
        System.out.println(newboardentity.getName());
    }
}

  • 이떄 jpa는 눈에 보이는 코드만 전부라고 생각하면 안됨
  • 따라서 바로 생성한 엔티티에 있는 속성을 프린트하는 것이 아닌 그것을 save하고 난 후의 엔티티의 속성을 출력하는 것이 더 좋다

8) PostEntity 생성

package jsbdy.jpa.repository;
import jsbdy.jpa.entity.PostEntity;
import org.springframework.data.repository.CrudRepository;
public interface PostRepository extends CrudRepository<PostEntity, Long> {
}

=> 이제 postentity 사용 가눙

9) TestComponent 재작성

@Component
public class TestComponent {
    public TestComponent(
            @Autowired BoardRepository boardrepository,
                 PostRepository postrepository
            ){
        BoardEntity boardentity = new BoardEntity();
        boardentity.setName("new board");
        BoardEntity newboardentity = boardrepository.save(boardentity);

        PostEntity postentity = new PostEntity();
        postentity.setWriter("hello ORM");
        postentity.setContent("created by Hibernate");
        postentity.setWriter("jsbdy");
        postentity.setBoardentity(newboardentity);//save되고 난 후의 entity 지정
        PostEntity newpostentity = postrepository.save(postentity);
    }
}


10) findById 말고 다른 것을 찾아볼까?

일단 디폴드로 주어지는 것으로는 findById가 있어 근데 작성자로 찾는 것은 안됨?
PostRepository 가서 아래와 같이 리스트

public interface PostRepository extends CrudRepository<PostEntity, Long> {
    List<PostEntity> findAllByWriter(String writer);
}

TestComponent 가서 아래와 같이 추가

System.out.println(postrepository.findAllByWriter("jsbdy").size());
  • where wrtier = 'jsbdy' 와 똑같은 의미 따라서 1 이라고 잘 프린트되는 것을 볼 수 있삼
    List <PostEntity> findAllByWriterAndBoardEntity(String writer, BoardEntity entity);
    List <PostEntity> findAllByWriterContatining(String writer);

11) BaseEntity

  • 모든 엔티티들이 기본적으로 어떠한 속성 가지고 있게 하고 싶으면 지정해줌
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity{ //추상 클래스로 만들기
    @CreatedDate
    @Column(updatable=false)
    private Instant createdAt;

    @LastModifiedDate
    @Column(updatable = true)
    private Instant updatedAt;
  • 추상클래스로 지정 & 물론 getter setter도
  • 그리고 아까 만든 PostEntity, BoardEntity에 extends
  • 따로 추가적으로 추상메소드는 만들어주지 않아서 엔티티들도 따로 선언해줄 애들 존재 x
  • 근데 Auditing이란 아이는 따로 스프링에서 지정된 애가 아니라서 application에 추가적으로 지정해주기 (@EnableJpaAuditing) & run

  • createdat, updatedat 잘 생성됨

Table, Column, JoinColumn, JoinTable

PostEntity

  • @Entity밑에 아래의 것 추가
@Table(name="post")
  • 그리고 manytoone 어노테이션 밑에 @JoinColumn(name="board_id") 추가
    @ManyToOne(
            /*어떠한 관계를 대상으로 관계맺나?*/
            targetEntity = BoardEntity.class,
            fetch = FetchType.LAZY
    ) /*다대일관계*/
    @JoinColumn(name="board_id")

BoardEntity에서도 아래 추가

- @Entity밑에 추가
@Table(name="board") 

- @Column(name="board_name") 아래에 추가
private String name;

Before


mysql 컬럼에 잘 추가되고 반영됨 ㅇㅇ


에러

(1) 해결참고블로그

at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35) ~[hibernate-core-5.4.33.jar:5.4.33]
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:101) ~[hibernate-core-5.4.33.jar:5.4.33]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-5.4.33.jar:5.4.33]
... 33 common frames omitted

Process finished with exit code 1


(2) 해결참고블로그
/example?serverTimezone=UTC&characterEncoding=UTF-8 이걸 뒤에 추가

Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service

Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(
Spring Boot
[Spring Boot] Hibernate 사용 시 Error creating bean with name 'entityManagerFactory' 해결 블로그

(3)

Unable to load class https://www.leawy.com/thread/hibernate-core-and-annotations/7792/java-lang-classnotfoundexception-could-not-load-requested-class-org-hibernate-mysql8dialect.htm

(4)

Access denied for user 'demo_jpa'@'localhost' (using password: NO)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(

https://stackoverflow.com/questions/2995054/access-denied-for-user-rootlocalhost-using-passwordno


https://www.yawintutor.com/error-5068-unable-to-open-jdbc-connection-for-ddl/

  • root로 mysql에 로그인하고

    mysql> use mysql;
    Database changed
    mysql> select * from user;
    아래처럼 쳐서 demo_jpa라는 아이를 살펴보았더니 N 천국 ^^ 권한없음 천국~~

mysql> create user 'demo_jpa'@'localhost';
Query OK, 0 rows affected (0.04 sec)
mysql> grant all privileges on . to 'demo_jpa'@'localhost';
Query OK, 0 rows affected (0.04 sec)
flush privileges;
Query OK, 0 rows affected (0.03 sec)

  • 일케 해주고 돌리니깐 드디어 됐다
    mysql 권한 문제였나봉가

(5) jpa find~함수 작성 시 엔티티 명, 레포지토리 명 (소대문자 구별하는 것) 아주 중요!

List <PostEntity> findAllByWriterAndBoardEntity(String writer, BoardEntity entity);

라고 처음에 작성했는데, 나같은 경우에는 PostEntity에서 BoardEntity를 정의할 때

    private BoardEntity boardentity;

이렇게 정의했었음 근데 jpa에서

findAllByWriterAndBoardEntity

이렇게 썼더니에러가 남 당연함
저렇게 쓰면 jpa는 boardEntity를 찾을텐데 나는 boardentity라고 정의해놨으니.. 따라서 아래처럼 수정하면 잘 됨ㅋ

List <PostEntity> findAllByWriterAndBoardentity

0개의 댓글