๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Today I Learned(TIL)/์ˆ˜์ค€๋ณ„ ํ•™์Šต๋ฐ˜

์ˆ˜์ค€๋ณ„ ํ•™์Šต๋ฐ˜_๋ฒ ์ด์ง๋ฐ˜ 4ํšŒ์ฐจ ์„ธ์…˜

by carrot0911 2024. 12. 21.

๋ฒ ์ด์ง๋ฐ˜

๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋ฐฉ๋ฒ• JPA

12/17 11:00 ~ 12:40 (์•ฝ 1์‹œ๊ฐ„ 40๋ถ„ ์ง„ํ–‰)

 

์ค‘์š” ํ‚ค์›Œ๋“œ

  • JPA
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ → ๋ฉด์ ‘์—์„œ ํ•ญ์ƒ ๋‚˜์˜ค๋Š” ๋‚ด์šฉ
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์žฅ์ 
    • 1์ฐจ ์บ์‹ฑ
    • ๋™๋“ฑ์„ฑ ๋ณด์žฅ
    • ์“ฐ๊ธฐ ์ง€์—ฐ
    • ๋ณ€๊ฒฝ ๊ฐ์ง€
  • JPA ๋‘ ๊ฐ€์ง€ ํ™œ์šฉ ๋ฐฉ๋ฒ•
    • ์ˆœ์ˆ˜ JPA
    • JPA ์ธํ„ฐํŽ˜์ด์Šค → ํ˜„์—…์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

 

JPA(Java Persistence API)

JPA๋Š” ์ž๋ฐ” ์ƒํƒœ๊ณ„์—์„œ ORM์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œ์ค€ ๋ช…์„ธ์ด๋‹ค.
Hibernate๋Š” JPA ๋ช…์„ธ๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

JPA๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ JDBC API๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

 

ORM(Object-Relational Mapping)

๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

ORM์˜ ํ•œ๊ณ„๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— SQL์„ ์ž˜ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

  • ๋‘˜ ๋‹ค ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ํ•œ์ชฝ๋งŒ ์•Œ๊ณ  ์žˆ์œผ๋ฉด ์•ˆ ๋œ๋‹ค.
  • ORM์ด ์ƒ์‚ฐ์„ฑ์ด ์ข‹๋‹ค.

์–ธ์–ด๋งˆ๋‹ค ๋‹ค์–‘ํ•œ ORM ๊ธฐ์ˆ 

์–ธ์–ด ORM ๊ธฐ์ˆ  ์ด๋ฆ„
Java JPA
javascript Sequelize
python Django ORM

CRUD ํ™œ์šฉ ์˜ˆ์‹œ

1. ์ƒ์„ฑ(CREATE)

INSERT INTO student (name) VALUES ("gygim");
Student newStudent = new Student("gygim");
studentRepository.save(newStudent);

2. ์กฐํšŒ(READ)

SELECT * FROM student;
List<Student> students = studentRepository.findAll();

3. ์—…๋ฐ์ดํŠธ(UPDATE)

UPDATE student SET name="Steve" WHERE id = 1;
Student foundStudent = studentRepository.findById(1L);
foundStudent.setName("Steve");

4. ์‚ญ์ œ(DELETE)

DELETE FROM student WHERE id = 1;
Student foundStudent = studentRepository.findById(1L);
studentRepository.delete(foundStudent);

 

์—”ํ‹ฐํ‹ฐ(Entity) @Entity

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋˜๋Š” ํด๋ž˜์Šค์ด๋‹ค.

1. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

CREATE TABLE student (
    id BIGINT AUTO_INCREMENT PRIMARY_KEY,
    name VARCHAR(255)
);
Field Type Null Key Extra
id bigint(20) No PRI auto_increment
name varchar(255) No    

2. ์—”ํ‹ฐํ‹ฐ(Entity)

