스프링 3일차

TaeYoon Kim·2023년 12월 19일
0

SW CAMP

목록 보기
15/30

1교시
저번 시간 복습
스프링 실행 순서와 의존성 주입, 의존성 주입 방법 4가지.

나만의 객체를 만들고 싶을 때 쓰는 방법.
JDBCTemplete를 의존정 주입 받는 방법.

@Bean 어노테잉션 이용방법 메소드에 달아서 사용하는 것
객체의 코드를 내가 변경할 수 없는 때

  1. config 패키지를 만든다.
    2, 컴포넌트 어노테이션이 달린 @Configuration 어노테이션을 추가한
    클래스를 만든다.
  2. 생성자 이용해서 객체를 생성한다.
  3. @Bean이라는 어노테이션을 단 함수를 만든다.

기초 카테고리에 JPA만들어두자.

2교시 JPA
Spring Data JPA로 넘어가기 전에 ORM부터 알아보자.
ORM(Object relational Mapping)
sql를 자동으로 실행해서 편리함을 준다. 물론 자동이라 완벽하지 않다.
자바 ORM를 JPA(Java Persistence API)로 부른다. JPA는 기술 이름이라 라이브러리 이름이 JPA가 아니다.
개발한 회사이름이 라이브러리다.
ex) Hibernate( Spring이 쓰는 거) , Toplink, 이클립스

잠시 스프링을 잊고 JPA를 써보자.
1. 새 프로젝트를 만들고
2. 설정에 hibernate와 mysql connection 추가
Maven 예시

<dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.3.Final</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.2.0</version>
        </dependency>
    </dependencies>
  1. hibernation 기본 설정(공식사이트 참고)
    https://docs.jboss.org/hibernate/orm/6.4/quickstart/html_single/
    3-1 . persistence.xml 파일 작성 (DB 연결 정보)
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="hibernateproject">
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.user" value="kty"/>
            <property name="javax.persistence.jdbc.password" value="qwer1234"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.72.30/test"/>

            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>

class main생성

import javax.persistence.*;

public class HibernateMain {
    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hibernateproject");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction entityTransaction = entityManager.getTransaction();
    }
}

데이터 클래스 생성

package model;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // auoto increment 설정
    private Integer student_id;
    private String student_name;
}

어노테이션들이 중요하다.
@Entity: 테이블이 될 클래스
@Table : 테이블의 이름을 클래스 이름이 아니라 원하는 값으로 재설정
@Id : 기본키로 쓸 속성

부록 JPA와 Spring data JPA의 차이점

3교시
자동화의 위험을 유튜브 썰로 알아보는 시간과 짜잘한 설정들

<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>

hibernate.hbm2ddl.auto value 옵션들 중에 기존 데이터를 삭제하는 것들이 있으니 사용에 주의하자.
실제로 배민 운영 데이터가 날아갔던 사례가 있다......

4교시
Entity 매니저로 객체를 저장하고 가져오고 수정, 삭제해보자.

import model.Student;

import javax.persistence.*;

public class HibernateMain {
    public static void main(String[] args) {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hibernateproject");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        EntityTransaction entityTransaction = entityManager.getTransaction();
        entityTransaction.begin();

        //insert
//        Student student = new Student("name1");
//        entityTransaction.begin();
//        entityManager.persist(student);

        //select
//        Student student = entityManager.find(Student.class,1);
//
//        System.out.println(student.getStudent_id());
//        System.out.println(student.getStudent_name());

		//update
//        Student student = entityManager.find(Student.class,1);
//        student.setStudent_name("test2");

        //delete 
//        Student student = entityManager.find(Student.class,1);
//        entityManager.remove(student);

        entityTransaction.commit(); //sql 실행해서 DB에 적용되는 시점

    }
}

5교시
엔티티 생명주기
엔티티 매니저 객체가 아주 중요하다.
엔티티 매니저 =
1.영속성 컨텍스트(엔티티를 관리해주는 객체)
2. DB에서 변경점들을 저장해두는 객체 (쓰기 지연 쿼리문을 통해 동기화 준비)

