- Entity Manager, Transaction, Persistence Context
- JPA & Hibernate Annotations
- JPQL(Java Persistence Query Language)
- Native Queries
- Named Queries
- Fetch Type: Eager vs Lazy
- Entity Relationships
- Inheritance & Mapping
- Transaction Management
- First Level Cache & Second Level Cache
- Spring Data JPA
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์ ๋ฐ์ดํฐ ์ค๋ณต์ ๋ฐฉ์งํ๊ธฐ ์ํด ํ์ชฝ ์ํฐํฐ๋ง์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ์ค์
- -ToOne ์ฐ๊ด ๊ด๊ณ์ ๊ธฐ๋ณธ
FetchType
์Eager
์ด๋ฏ๋ก ์ผ๋ํด ๋๊ธฐ
- ๊ธฐ๋ณธ์ ์ผ๋ก
FetchType
์Eager
๋ก ์ค์ ๋์ด ์์ - ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ค์ ํ ๋, ์ฃผ์ธ์ด ์๋ ์ชฝ์
mappedBy = {๋ณ์๋ช }
์ ์ค์ ํด์ฃผ๋ฉด ๋จ
Student ํด๋์ค
@OneToOne(fetch = FetchType.LAZY)
private Passport passport;
Passport ํด๋์ค
@OneToOne(fetch = FetchType.LAZY, mappedBy = "passport")
private Student student;
- ๊ธฐ๋ณธ์ ์ผ๋ก
@ManyToOne
์FetchType
์Eager
๋ก ์ค์ ๋์ด ์์ - ๊ธฐ๋ณธ์ ์ผ๋ก
@OneToMany
์FetchType
์Lazy
๋ก ์ค์ ๋์ด ์์ - ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์
@ManyToOne
์ชฝ์ ์ค์ , ์ฆmappedBy = {๋ณ์๋ช }
๋@OneToMany
์ชฝ์ ์ค์
Review ํด๋์ค
@ManyToOne(fetch = FetchType.LAZY)
private Course course;
Course ํด๋์ค
@OneToMany(mappedBy = "course")
private List<Review> reviews = new ArrayList<>();
- ๊ธฐ๋ณธ์ ์ผ๋ก
@ManyToMany
์FetchType
์Lazy
๋ก ์ค์ ๋์ด ์์ - ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ์ํฐํฐ์ ์ฃผํค๋ฅผ ๊ฐ์ง๊ณ ๋๊ฐ์
JoinTable
์ ์์ฑํด์ค (COURSE_STUDENTS, STUDENT_COURSES) - ๊ทธ๋ฌ๋ ์ด๊ฒ์ ์ข์ง ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ์ด๋ฏ๋ก ๋ ์ค์ ํ์ชฝ์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ์ค์ ํด์ค์ผ๋ก์จ ๋ฌธ์ ํด๊ฒฐ ๊ฐ๋ฅ
@JoinTable
์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ ์ชฝ์ ์ค์ joinColumns
๋ ์ฃผ์ธ ์ชฝ์ ์ฃผํค ์ค์ inverseJoinColumns
๋ ์ฃผ์ธ์ด ์๋ ์ชฝ์ ์ฃผํค ์ค์
Student ํด๋์ค(์ฐ๊ด๊ด๊ณ ์ฃผ์ธ)
@ManyToMany
@JoinTable(
name = "STUDENT_COURSE",
joinColumns = @JoinColumn(name = "STUDENT_ID"),
inverseJoinColumns = @JoinColumn(name = "COURSE_ID")
)
private List<Course> courses = new ArrayList<>();
Course ํด๋์ค
@ManyToMany(mappedBy = "courses")
private List<Student> students = new ArrayList<>();
๋ถ๋ชจ ํด๋์ค
@Entity
@Getter
@Table(name = "employees")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "EMPLOYEE_TYPE")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
public Employee(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Employee[%s]", this.name);
}
}
์์ ํด๋์ค
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PartTimeEmployee extends Employee {
private BigDecimal hourlyWage;
@Builder
public PartTimeEmployee(String name, BigDecimal hourlyWage) {
super(name);
this.hourlyWage = hourlyWage;
}
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FullTimeEmployee extends Employee {
private BigDecimal salary;
@Builder
public FullTimeEmployee(String name, BigDecimal salary) {
super(name);
this.salary = salary;
}
}
@Inheritance
์strategy
์ ๊ธฐ๋ณธ๊ฐ์SINGLE_TABLE
์ ๋๋ค.SINGLE_TABLE
์ ์์ ๊ด๊ณ์ ์๋ ํ ์ด๋ธ๋ค์ ๋ชจ๋ ํฉ์ณ์ ํ๋์ ํ ์ด๋ธ๋ก ์ ์ฅํฉ๋๋ค. ์ฆ, ๋ถ๋ชจ ํ ์ด๋ธ๋ง ์์ฑ๋ฉ๋๋ค.- ๊ธฐ๋ณธ์ ์ผ๋ก
DTYPE
์ด๋ผ๋ ์๋ก์ด ์นผ๋ผ์ด ์์ฑ๋๊ณ , ์ด ์นผ๋ผ์ ์ด๋ ํ ์์ ํด๋์ค์ธ์ง ๊ตฌ๋ถํด์ค๋๋ค. ํด๋น ์นผ๋ผ๋ช ์@DiscriminatorColumn
์ด๋ ธํ ์ด์ ์ผ๋ก ์ฌ์ ์ ํ ์ ์์ต๋๋ค. - ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ ์ฟผ๋ฆฌ๋ ๋งค์ฐ ๋จ์ํ๋ฏ๋ก ์ฑ๋ฅ๋ฉด์์๋ ์ข์ผ๋, ํ
์ด๋ธ์ด ์์ฑ๋ ๋
null
๊ฐ์ด ์์ฑ๋๋ฏ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๊ณ๋ฉด์์๋ ๋นํจ์จ์ ์ ๋๋ค.
๋ถ๋ชจ ํด๋์ค
@Entity
@Getter
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
- ์์ ๊ด๊ณ์ ์๋ ํด๋์ค์ ๋ํด ๋ชจ๋ ๊ฐ๋ณ์ ์ธ ํ ์ด๋ธ์ ์์ฑํด์ค๋๋ค.
- ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋, ์ฆ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์กฐํํ ๋
UNION
์ ์ฌ์ฉํ๊ณ ์ฑ๋ฅ๋ ์ค์ํ ํธ์ ๋๋ค. - ๊ทธ๋ฌ๋ ์์ ํด๋์ค๊ฐ ๋ถ๋ชจ ํด๋์ค์ ๋ชจ๋ ์นผ๋ผ์ ์์ ๋ฐ์ผ๋ฏ๋ก ๊ณตํต ์นผ๋ผ์ ๋ํ ์ค๋ณต ํ์์ด ๋ฐ์ํฉ๋๋ค.
@Entity
@Getter
@Inheritance(strategy = InheritanceType.JOINED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
- ๋ถ๋ชจ ํด๋์ค์ ํ ์ด๋ธ์ ์์ ์ ์นผ๋ผ๋ง์ ๊ฐ์ง๊ณ , ์์ ํด๋์ค์ ํ ์ด๋ธ์ ๋ถ๋ชจ ํด๋์ค์ ID๋ฅผ ์ฐธ์กฐํ๋ ์ธ๋ํค๋ ์์ ์ ์นผ๋ผ๋ง์ ๊ฐ์ง๋๋ค.
- ๊ทธ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ค๊ณ๋ฉด์์๋ ๊ฐ์ฅ ํจ์จ์ด ์ข์ต๋๋ค.
- ๋ถ๋ชจ ํด๋์ค๋ฅผ ์กฐํํ ๊ฒฝ์ฐ, ๊ฐ๊ฐ์ ์์ ํด๋์ค์ ๋ํด
JOIN
์ฐ์ฐ์ ์ํํ๋ฏ๋ก ์ฑ๋ฅ๋ฉด์์๋ ๋จ์ด์ง๋๋ค.
- ๋ถ๋ชจ ํด๋์ค
@Getter
@MappedSuperclass
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
@MappedSuperClass
๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ํด๋์ค๋ฅผ ์ํฐํฐ๋ก ๋งคํํ ์ ์์ผ๋ฏ๋ก@Entity
์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.- ์ด๋ก ์ธํด์ ๋ถ๋ชจ ํด๋์ค๋ก ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ์ ์๊ฒ ๋ฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์์๋ ์์ ํด๋์ค์ ํ
์ด๋ธ๋ง ์์ฑ๋๊ณ
TABLE_PER_CLASS
์ ๊ฐ์ ํํ๋ก ์์ฑ๋ฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋์์ธ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ๊ณ ๋ คํ๋ค๋ฉด JOINED
๋ฐฉ์์ ์ถ์ฒํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ฑ๋ฅ์ ๋ ๊ณ ๋ คํ๋ค๋ฉด SINGLE_TABLE
์ ์ถ์ฒํฉ๋๋ค.
๋ฐ๋ฉด์ TABLE_PER_CLASS
ํ๊ณ Mapped Super Class
๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ๊ฐ ํ
์ด๋ธ๋ง๋ค ์ค๋ณต๋๋ ์นผ๋ผ์ด ์์ฑ๋๋ฏ๋ก ๋น์ถ์ฒํฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํ๋ฅผ ๋ณํ์ํค๋ ํ๋์ ๋ ผ๋ฆฌ์ ์ธ ์์ ๋จ์๋ฅผ ๊ตฌ์ฑํ๋ ์ฐ์ฐ๋ค์ ์งํฉ์ ๋๋ค.
์๋ฅผ ๋ค์ด A ๊ณ์ข์์ B ๊ณ์ข๋ก ์ผ์ ๊ธ์ก์ ์ด์ฒดํ๋ค๊ณ ๊ฐ์ ํฉ์๋ค.
- A ๊ณ์ข์ ์์ก์ ํ์ธํ๋ค.
- A ๊ณ์ข์ ๊ธ์ก์์ ์ด์ฒดํ ๊ธ์ก์ ๋นผ๊ณ ๋ค์ ์ ์ฅํ๋ค.
- B ๊ณ์ข์ ์์ก์ ํ์ธํ๋ค.
- B ๊ณ์ข์ ๊ธ์ก์์ ์ด์ฒดํ ๊ธ์ก์ ๋ํ๊ณ ๋ค์ ์ ์ฅํ๋ค.
์ด๋ฌํ ๊ณผ์ ๋ค์ด ๋ชจ๋ ํฉ์ณ์ ธ์ "๊ณ์ข ์ด์ฒด" ๋ผ๋ ํ๋์ ์์ ๋จ์๋ฅผ ๊ตฌ์ฑํ๊ฒ ๋ฉ๋๋ค.
Commit ์ฐ์ฐ
ํ๋์ ๋ ผ๋ฆฌ์ ๋จ์(ํธ๋์ญ์ )์ ๋ํ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ค์ ์ผ๊ด๋ ์ํ์ ์์ ๋, ์ด ํธ๋์ญ์ ์ด ํํ ๊ฐฑ์ ์ฐ์ฐ์ด ์๋ฃ๋ ๊ฒ์ ํธ๋์ญ์ ๊ด๋ฆฌ์์๊ฒ ์๋ ค์ฃผ๋ ์ฐ์ฐ์ ๋๋ค.
Rollback ์ฐ์ฐ
ํ๋์ ํธ๋์ญ์ ์ฒ๋ฆฌ๊ฐ ๋น์ ์์ ์ผ๋ก ์ข ๋ฃ๋์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๊ด์ฑ์ ๊นจ๋จ๋ ธ์ ๋, ์ด ํธ๋์ญ์ ์ ์ผ๋ถ๊ฐ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋์๋๋ผ๋ ํธ๋์ญ์ ์ ์์์ฑ์ ๊ตฌํํ๊ธฐ ์ํด ์ด ํธ๋์ญ์ ์ด ํํ ๋ชจ๋ ์ฐ์ฐ์ ์ทจ์(Undo)ํ๋ ์ฐ์ฐ์ ๋๋ค.
Rollback ์์๋ ํด๋น ํธ๋์ญ์ ์ ์ฌ์์ํ๊ฑฐ๋ ํ๊ธฐํฉ๋๋ค.
์์์ฑ(Atomicity), All or Nothing
ํธ๋์ญ์ ์ ๋ชจ๋ ์ฐ์ฐ๋ค์ ์ ์์ ์ผ๋ก ์ํ ์๋ฃ๋๊ฑฐ๋ ์๋๋ฉด ์ ํ ์ด๋ ํ ์ฐ์ฐ๋ ์ํ๋์ง ์์ ์ํ๋ฅผ ๋ณด์ฅํด์ผ ํฉ๋๋ค.
์ผ๊ด์ฑ(Consistency)
ํธ๋์ญ์ ์๋ฃ ํ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ผ๊ด๋ ์ํ๋ก ์ ์ง๋์ด์ผ ํฉ๋๋ค.
๋ ๋ฆฝ์ฑ(Isolation)
ํ๋์ ํธ๋์ญ์ ์ด ์คํํ๋ ๋์ค์ ๋ณ๊ฒฝํ ๋ฐ์ดํฐ๋ ์ด ํธ๋์ญ์ ์ด ์๋ฃ๋ ๋๊น์ง ๋ค๋ฅธ ํธ๋์ญ์ ์ด ์ฐธ์กฐํ์ง ๋ชปํฉ๋๋ค.
์ง์์ฑ(Durability)
์ฑ๊ณต์ ์ผ๋ก ์ํ๋ ํธ๋์ญ์ ์ ์์ํ ๋ฐ์๋์ด์ผ ํฉ๋๋ค.
๊ฒฉ๋ฆฌ ์์ค(Isolation Level)์ด๋?
ํธ๋์ญ์ ์์ ์ผ๊ด์ฑ์ด ์๋ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ๋๋ก ํ๋ ์์ค
๊ฒฉ๋ฆฌ ์์ค์ ํ์์ฑ
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ACID ์์ฑ์ ๋ฐ๋ผ ํธ๋์ญ์
์ด ์์์ ์ด๋ฉด์๋ ๋
๋ฆฝ์ ์ธ ์ํ์ ํ๋๋ก ํฉ๋๋ค. ๊ทธ๋์ Locking
์ด๋ผ๋ ๊ฐ๋
์ด ๋ฑ์ฅํ๊ฒ ๋์ต๋๋ค. Locking
์ ํ๋์ ํธ๋์ญ์
์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃจ๋ ๋์ ๋ค๋ฅธ ํธ๋์ญ์
์ด ๊ด์ฌํ์ง ๋ชปํ๊ฒ ๋ง๋ ๊ฒ์
๋๋ค. ํ์ง๋ง ๋ฌด์กฐ๊ฑด์ ์ธ Locking
์ผ๋ก ์ธํด ๋์์ ์ํ๋๋ ๋ง์ ํธ๋์ญ์
๋ค์ ์์๋๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ๋๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑ๋ฅ์ ๋จ์ด์ง๊ฒ ๋ฉ๋๋ค. ๋ฐ๋๋ก ์๋ต์ฑ์ ๋์ด๊ธฐ ์ํด Locking
๋ฒ์๋ฅผ ์ค์ธ๋ค๋ฉด ์๋ชป๋ ๊ฐ์ด ์ฒ๋ฆฌ ๋ ์ฌ์ง๊ฐ ์์ต๋๋ค. ๊ทธ๋์ ์ต๋ํ ํจ์จ์ ์ธ Locking
๋ฐฉ๋ฒ์ด ํ์ํฉ๋๋ค.
Read Uncommitted(Level 0)
SELECT
๋ฌธ์ฅ์ด ์ํ๋๋ ๋์ ํด๋น ๋ฐ์ดํฐ์Shared Lock
์ด ๊ฑธ๋ฆฌ์ง ์๋ ๋ ๋ฒจ- ํธ๋์ญ์ ์ ์ฒ๋ฆฌ์ค์ธ ํน์ ์์ง ์ปค๋ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ์ฝ๋ ๊ฒ์ ํ์ฉํฉ๋๋ค.
- ๋ฐ๋ผ์ ์ด๋ค ์ฌ์ฉ์๊ฐ A๋ผ๋ ๋ฐ์ดํฐ๋ฅผ B๋ผ๋ ๋ฐ์ดํฐ๋ก ๋ณ๊ฒฝํ๋ ๋์ ๋ค๋ฅธ ์ฌ์ฉ์๋ ์์ง ์๋ฃ๋์ง ์์(Uncommited ๋๋ Dirty) ํธ๋์ญ์ ์ด์ง๋ง ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ์ธ B๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
- ๊ทธ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
Read Committed(Level 1)
SELECT
๋ฌธ์ฅ์ด ์ํ๋๋ ๋์ ํด๋น ๋ฐ์ดํฐ์Shared Lock
์ด ๊ฑธ๋ฆฌ๋ ๋ ๋ฒจ- ํธ๋์ญ์ ์ด ์ํ๋๋ ๋์ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ์ ๊ทผํ ์ ์์ด ๋๊ธฐํ๊ฒ ๋ฉ๋๋ค.
- ์ฆ, Commit์ด ์ด๋ฃจ์ด์ง ํธ๋์ญ์ ๋ง ์กฐํํ ์ ์์ต๋๋ค.
- ๋ฐ๋ผ์ ์ด๋ค ์ฌ์ฉ์๊ฐ A ๋ผ๋ ๋ฐ์ดํฐ๋ฅผ B ๋ผ๋ ๋ฐ์ดํฐ๋ก ๋ณ๊ฒฝํ๋ ๋์ ๋ค๋ฅธ ์ฌ์ฉ์๋ ํด๋น ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค.
Repeatable Read(Level 2)
- ํธ๋์ญ์
์ด ์๋ฃ๋ ๋๊น์ง
SELECT
๋ฌธ์ฅ์ด ์ฌ์ฉํ๋ ๋ชจ๋ ๋ฐ์ดํฐ์Shared Lock
์ด ๊ฑธ๋ฆฌ๋ ๋ ๋ฒจ - ํธ๋์ญ์ ์ด ๋ฒ์ ๋ด์์ ์กฐํํ ๋ฐ์ดํฐ์ ๋ด์ฉ์ด ํญ์ ๋์ผํจ์ ๋ณด์ฅํฉ๋๋ค.
- ๋ฐ๋ผ์ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ๊ทธ ์์ญ์ ํด๋น๋๋ ๋ฐ์ดํฐ๊ฐ Commit ์ด ๋๊ธฐ ์ ์ ์์ ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
Serializable(Level 3)
- ํธ๋์ญ์
์ด ์๋ฃ๋ ๋๊น์ง
SELECT
๋ฌธ์ฅ์ด ์ฌ์ฉํ๋ ๋ชจ๋ ๋ฐ์ดํฐ์Shared Lock
์ด ๊ฑธ๋ฆฌ๋ ๋ ๋ฒจ - ์๋ฒฝํ ์ฝ๊ธฐ ์ผ๊ด์ฑ ๋ชจ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ๋ผ์ ๋ค๋ฅธ ์ฌ์ฉ์๋ ๊ทธ ์์ญ์ ํด๋น๋๋ ๋ฐ์ดํฐ์ ๋ํ ์์ ๋ฐ ์ ๋ ฅ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
Dirty Read
- Commit ๋์ง ์์ ์์ ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ํธ๋์ญ์ ์์ ์ฝ์ ์ ์๋๋ก ํ์ฉํ ๋ ๋ฐ์ํ๋ ํ์์ ๋๋ค.
- ์ด๋ค ํธ๋์ญ์ ์์ ์์ง ์คํ์ด ๋๋์ง ์์ ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ณด๊ฒ ๋๋ ํ์์ ๋๋ค.
Non-Repeatable Read
-
ํ ํธ๋์ญ์ ์์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฒ ์ํํ ๋ ๊ทธ ์ฌ์ด์ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ๊ฐ์ ์์ ๋๋ ์ญ์ ํจ์ผ๋ก์จ ๋ ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๊ฐ ์์ดํ๊ฒ ๋ํ๋๋ ๋น ์ผ๊ด์ฑ ํ์์ ๋๋ค.
-
์์
- ํธ๋์ญ์
1 -
SELECT * FROM person WHERE id = 10;
- ํธ๋์ญ์
2 -
UPDATE person SET age = 30 WHERE id = 10;
- ํธ๋์ญ์
1 -
SELECT * FROM person WHERE id = 10;
Phantom Read
-
ํ ํธ๋์ญ์ ์์์ ์ผ์ ๋ฒ์์ ๋ ์ฝ๋๋ฅผ ๋ ๋ฒ ์ด์ ์ฝ์ ๋, ์ฒซ ๋ฒ์งธ ์ฟผ๋ฆฌ์์ ์๋ ๋ ์ฝ๋๊ฐ ๋ ๋ฒ์งธ ์ฟผ๋ฆฌ์์ ๋ํ๋๋ ํ์์ ๋๋ค.
-
์ด๋ ํธ๋์ญ์ ๋์ค ์๋ก์ด ๋ ์ฝ๋๊ฐ ์ฝ์ ๋๋ ๊ฒ์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ํ๋ฉ๋๋ค.
-
์์
- ํธ๋์ญ์
1 -
SELECT * FROM person WHERE age BETWEEN 5 AND 55;
- ํธ๋์ญ์
2 -
INSERT INTO person VALUES(13, 'Alex', 25);
- ํธ๋์ญ์
1 -
SELECT * FROM person WHERE age BETWEEN 5 AND 55;
Serializable
์ ์ ํํ๊ฒ ๋๋ฉด ๋ฌธ์ ๊ฐ ๋๋ ํ์๋ค์ ๋ฐ์ํ์ง ์์ง๋ง ์ฑ๋ฅ์ด ๊ต์ฅํ ๋จ์ด์ง๋๋ค. ์๋ํ๋ฉด ๋ณ๋ ฌ์ ์ผ๋ก ํธ๋์ญ์
์ด ์คํ๋๋๋ผ๋ ๋ชจ๋ Commit ์ด ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผํ๋ฏ๋ก ์ฌ์ค์ ์ง๋ ฌ์ ์ผ๋ก ์คํ๋๋ค๊ณ ๋ณผ ์๊ฐ ์์ต๋๋ค.
๋๋ถ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์
์์๋ Read Committed
์ ์ฌ์ฉํฉ๋๋ค. Locking ์ ์ ํ ์ฌ์ฉํ๋ฏ๋ก ์ฑ๋ฅ๋ฉด์์๋ ์ค์ํ ํธ์ด๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๊ด์ฑ์ ๋ํด์๋ ์ค์ํ ํธ์
๋๋ค.
๋ง์ฝ ํ๋์ ํธ๋์ญ์
์์ ํ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ MQ๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด JPA์ @Transactional
์ ์ฌ์ฉํด๋ ๋ฌด๋ฐฉํฉ๋๋ค. ๊ทธ๋ฌ๋ ํ๋์ ํธ๋์ญ์
์์ ํ๋ ์ด์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ MQ๋ฅผ ์ฌ์ฉํด์ ์์ ์ด๋ ์ฝ๊ธฐ ์ฐ์ฐ ๋ฑ์ ์ํํ๊ฒ ๋๋ฉด Spring์ @Transactional
์ ์ฌ์ฉํด์ฃผ์ด์ผ ํฉ๋๋ค.
๊ฒฉ๋ฆฌ ์์ค ์ค์
@Transactional(isolation = Isolation.READ_COMMITTED)
๋๋
READ_UNCOMMITTED
= 1READ_COMMITTED
= 2REPEATABLE_READ
= 4SERIALIZABLE
= 8
spring.jpa.properties.hibernate.connection.isolation=2
์์์ฑ ์ปจํ
์คํธ(Persistence Context)์ ๋ด๋ถ์๋ ์ํฐํฐ๋ฅผ ๋ณด๊ดํ๋ ์ ์ฅ์๊ฐ ์๋๋ฐ ์ด๊ฒ์ 1์ฐจ ์บ์(First Level Cache)
๋ผ๊ณ ๋ถ๋ฆ
๋๋ค. 1์ฐจ ์บ์๋ ํธ๋์ญ์
์ด ์์ํ๊ณ ์ข
๋ฃํ ๋๊น์ง๋ง ์ ํจํฉ๋๋ค. ์ฆ, ํธ๋์ญ์
๋จ์์ ์บ์์
๋๋ค. ๋ฐ๋ผ์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด๋ก ๋ณด๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ ํ์๋ฅผ ํ๊ธฐ์ ์ผ๋ก ์ค์ด์ง๋ ๋ชปํฉ๋๋ค.
JPA ๊ตฌํ์ฒด๋ค์ ์ ํ๋ฆฌ์ผ์ด์
๋จ์์ ์บ์๋ฅผ ์ง์ํ๋๋ฐ ์ด๊ฒ์ ๊ณต์ ์บ์
๋๋ 2์ฐจ ์บ์(Second Level Cache)
๋ผ๊ณ ๋ถ๋ฆ
๋๋ค. 2์ฐจ ์บ์๋ฅผ ์ ์ฉํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์กฐํ ์ฑ๋ฅ์ ํฅ์ํ ์ ์์ต๋๋ค.
1์ฐจ ์บ์๋ ์์์ฑ ์ปจํ ์คํธ ๋ด๋ถ์ ์์ต๋๋ค. ์ํฐํฐ ๋งค๋์ ๋ก ์กฐํํ๊ฑฐ๋ ๋ณ๊ฒฝํ๋ ๋ชจ๋ ์ํฐํฐ๋ 1์ฐจ ์บ์์ ์ ์ฅ๋ฉ๋๋ค. ํธ๋์ญ์ ์ Commit ํ๊ฑฐ๋ Flush ๋ฅผ ํ๊ฒ ๋๋ฉด 1์ฐจ ์บ์์ ์๋ ์ํฐํฐ์ ๋ณ๊ฒฝ ์ฌํญ๋ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํฉ๋๋ค.
JPA๋ฅผ ์คํ๋ง ํ๋ ์์ํฌ ๊ฐ์ ์ปจํ ์ด๋ ์์์ ์คํํ๋ฉด ํธ๋์ญ์ ์ ์์ํ ๋ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์์ฑํ๊ณ ํธ๋์ญ์ ์ ์ข ๋ฃํ ๋ ์์์ฑ ์ปจํ ์คํธ๋ ์ข ๋ฃํฉ๋๋ค.
1์ฐจ ์บ์๋ ํ์ฑํํ๊ฑฐ๋ ๋นํ์ฑํํ ์ ์๋ ์ต์ ์ด ์๋๊ณ ์์์ฑ ์ปจํ ์คํธ ์์ฒด๊ฐ ์ฌ์ค์ 1์ฐจ ์บ์์ ๋๋ค.
2์ฐจ ์บ์๋ ์ ํ๋ฆฌ์ผ์ด์ ๋จ์์ ์บ์์ ๋๋ค. ๋ฐ๋ผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ข ๋ฃํ ๋๊น์ง ์บ์๊ฐ ์ ์ง๋ฉ๋๋ค. 2์ฐจ ์บ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ํฐํฐ ๋งค๋์ ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ ์ฐ์ 2์ฐจ ์บ์์์ ์ฐพ๊ณ ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฐพ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋์ 2์ฐจ ์บ์๋ฅผ ์ ์ ํ ํ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ ํ์๋ฅผ ํ๊ธฐ์ ์ผ๋ก ์ค์ผ ์ ์์ต๋๋ค.
2์ฐจ ์บ์๋ ๋์์ฑ์ ๊ทน๋ํํ๋ ค๊ณ ์บ์ํ ๊ฐ์ฒด๋ฅผ ์ง์ ๋ฐํํ์ง ์๊ณ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด์ ๋ฐํํฉ๋๋ค. ๋ง์ฝ ์บ์ํ ๊ฐ์ฒด๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ฉด ์ฌ๋ฌ ๊ณณ์์ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋์์ ์์ ํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋๋ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ๊ฐ์ฒด์ ๋ฝ์ ๊ฑธ์ด์ผ ํ๋๋ฐ ์ด๋ ๊ฒ ํ๋ฉด ๋์์ฑ์ด ๋จ์ด์ง ์ ์์ต๋๋ค. ๋ฝ์ ๋นํ๋ฉด ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๋น์ฉ์ ์์ฃผ ์ ๋ ดํ๋ฏ๋ก 2์ฐจ ์บ์๋ ๋ณต์ฌ๋ณธ์ ๋ฐํํ๊ฒ ๋ฉ๋๋ค.
Hibernate ๊ฐ ์ง์ํ๋ ์บ์๋ ํฌ๊ฒ 3๊ฐ์ง๊ฐ ์์ต๋๋ค.
1. ์ํฐํฐ ์บ์
- ์ํฐํฐ ๋จ์๋ก ์บ์ํฉ๋๋ค. ์๋ณ์(ID)๋ก ์ํฐํฐ๋ฅผ ์กฐํํ๊ฑฐ๋ ์ปฌ๋ ์ ์ด ์๋ ์ฐ๊ด ๊ด๊ณ์ ์๋ ์ํฐํฐ๋ฅผ ์กฐํํ ๋ ์ฌ์ฉํฉ๋๋ค.
2. ์ปฌ๋ ์ ์บ์
- ์ํฐํฐ์ ์ฐ๊ด๋ ์ปฌ๋ ์ ์ ์บ์ํฉ๋๋ค. ์ปฌ๋ ์ ์ด ์ํฐํฐ๋ฅผ ๋ด๊ณ ์์ผ๋ฉด ์๋ณ์ ๊ฐ๋ง ์บ์ํฉ๋๋ค.
3. ์ฟผ๋ฆฌ ์บ์
- ์ฟผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ฅผ ํค๋ก ์ฌ์ฉํด์ ์บ์ํฉ๋๋ค. ๊ฒฐ๊ณผ๊ฐ ์ํฐํฐ๋ฉด ์๋ณ์ ๊ฐ๋ง ์บ์ํฉ๋๋ค.
์์กด์ฑ ์ค์
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>
ํ๋กํผํฐ ์ค์
spring.jpa.properties.hibernate.cache.use_second_level_cache = true
๐จ 2์ฐจ ์บ์ ํ์ฑํํฉ๋๋ค.spring.jpa.properties.hibernate.cache.region.factory_class
๐จ 2์ฐจ ์บ์๋ฅผ ์ฒ๋ฆฌํ ํด๋์ค๋ฅผ ์ง์ ํฉ๋๋ค.spring.jpa.properties.hibernate.generate_statistics = true
๐จ ํ์ด๋ฒ๋ค์ดํธ๊ฐ ์ฌ๋ฌ ํต๊ณ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๊ฒ ํด์ฃผ๋๋ฐ ์บ์ ์ ์ฉ ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
- L2C puts: 2์ฐจ ์บ์์ ๋ฐ์ดํฐ ์ถ๊ฐ
- L2C hits: 2์ฐจ ์บ์์ ๋ฐ์ดํฐ ์ฌ์ฉ
- L2C miss: 2์ฐจ ์บ์์ ํด๋น ๋ฐ์ดํฐ ์กฐํ ์คํจ -> ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ
spring:
jpa:
properties:
hibernate:
generate_statistics: true
format_sql: true
cache:
use_second_level_cache: true
region:
factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory
javax:
persistence:
sharedCache:
mode: ENABLE_SELECTIVE
logging:
level:
net:
sf:
ehcache: debug
์ํฐํฐ ์บ์์ ์ปฌ๋ ์ ์บ์
@Cacheable
๐จ ์ํฐํฐ ์บ์ ์ ์ฉ์ ์ฌ์ฉํ๋ ์ด๋ ธํ ์ด์
@Cache
๐จ ํ์ด๋ฒ๋ค์ดํธ ์ ์ฉ์ ๋๋ค. ์บ์์ ๊ด๋ จ๋ ๋ ์ธ๋ฐํ ์ค์ ์ ํ ๋ ์ฌ์ฉํฉ๋๋ค. ๋ํ ์ปฌ๋ ์ ์บ์๋ฅผ ์ ์ฉํ ๋์๋ ์ฌ์ฉํฉ๋๋ค.
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Entity
public class Course {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@OneToMany(mappedBy = "course")
private List<Review> reviews = new ArrayList<>();
...
}
CacheConcurrencyStrategy ์์ฑ
READ_ONLY
๐จ ์์ฃผ ์กฐํํ๊ณ ์์ ์์ ์ ํ์ง ์๋ ๋ฐ์ดํฐ์ ์ ํฉํฉ๋๋ค.
READ_WRITE
๐จ ์กฐํ ๋ฐ ์์ ์์ ์ ํ๋ ๋ฐ์ดํฐ์ ์ ํฉํฉ๋๋ค. Phantom Read ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก SERIALIZABLE ๊ฒฉ๋ฆฌ ์์ค์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
NONSTRICT_READ_WRITE
๐จ ๊ฑฐ์ ์์ ์์ ์ ํ์ง ์๋ ๋ฐ์ดํฐ์ ์ ํฉํฉ๋๋ค.