@Entity
public class Student {
    @Id
    @GeneratedValue(straregy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    // Getter and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}

 

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

์—”ํ‹ฐํ‹ฐ(Entity)๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„์ด๋‹ค.
์ž๋ฐ”์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด์—์„œ ์ค‘๊ฐ„ ๋‹ค๋ฆฌ ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ง‘์–ด๋„ฃ๋Š” ์ˆœ๊ฐ„ ์ถ”์ ํ•˜๊ณ  ๊ฐ์‹œํ•œ๋‹ค. 
๋™๊ธฐํ™” ์ž‘์—…์„ ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ผ์น˜๋˜๊ฒŒ๋” ๋งŒ๋“ค์–ด์ค€๋‹ค.

1. JPA๋ฅผ ํ™œ์šฉํ•œ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ๋ฆ„๋„

a. ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € ํŒฉํ† ๋ฆฌ(EMF: EntityManagerFactory)

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/<๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค>
spring.datasource.username=<์œ ์ €์ด๋ฆ„>
spring.datasource.password=<๋น„๋ฐ€๋ฒˆํ˜ธ>
spring.datasource.driver-class-name=<๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐฉ์–ธ>

์˜ˆ์‹œ: EntityManagerFactory๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์ฝ”๋“œ

EntityManagerFactory emf = Persistence.reateEntityManagerFactory("์˜๋ฌธ์˜ EMF");

b. ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €(EM: EntityManager)

์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €(EntitiyManager)๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋™์‹œ์— ์ƒ์„ฑ๋œ๋‹ค.
์ƒํ˜ธ์ž‘์šฉ์„ ํ•˜๋Š” ์นœ๊ตฌ์ด๋‹ค.

์˜ˆ์‹œ: EntityManagerFactory๊ฐ€ ์š”์ฒญ๋งˆ๋‹ค EntitiyManager๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ

EntityManagerFactory emf = Persistence.createEntityManagerFactory("์˜๋ฌธ์˜EMF");
EntityManager emA = emf.createEntityManager();
EntityManager emB = emf.createEntityManager();
โœ”๏ธ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์ƒ์„ฑ ์‹œ์ 

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” EntityManager๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ๋งŒ๋“ค์–ด์ง„๋‹ค.

2. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ํ™œ์šฉ

@Repository
public class StudentRepository {

		@PersistenceContext
		EntityManager em;
		
		public void save(Student student) {
				em.persist(student);
		}
		
		...
}

@PersisteneContext๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €(EntityManager)๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

 

์—”ํ‹ฐํ‹ฐ(Entity) ์ƒ๋ช…์ฃผ๊ธฐ

์ƒํƒœ ์„ค๋ช…
๋น„์˜์† ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ์ „ํ˜€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ
์˜์† ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ
์ค€์˜์† ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์—ˆ๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ
์‚ญ์ œ ์‚ญ์ œ๋œ ์ƒํƒœ

1. ๋น„์˜์†

// ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ์ƒํƒœ(๋น„์˜์†)
Student student = new Student();
student.setName("์˜๋ฌธ์˜ํ•™์ƒ");

2. ์˜์†

// ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ์ƒํƒœ(๋น„์˜์†)
Student newStudent = new Student();
newStudent.setName("์˜๋ฌธ์˜ํ•™์ƒ");

// ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ ์ƒํƒœ(์˜์†์ƒํƒœ)
em.persist(newStudent);

 

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์žฅ์ 

1. 1์ฐจ ์บ์‹ฑ

Student a = em.find(Student.class, "์˜๋ฌธ์˜ํ•™์ƒA"); // SELECT * FROM Student WHERE id = '์˜๋ฌธ์˜ํ•™์ƒA'
Student b = em.find(Student.class, "์˜๋ฌธ์˜ํ•™์ƒA"); // SELECT ์ฟผ๋ฆฌ ๋ฐœ์ƒ X (1์ฐจ ์บ์‹œ ์‚ฌ์šฉ)

2. ๋™์ผ์„ฑ ๋ณด์žฅ

Student a = em.find(Student.class, "์˜๋ฌธ์˜ํ•™์ƒA");
Student b = em.find(Student.class, "์˜๋ฌธ์˜ํ•™์ƒA");

// ๋™์ผ์„ฑ ๋น„๊ต true (๊ฐ™์€ ๊ฐ์ฒด ๋ฐ˜ํ™˜)
System.out.println(a == b);

3. ์“ฐ๊ธฐ ์ง€์—ฐ

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

//๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‹œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘
transaction.begin(); // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

em.persist(studentA); // (1) INSERT ...
em.persist(studentB); // (2) INSERT ...

// ์“ฐ๊ธฐ์ง€์—ฐ์€ persist ํ˜ธ์ถœ์‹œ SQL ์ด ๋ฐ”๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
// (1, 2 ์˜ sql ์„ ๋ชจ์•˜๋‹ค๊ฐ€ ๋ณด๋‚ธ๋‹ค.)
trasnaction.commit(); ํŠธ๋žœ์ ์…˜ ์ปค๋ฐ‹

4. ๋ณ€๊ฒฝ ๊ฐ์ง€

// ์˜์†
Student foundStudent = em.find(Student.class, "์˜๋ฌธ์˜ํ•™์ƒA");
foundStudent.setName("์ƒˆ๋กœ์šด์ด๋ฆ„");

// persist ํ˜ธ์ถœ ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
// ๋ณ€๊ฒฝ๋œ ์†์„ฑ์€ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ ์ž๋™ ๋ฐ˜์˜ ๋ฉ๋‹ˆ๋‹ค.
em.persist(foundStudent);

 

์‹ค์Šต ํฌ์ธํŠธ

  • student ์ƒ์„ฑ API
  • student ์กฐํšŒ API

1. ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ค€๋น„

CREATE DATABASE basic_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

2. ์˜์กด์„ฑ ์ถ”๊ฐ€ ๋ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •

// JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// MYSQL
implementation 'mysql:mysql-connector-java:8.0.28'

// MariaDB
implementation 'org.mariadb.jdbc:mariadb-java-client'
spring.application.name=<์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋ฆ„>

 // Mysql ์‚ฌ์šฉ์‹œ
spring.datasource.url=jdbc:mysql://localhost:3306/basic_db
spring.datasource.username=<์œ ์ €์ด๋ฆ„>
spring.datasource.password=<๋น„๋ฐ€๋ฒˆํ˜ธ>
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

// (์„ ํƒ) MariaDB ์‚ฌ์šฉ์‹œ
spring.datasource.url=jdbc:mariadb://localhost:3306/basic_db
spring.datasource.username=<์œ ์ €์ด๋ฆ„>
spring.datasource.password=<๋น„๋ฐ€๋ฒˆํ˜ธ>
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

// JPA ์—์„œ ์ง€์›ํ•ด์ฃผ๋Š” ํŽธ์˜ ๊ธฐ๋Šฅ
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

3. ์—”ํ‹ฐํ‹ฐ(Entity) ๋งŒ๋“ค๊ธฐ - Student.java

@Entity
@Getter
@Table(name = "student")
public class Student {

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

    private String name;

    protected Student() {}

    private Student(String name) {
        this.name = name;
    }

    public static Student of(String name) {
        return new Student(name);
    }
}

4. ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋กœ์ง - JPAStudentRepository.java

@Repository
public class JPAStudentRepository implements StudentRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    @Override
    public Student save(Student student) {
        entityManager.persist(student);
        return student;
    }

    @Override
    public List<Student> findAll() {
        return entityManager.createQuery("SELECT s FROM Student s", Student.class).getResultList();
    }
}

 

JPA ๋‘ ๊ฐ€์ง€ ํ™œ์šฉ ๋ฐฉ๋ฒ•

1. ์ˆœ์ˆ˜ JPA ํ™œ์šฉ

@Repository
public class JPAStudentRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public Student save(Student student) {
        entityManager.persist(student);
        return student;
    }

    public List<Student> findAll() {
        return entityManager.createQuery("SELECT s FROM Student s", Student.class).getResultList();
    }
}

2. JPA ์ธํ„ฐํŽ˜์ด์Šค ํ™œ์šฉ

public interface SpringDataStudentRepository extends JpaRepository<Student, Long> {
}

a. ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ

public interface SpringDataStudentRepository extends JpaRepository<Student, Long> {
    
    Optional<Student> findByName(String name);
}