엔티티의 상태 4가지
1. 비영속 : 영속성 컨텍스트와 전혀관계가 없는 상태
2. 영속 : 영속성 컨텍스트에 저장된 상태
3. 준영속 : 영속성 컨텍스에 저장되었다가 분리된 상태 (컨텍스트에서 지운 상태)
4. 실제 DB에서 지운 상태

select문을 실행되는 과정
1. 영속 상태인 데이터가 있는지 확인한다. (엔티티 매니저에 객체가 있는지 확인)
2. 데이터가 있다면 바로 데이터를 가져온다.
3. 데이터가 없다면 해당 데이터를 DB에서 쿼리문을 통해 찾는다.
4. DB에 있다면 데이터를 가져와서 객체를 만들고 영속상태로 만든다.
5. 값을 반환해준다.

ORM를 사용하면 지연로딩으로 인해 N+1문제가 발생한다. (면접 단골 문제)

6교시

insert문이 실행되는 과정
1. 객체를 영속상태로 바꾼다.
2. 지연쿼리 저장소에 쿼리문을 만들어둔다.
3. commit 함수를 실행할 때 DB에 모와둔 쿼리문을 통해 추가 후, 비영속 상태로 바꾼다.

auto increment 설정은 어떻게 구현한 걸까?
프로그램을 다시 시작해도 마지막 추가값을 잘 가져온다.
그럼 DB에서 언제 그 값을 가져오는 걸까?

커밋은 영속성 컨텍스트와 DB의 내용을 동기화(?)하는 과정이다.
commit 안에 있는 flush라는 친구가 DB로 값을 보내준다.

update와 delete문
일단 값을 영속 상태로 만들고,
DB와 내용이 달라지는 순간에 sql문을 지연 쿼리 저장소에 저장해둔다.

데이터 베이스 ACID 도 다시 공부해봐야겠네.

7교시
다른 테이블들과 관계가 있는 경우 (1:1, 1:N, N:M)
연관 관계를 매핑해줘야한다.

엔티티 클래스들에 관계를 만들어주어야한다. 어떻게?
외래키를 저장하는 변수를 만들어서.

@ManyToOne
@OneToMany
@OneToOne
@ManyToMany
@JoinColumn(name ="Department_id")

양방향 관계와 단방향관계가 있다.

1대N 단방향과 양방향 관계 설정

  • 단방향
    N인 쪽 엔티티 클래스에 외래키를 저장할 변수를 만든다.
    @ManyToOne 어노테이션를 추가한다.
    @JoinColumn(name ="Departmentid") 어노테이션을 추가한다.
    이 때 name의 값은 (테이블이름)
    (기본키 변수명) 의 규칙이 있다.
    @ManyToOne // 다 측인 곳이니까  학생과 학과는  N:1관계이다.
    @JoinColumn(name ="Department_id") //규칙이 있다. 테이블명_기본키칼럼명
    private Department department;
  • 양방향
    양방향 설정할 때에는 주인을 설정해줘야한다는 사실을 기억하자.
    1인 쪽 엔티티 클래스에 N쪽 엔티티 클래스를 저장할 리스트 객체를 만든다.
    @OneToMany(mappedBy = "department") 어노테이션을 달아준다.
    이때 mappedBy의 값은 N쪽 엔티티 클래스에 만들어 놓은 외래키를 저장하는 변수 이름이다.
@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // auoto increment 설정
    private Integer id;
    private String name;
    @OneToMany(mappedBy = "department") //양방향 관계를 맺을 땐 주인을 정해줘야한다.
    private List<Student> students = new ArrayList<>();
}

그리고 엔티티 클래스는 꼭 기본 생성자가 필요하다.
이것 때문에 에러 축제였다.
https://hyeonic.tistory.com/191

0개의 댓글