๐ง ๋ค์ด๊ฐ๊ธฐ ์
์ฝํ๋ง์ผ๋ก JPA Entity๋ฅผ ์ค๊ณํ๋ ๋์ค ๋ฌธ๋ ์๋ฌธ์ด ์๊ธฐ๊ฒ ๋์๋ค.
์ํ๋ง์์๋ ๋ณดํต ์ํฐํฐ์ ํ๋๋ฅผ ์ ์ํ ๋ private๋ก ์ธ๋ถ๋ก์ ํ๋์ ๋ ธ์ถ์ ๋ง๊ณ , ๋กฌ๋ณต ์ด๋ ธํ ์ด์ ์ ํตํด getter๋ setter๋ฅผ ์ ๊ณตํ์ฌ ํด๋น ๋ฉ์๋๋ฅผ ํตํด ์ ๊ทผํ ์ ์๋๋ก ํ์ฌ ๊ฐ์ฒด์งํฅ์ ์ธ ํน์ฑ์ ๋ง์กฑ์์ผ ์ฃผ์๋ค.
๊ทธ๋ฌ๋ Spring ๊ณต์๋ฌธ์๋ฅผ ์ดํด๋ณด๋ฉด, ์ฝํ๋ง์ Entity๋ฅผ ์ค๊ณํ ๋๋ private์ ๊ฐ์ ์ ๊ทผ์ ์ด์๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.
๋ฐ๋ผ์ ์ private ์ ๊ทผ์ ์ด์๋ฅผ ์ฌ์ฉํ์ง ์๋์ง, ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ๊ฐ์ฒด์งํฅ์ ์ธ ํน์ฑ์ ๋ง์กฑํ๋ฉด์ ์ค๊ณํ ์ ์๋์ง์ ๋ํด ์์๋ณด๊ณ ์ ํ๋ค.
๐ธKotlin์ Field์ ๊ฐ๋ ์ด ์๋ Property์ ๊ฐ๋
ํ๋ก๊ทธ๋๋ฐ์์ ํ๋(Field)์ ํ๋กํผํฐ(property)๋ ๋น์ทํด ๋ณด์ด์ง๋ง ์ค์ํ ์ฐจ์ด์ ์ด ์๋ค.
1๏ธโฃ Field
public class Car {
private final String name;
private final Integer distance;
public Car(String name, Integer distance){
this.name = name;
this.distance = distance;
}
}
์ฐ์ ์ฐ๋ฆฌ๊ฐ ํํ ์ฌ์ฉํ๋ java์์๋ ์์ ์ฝ๋์์ name๊ณผ distance์ ๋ณ์๋ค์ field์ ๊ฐ๋ ์ผ๋ก ์ ๊ทผํ๋ค.
์ฆ, ์์์ ๋ค๋ฃจ๋ ํด๋์ค์ ์ํ๋ฅผ ๋ํ๋ด๋ field๋ ๊ฐ ๊ทธ ์์ฒด์ด๋ค.
๋ฐ๋ผ์ ํด๋น field๋ฅผ private๋ก ์ ๊ทผ์ ์ด์๋ฅผ ์ค์ ํ์ฌ Entity์ ์ํ๋ฅผ ์ธ๋ถ๋ก ๋ ธ์ถ์ํค์ง ์๊ณ , getter๋ setter๋ฅผ ํตํด ์ ๊ทผํ๋ ๊ฒ์ด ๊ฐ์ฒด์งํฅ์ ์ธ ํน์ฑ ์ค ์บก์ํ๋ฅผ ์งํค๋ฉฐ ์ค๊ณํ ์ ์๋ค.
2๏ธโฃ Property
class Car(
val name: String, // ๋ถ๋ณ ๋ณ์
var distance: Int
)
๋ฐ๋ฉด, kotlin์์๋ field์ ๊ฐ๋ ์ด ์๋ property์ ๊ฐ๋ ์ด๋ค.
์ฝํ๋ฆฐ์ ๊ณต์๋ฌธ์๋ฅผ ์ดํด๋ณด๋ฉด field๋ผ๋ ์ฉ์ด ๋์ Property๋ผ๋ ์ฉ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด Field์ Property์ ์ฐจ์ด์ ์ ๋ฌด์์ผ๊น?
๐น Property๋?
ํ๋กํผํฐ(Property)๋ ๊ฐ์ฒด์ ์์ฑ(๊ฐ)์ ๋ค๋ฃฐ ๋ ์ฌ์ฉํ๋ ๊ฐ๋ ์ผ๋ก,
ํ๋(Field)๋ฅผ ๊ฐ์ธ๊ณ Getter(์ฝ๊ธฐ)์ Setter(์ฐ๊ธฐ)๋ฅผ ํตํด ์ ์ดํ ์ ์๋๋ก ๋ง๋ ๋ค.
์์ ์์๋ก ๋ค์ ๋์์ ๋ง์ฝ ์์ ์ฝ๋๋ฅผ ์๋ฐ๋ก ๋์ปดํ์ผ ํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
public class Car {
private final String name; // final ํ๋ (Setter ์์)
private int distance;
public Car(String name, int distance) {
this.name = name;
this.distance = distance;
}
public String getName() { // Getter๋ง ์กด์ฌ
return name;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) { // distance๋ง Setter ์์
this.distance = distance;
}
}
์์ ๋์ปดํ์ผ ๋ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๋ก ์ ๋ด๋ฆด ์ ์๋ค.
- Kotlin์์ var์ ์ฌ์ฉํ๋ฉด Java์์๋ final ํ๋ + getter/setter๊ฐ ์๋ ์์ฑ๋จ.
- Kotlin์์ val์ ์ฌ์ฉํ๋ฉด Java์์ getter๋ง ์์ฑ๋๊ณ setter๋ ์์.
- Kotlin์ ์์ฑ์๋ Java์์๋ ์ผ๋ฐ์ ์ธ public ์์ฑ์๋ก ๋ณํ๋จ.
๐ก ์ฝํ๋ฆฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ํด๋์ค, ๋ฉ์๋, ํ๋กํผํฐ๊ฐ final์ด๋ค.
ํ์ง๋ง JPA๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด allOpen ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ open์ผ๋ก ๋ฐ๋๋ค.
(์ฐธ๊ณ : https://kotlinlang.org/docs/all-open-plugin.html)
Kotlin์์๋ ํ๋กํผํฐ ๊ฐ๋ ์ ์ฌ์ฉํ์ฌ ๋ถํ์ํ ์ฝ๋ ์์ฑ์ ์ค์ด๊ณ , Getter์ Setter๋ฅผ ํตํด ํ๋๋ฅผ ๊ฐ์ ์ ์ผ๋ก ์กฐ์ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ด๋ฌํ ๋ฐฉ์ ๋๋ถ์ Java๋ก ๋์ปดํ์ผ๋ ์ฝ๋์์๋ Entity๋ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์บก์ํ ์ํ๋ฅผ ์ ์งํ ์ ์์ด, ๋ณ๋์ ์ ๊ทผ ์ ์ด์๋ฅผ ์ค์ ํ์ง ์์๋ ๊ฐ์ฒด๋ฅผ ์์ ํ๊ฒ ๋ณดํธํ ์ ์๋ค.
๊ทธ๋ฐ๋ฐ๋ ์ฌ์ ํ ์ฐ์ฐํ ๋ถ๋ถ์ด ๋จ๋๋ค.
๋น๋ก ํ๋ ์์ฒด๋ ์ธ๋ถ์ ์ง์ ๋
ธ์ถ๋์ง ์์ง๋ง, ํ๋กํผํฐ๋ฅผ ํตํด Entity์ ์ํ๊ฐ ๊ทธ๋๋ก ์ธ๋ถ์ ๊ณต๊ฐ๋๋ฏ๋ก ์ธ์ ๋ ์ง ์ฝ๊ฒ ์ ๊ทผํ๊ณ ๋ณ๊ฒฝํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ ์ธ๋ฐํ ์ ์ด๋ฅผ ์ํด์๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
๐ธKotlin Entity๋ฅผ ๊ฐ์ฒด์งํฅ์ ์ผ๋ก ์ค๊ณํด ๋ณด์.
1๏ธโฃ ์ ๊ทผ ์ ์ด์ private๋ก ์ ์ธํ๊ธฐ
์ธ๋ถ๋ก ๊ฐ์ ๋ ธ์ถ์ํค์ง ์๊ธฐ ์ํด ๊ฐ์ฅ ์ฒซ ๋ฒ์งธ๋ก ๋ ์ค๋ฅด๋ ๋ฐฉ๋ฒ์ด๋ค.
@Entity
@Table(name = "user")
class User(
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0L,
@Column(name = "email", nullable = false, unique = true)
var email: String,
@Column(name = "password", nullable = false)
var pw: String,
@Column(name = "name", nullable = false)
var name: String,
)
์์ ๊ฐ์ User์ ์ํฐํฐ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด ๋ณด์.
ํ์ฌ ์์ ์ํฐํฐ์์๋ email, pw, name๊ณผ ๊ฐ์ ์ปฌ๋ผ๋ค์ด ์ธ๋ถ์ ๋ ธ์ถ๋์ด ์ฝ๊ฒ ์ ๊ทผํ๊ณ ๋ณ๊ฒฝ๋ ์ ์๋ ๊ฐ๋ค์ด๋ค.
@Entity
@Table(name = "user")
class User(
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private var id: Long = 0L,
@Column(name = "email", nullable = false, unique = true)
private var email: String,
@Column(name = "password", nullable = false)
private var pw: String,
@Column(name = "name", nullable = false)
private var name: String,
)
์์ ๊ฐ์ด private๋ก ์ ๊ทผ์ ์ด์๋ฅผ ์ค์ ํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์ด๋ ๊ฒ ์ค์ ํ๋ฉด ์ด์ Entity ์ธ๋ถ์์ ์ ๊ทผ์ ํ ์ ์๊ฒ ๋๊ณ ๊ฐ์ ๋ณ๊ฒฝํ ์๋ ์๊ฒ ๋๋ค
fun getEmail =
email;
๋ฐ๋ผ์, ์์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ ์ํจ์ผ๋ก์จ ์ ๊ทผ์ด๋ ๋ณ๊ฒฝ์ด ํ์ํ ๋ณ์์ ๋ํด์๋ getter๋ setter๋ฅผ ๋ณ๋๋ก ์ ๊ณตํด์ค์ผ ํ๋ค.
์ฌ๊ธฐ์ ๋ชจ์์ด ๋ฐ์ํ๋ค.
1. Lombok์ ์ง์ํ๋ ์๋ฐ์ ๋ฌ๋ฆฌ, Kotlin์ ์ง์ ์ ์ผ๋ก ํ๋กํผํฐ๋ฅผ ๊ด๋ฆฌํด์ผ ํ๋ค
์ผ๋จ ์ฒซ ๋ฒ์งธ๋ก, ์ฝํ๋ฆฐ์ ๋ถํ์ํ ์ฝ๋ ์์ฑ์ ์ค์ด๋ ๊ฒ์ ์ฒ ํ์ผ๋ก ํ๋ ์ธ์ด์ด๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ์ ๊ทผํ๊ฑฐ๋ ๋ณ๊ฒฝํด์ผ ํ๋ ๋ณ์๋ง๋ค ์ผ์ผ์ด getter๋ setter๋ฅผ ์ง์ ํ๊ฒ ๋๋ฉด ์ฝ๋๊ฐ ๋๋ฌด ์ฅํฉํด์ง๋ค.
์ํ๋ง์์๋ ์ด๋ฌํ getter๋ setter๋ก ์ธํด ์ฝ๋๊ฐ ๊ธธ์ด์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ์ ๋กฌ๋ณต ์ด๋ ธํ ์ด์ ์ ์ ๊ณตํ์ง๋ง, ์ฝํ๋ง์์๋ ํ๋กํผํฐ์ ๊ฐ๋ ์ด๊ธฐ ๋๋ฌธ์ ๋กฌ๋ณต ์ด๋ ธํ ์ด์ ์ด ์ ๊ณต๋์ง ์๋๋ค. ๊ทธ๋์ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฝ๋๊ฐ ๊ธธ์ด์ง๋ค.
2. Kotlin์ ํ๋กํผํฐ๋ ์ปดํ์ผ ๊ณผ์ ์์ Java ๋ฐ์ดํธ์ฝ๋๋ก ๋ณํ๋๋ค
์์์๋ ๋ค๋ค๋ฏ์ด ์ฝํ๋ฆฐ์ ํ๋กํผํฐ์ ๊ฐ๋ ์ด๋ค. ๊ทธ๋ฆฌ์ฝ ์ฝํ๋ฆฐ์ ์ปดํ์ผ ๊ณผ์ ์์ ์๋ฐ ๋ฐ์ดํธ ์ฝ๋๋ก ๋ณํ๋์ด ์คํ๋๋๋ฐ, ์ด๋ ์๋ฐ ๋์ปดํ์ผ ๊ณผ์ ์์ ์๋์ผ๋ก getter์ setter๊ฐ ์์ฑ์ด ๋๋ค.
class User{
...
private Long getId() {
return id;
}
private String getEmail() {
return email;
}
private String getPw() {
return pw;
}
...
}
Kotlin์์ private์ผ๋ก ์ ์ธํ ํ๋กํผํฐ๋ private ํ getter์ setter๋ก ๋ณํ๋์์ง๋ง, ์ฐ๋ฆฌ๋ ์ด๋ฅผ ๋ค์ public์ผ๋ก ์ด์ด์ผ ํ๋ค.
์ฆ, ์๋ Kotlin์์ ์๋์ ์ผ๋ก private var๋ก ์ ์ธํ์ฌ ์ธ๋ถ์์ ์ ๊ทผ์ ๋ง์์์๋ ๋ถ๊ตฌํ๊ณ , getter์ setter๋ฅผ ๋ช ์์ ์ผ๋ก ๋ค์ ๋ง๋ค์ด public์ผ๋ก ์ด์ด์ผ ํ๋ ๋ถํ์ํ ๊ณผ์ ์ด ๋ฐ์ํ๋ค. ์ด ๊ณผ์ ์ Kotlin์ ๋ถํ์ํ ์ฝ๋๋ฅผ ์ค์ด๋ ค๋ ์ฒ ํ๊ณผ ๋ง์ง ์๋๋ค.
๊ฒฐ๊ตญ, Kotlin์์ ๊ฐ์ฒด์ ์บก์ํ๋ฅผ ์ ์งํ๋ฉด์๋ ์ธ๋ฐํ ์ ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ ค๋ฉด, setter๋ฅผ ๋ง๊ณ getter๋ง ์ ๊ณตํ๊ฑฐ๋, ์์ ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ถ๋ณ(immutable)ํ๋๋ก ์ค๊ณํ๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํด์ผ ํ๋ค.
2๏ธโฃ val๋ก๋ง ๋ณ์๋ฅผ ์ง์ ?
@Entity
@Table(name = "user")
class User(
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@Column(name = "email", nullable = false, unique = true)
val email: String,
@Column(name = "password", nullable = false)
val pw: String,
@Column(name = "name", nullable = false)
val name: String,
)
๋ค์์ผ๋ก ์๊ฐํ ์ ์๋ ๋ถ๋ถ์ var์ด ์๋ ๋ถ๋ณ์ ๋ํ๋ด๋ var๋ก ๋ณ์๋ฅผ ์ ์ธํ๋ ๊ฒ์ด๋ค.
์๋ํ๋ฉด ์ฐ๋ฆฌ๊ฐ ๊ณ ๋ คํ๋ ๋ถ๋ถ์ด ์๋์น ์๊ฒ setter๊ฐ ์ธ๋ถ๋ก ๋ ธ์ถ๋์ด ๊ฐ๋ฐ์๋ค์ ์ค์๋ก ์ธํด entity์ ์ํ ๊ฐ์ ๋ณํ๊ฐ ์๊ธฐ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ var์ด ์๋ val๋ก ๋ณ์๋ฅผ ์ ์ธํ๊ฒ ๋๋ฉด ์๋ฐ๋ก ๋์ปดํ์ผ๋๋ ๊ณผ์ ์์ getter๋ง ์์ฑ๋ ๊ฒ์ด๊ณ ์ธ๋ถ๋ก๋ถํฐ์ ์ํฐํฐ๊ฐ ์๋์น ์๊ฒ ๋ณ๊ฒฝ๋ ์๋ ์๋ค๋ ๋ฌธ์ ์ ์ ํด๊ฒฐ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ฉด ๋ณ๊ฒฝํ ๊ฐ๋ง var๋ก ๋๊ณ , ๋ณ๊ฒฝ๋์ง ์์ ๊ณ ์ ์ ๊ฐ๋ค์ val๋ก ์ค์ ํ๋ฉด ๋ฌธ์ ๊ฐ ๊ธ๋ฐฉ ํด๊ฒฐ๋ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค.
ํ์ง๋ง ์ด๋ฌํ ์ ๊ทผ๋ฐฉ์์ JPA์ Hibernate ๋ฌธ์๋ ์ํฐํฐ๊ฐ ์ง์ผ์ผ ํ๋ ์กฐ๊ฑด 3๊ฐ์ง์ ์๋ฐฐ๋๋ค.
์ฐ์ val๋ก ์ ์ํ๋ ๊ฒฝ์ฐ ์๋ฐ์์ ๋์ปดํ์ผ ๋์์ ๋๋ฅผ ๋ค์ ํ๋ฒ ์ดํด๋ณด์.
val email: String
์์ ๊ฐ์ ๋ณ์๋ฅผ ์๋ฐ๋ก ๋์ปดํ์ผํ๋ฉด
private final String email;
public void getEmail(){
return email;
}
private final๋ก ์ ์ธ๋ ํ๋๊ฐ ์๊ธฐ๊ฒ ๋๋ค.
๐จJPA & Hibernate ๊ณต์ ๋ฌธ์ ๊ถ์ฅ ์ฌํญ
์ด๋, final ํค์๋๊ฐ ๋ฌธ์ ๊ฐ ๋๋ ๊ฒ์ธ๋ฐ ๋ค์ ๋ณธ๋ก ์ผ๋ก ๋์์ JPA์ Hibernate ๋ฌธ์๊ฐ ์๊ตฌํ๋ ๊ฒ์ ์ดํด๋ณด์.
JPA ๊ณต์๋ฌธ์์๋ Entity๋ฅผ ์ค๊ณํ ๋ ์์ ๊ฐ์ ์กฐ๊ฑด์ ์ ์ํ๊ณ ์๋ค.
- Class๋ final๋ก ์ ์ธ๋์ด์๋ ์๋๋ค.
- Method๋ฅผ final๋ก ์ ์ธํ๋ฉด ์๋๋ค.
- Persistent Instance Variable(field)์ final๋ก ์ ์ธํ๋ฉด ์๋๋ค.
์ฆ, field๊ฐ์ ๋ํด์ final๋ก ์ ์ธํ์ง ์๋ ๊ฒ์ ์์น์ผ๋ก ํ๊ณ ์๋ค.
๊ทธ๋ฆฌ๊ณ Hibernate์ ๊ณต์๋ฌธ์์๋ ๋น์ทํ ๋ด์ฉ์ ํ์ธํ ์ ์๋ค.
- Hibernate์ Lazy-Loading(์ง์ฐ ๋ก๋ฉ) ๊ธฐ๋ฅ์ ์ํฐํฐ๋ฅผ ํ๋ก์(proxy) ๊ฐ์ฒด๋ก ๊ฐ์ธ์ ํ์ํ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋๋ก ๋์ํ๋ค.
- ํ์ง๋ง final ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด Hibernate๊ฐ ํ๋ก์๋ฅผ ์์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ Lazy-Loading์ ์ฌ์ฉํ ์ ์๋ค.
๋ฐ๋ผ์ Hibernate์์๋ final ํด๋์ค๋ฅผ ํผํ๋ ๊ฒ์ด ์ข๋ค.
-getter์ setter๋ฅผ final๋ก ์ ์ธํ๋ ๊ฒ๋ ์ง์ํด์ผ ํ๋ค.
Hibernate๋ getter๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ lazy-loading์ ์ํํ๋๋ฐ, final์ด๋ฉด ์ด๋ฅผ ๋ง์๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ.
-์ฑ๋ฅ ์ต์ ํ(performance tuning)๋ฅผ ๊ณ ๋ คํ๋ค๋ฉด final ํค์๋๋ฅผ ํผํ๋ ๊ฒ์ด Hibernate์ ๋ ์ ๋ง๋๋ค.
Hibernate๋ Java ๊ธฐ๋ฐ์ ORM(Object-Relational Mapping) ํ๋ ์์ํฌ๋ก, ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ด์ ๋งคํ์ ์๋์ผ๋ก ์ํํ์ฌ SQL์ ์ง์ ์์ฑํ์ง ์๊ณ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์กฐ์ํ ์ ์๋๋ก ๋์์ฃผ๋ ์ญํ ์ ํ๋ค.
๐น์ง์ฐ๋ก๋ฉ(Lazy-Loading)?
@Entity
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY) // Lazy Loading ์ ์ฉ
private List<Order> orders;
}
์ด๋, ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ํฐํฐ๋ฅผ ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ธ์ ์ง์ฐ ๋ก๋ฉ์ด๋ผ๋ ๊ธฐ๋ฅ์ ์ง์ํ๋๋ฐ, ์ด๋ ๊ฐ์ฒด๋ฅผ ์ฆ์ ๊ฐ์ ธ์ค์ง ์๊ณ ํด๋น ๋ฐ์ดํฐ๊ฐ ์ค์ ๋ก ํ์ํ ๋ ๋ก๋ํ๋ ๋ฐฉ์์ด๋ค. ์ฆ Lazy Loading์ ๋ถํ์ํ ๋ฐ์ดํฐ ๋ก๋๋ฅผ ๋ฐฉ์งํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐ ๊ธฐ์ฌํ๋ค.
hibernate-orm/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java at 8b021ac01f3a5d015d1db0ddd34fd687c
Hibernate's core Object/Relational Mapping functionality - hibernate/hibernate-orm
github.com
hibernate-orm์ AbstractLazyInitializer.java์ ์ฝ๋์ ๋์๊ณผ์ ์ ์กฐ๊ธ ๋ ์์ธํ๊ฒ ์ดํด๋ณด๊ณ ์ ํ๋ค.
Hibernate๋ ์ง์ฐ ๋ก๋ฉ(Lazy Loading)์ ๊ตฌํํ๊ธฐ ์ํด ์ํฐํฐ๋ฅผ ์ง์ ๋ก๋ํ์ง ์๊ณ EntityManager.find ํธ์ถ ์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ์ง ์๊ณ ์ํฐํฐ ํด๋์ค๋ฅผ ์์ํ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
AbstractLazyInitializer๋ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ค์ ์ํฐํฐ์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์งํ๊ณ , ์ด๊ธฐํ๋์ง ์์ ์ํ์์ ๋ฉ์๋ ํธ์ถ( (getter์ setter์ ๊ฐ์ ์์์ฑ ํ๋์ ์ ๊ทผํ๋ ๋ฉ์๋)์ด ๋ฐ์ํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํด๋น ์ํฐํฐ๋ฅผ ๋ก๋ํ์ฌ ์ฐธ์กฐ๋ฅผ ๊ฐฑ์ ํ๋ค. ์ดํ ํ๋ก์ ๊ฐ์ฒด๋ ๋ชจ๋ ๋ฉ์๋ ํธ์ถ์ ์๋ณธ ์ํฐํฐ์๊ฒ ์์ํ๋ค.
๋ฐ๋ผ์, Hibernate์ ์ง์ฐ ๋ก๋ฉ์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด ์ค์ ๋ฐ์ดํฐ ๋ก๋๋ฅผ ์ง์ฐ์ํค๊ณ , ํ์ํ ์์ ์๋ง ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ์ ์ํํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ ๊ฒ์ ์ดํด๋ณผ ์ ์๋ค.
๐ง val์ ์ฌ์ฉํ๋ฉด ์ง์ฐ๋ก๋ฉ ์ค ๋ฌธ์ ๊ฐ ๋ ๊น?
์ฌ์ค val๋ก Entity์ ํ๋กํผํฐ๋ฅผ ์ ์ํด๋ JPA, Hibernate์ ์ง์ฐ ๋ก๋ฉ์ด ์ ๋๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ด ์ธ ๊ฐ์ง์ด๋ค.
1. jpa๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด all-open ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ var, val์ ์๊ด์์ด open์ผ๋ก ๋์ํ๋ค.
Kotlin์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ํด๋์ค์ ๋ฉ์๋๊ฐ final์ด๋ฏ๋ก, JPA์์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋๋ก Kotlin ์ํฐํฐ ํด๋์ค๋ฅผ open์ผ๋ก ๋ง๋ค์ด์ผ ํ๋ค.
์ด๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๋ ๊ฒ์ด ๋ฐ๋ก all-open ํ๋ฌ๊ทธ์ธ์ด๋ค.
์์์ ์ง์ฐ๋ก๋ฉ์ ๊ณผ์ ์ ์ดํด๋ณด๋ฉด JPA์์๋ ์ํฐํฐ ํด๋์ค๋ฅผ ์์ํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. ์ด๋ ์ํฐํฐ ํด๋์ค๊ฐ open์ด์ด์ผ ์์์ด ๊ฐ๋ฅํ๋ค.
Kotlin์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ํด๋์ค๊ฐ final์ด๋ฏ๋ก, JPA๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด all-open ํ๋ฌ๊ทธ์ธ์ ํน์ ์ด๋ ธํ ์ด์ (@Entity, @MappedSuperclass, @Embeddable)์ด ๋ถ์ ํด๋์ค๋ฅผ ์๋์ผ๋ก open์ผ๋ก ๋ณ๊ฒฝํ๋ค.
2. ์ง์ฐ๋ก๋ฉ์ ์๋ณธ ์ํฐํฐ ์์ฑ ์์ฒด๋ฅผ ๋ค๋ก ๋ฏธ๋ฃจ๋ ๋ฐฉ์์ด๋ค.
User user = entityManager.find(User.class, 1L);
์ด ์ฝ๋๊ฐ ์คํ๋ ๋, Hibernate๋ ์ฆ์ User ์ํฐํฐ๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์๋๋ผ, ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
User userProxy = new HibernateProxy(); // ํ๋ก์ ๊ฐ์ฒด ์์ฑ
์ด ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ธฐ ์ ๊น์ง๋ ๊ฐ์ด ๋น์ด ์๋ค.
์ดํ getter ๋ฉ์๋์ธ user.getOrders()๋ฅผ ํธ์ถํ๋ฉด Hibernate๊ฐ DB์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ์ฌ ์๋ณธ ์ํฐํฐ๋ฅผ ์์ฑํ๊ณ ์ฐธ์กฐ๋ฅผ ์
๋ฐ์ดํธํ๋ค.
์ฆ, val์ ์ฌ์ฉํด๋ Hibernate์ ํ๋ก์๋ ์๋ณธ ์ํฐํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ์ด ์๋๋ผ, "์ค์ ์ํฐํฐ๋ฅผ ๋ก๋ฉํ๋ ์์ ์ ๋ฆ์ถ๋ ๋ฐฉ์"์ผ๋ก ๋์ํ๋ฏ๋ก ๋ถ๋ณ์ฑ์ด ๊นจ์ง์ง ์๋๋ค.
3. Field Access vs Property Access
์ค์ ์ํฐํฐ๋ฅผ ๋ก๋ฉํ๋ ์์ ์์ JPA์ ์ ๊ทผ๋ฐฉ์์ ๋ฐ๋ผ ๋๋๊ฒ ๋๋ค.
JPA์์ ์์์ฑ ์ํฐํฐ์ ์ ๊ทผํ ๋ 2๊ฐ์ง ๋ฐฉ์์ด ์๋ค.
- Field Access
- Property Access
Hibernate์ ๊ณต์๋ฌธ์์ ๋ฐ๋ฅด๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก @Id ์ด๋ ธํ ์ด์ ์ด ๋ถ๋ ์์น์ ๋ฐ๋ผ ์ ๊ทผ ๋ฐฉ์์ด ๋ฌ๋ผ์ง๋ค.
- Field Access : @Id ์ด๋ ธํ ์ด์ ์ด field์ ๋ถ์ ๊ฒฝ์ฐ
- Property Access : @Id ์ด๋ ธํ ์ด์ ์ด getter์ ๋ถ์ ๊ฒฝ์ฐ
JPA ๊ณต์๋ฌธ์์์๋ ํ๋กํผํฐ์ ์ ๊ทผ ๋ฐฉ์์ผ ๊ฒฝ์ฐ JavaBeans ์ปจ๋ฒค์ ์ ๋ฐ๋ผ์ผ ํ๋ค๊ณ ์ค๋ช ํ๊ณ ์์ผ๋ฉฐ, privateํ๋์ public ํ getter์ setter์ ์กฐํฉ์ผ๋ก ํ๋กํผํฐ๋ฅผ ํํํด์ผ ํ๋ค๊ณ ๋งํ๊ณ ์๋ค.
์ฆ ํ๋กํผํฐ์ ์ ๊ทผํ๊ธฐ ์ํด์๋ ๋ฐ๋์ setter๊ฐ ์์ด์ผ ํ๋๋ฐ
๊ทธ๋ฌ๋ฉด val์ setter๊ฐ ์์ฑ๋์ง ์์ผ๋ ๋ฌธ์ ๊ฐ ๋๋ ๊ฑฐ ์๋๊ฐ?
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด val์ ์ฌ์ฉํด๋ ๋ฌธ์ ๊ฐ ์๋ค.
์ฝํ๋ฆฐ์ ํ๋กํผํฐ์ ๊ฐ๋ ์ ์ฌ์ฉํ๊ณ ์์ง๋ง @Id ์ด๋ ธํ ์ด์ ์ผ๋ก ํ๋กํผํฐ ๋ณ์์ ์ ๊ทผํ ๋๋ ํ๋ ์ ๊ทผ ๋ฐฉ์์ด๋ค.
@Entity
class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0L, // ํ๋ ์ ๊ทผ ๋ฐฉ์
@Column(nullable = false)
var name: String
)
์์ ์ฝ๋๋ฅผ ์๋ฐ๋ก ๋์ปดํ์ผ ํ๊ฒ ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป๋๋ค.
@Entity
public class User {
@Id // ํ๋์ ์ ์ฉ๋จ (Field Access ๋ฐฉ์)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
์์ ๊ฐ์ด @Id ์ด๋ ธํ ์ด์ ์ด getter๊ฐ ์๋ ํ๋์ ๋ถ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ง์ฝ, ํ๋กํผํฐ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์ค์ ํ๊ณ ์ถ์ผ๋ฉด
@Entity
class User(
@get:Id // Getter์ @Id ์ ์ฉ (Property Access ๋ฐฉ์)
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0L,
@Column(nullable = false)
var name: String
)
@get:Id ์ด๋ ธํ ์ด์ ์ ํ์ฉํ๋ฉด ํ๋กํผํฐ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
(์ด๋๋ val์ ์ฌ์ฉํด์๋ ์๋๋ค.)
๋ฐ๋ผ์ val์ ์ฌ์ฉํด๋ JPA๋ ํ๋ ์ ๊ทผ ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ val์ ์ฌ์ฉํด๋ ๋ฌธ์ ๊ฐ ์๋ค๋ ์ ์ด๋ค.
๐ง๊ทธ๋ ๋ค๋ฉด val์ ๋ฌธ์ ๊ฐ ์๋ ๊ฑฐ ์๋๊น?
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด Hibernate ๊ตฌํ์ฒด์์"๋" ๋ฌธ์ ๊ฐ ์๋ค.
val์ ๋ค์ ์ ๋ฆฌํด ๋ณด์๋ฉด,
valํ๋กํผํฐ๋ ์๋ฐ๋ก ๋์ปดํ์ผ ํ๋ฉด field์ final์ด ๋ถ๊ณ , setter๊ฐ ์์ฑ๋์ง ์๋๋ค๋ ์ ์ ์ง๋๊ณ ์๋ค
์ด๋, setter๊ฐ ์์ฑ๋์ง ์๋ ์ ์ ํ๋ ์ ๊ทผ ๋ฐฉ์์ด๋ฉด ๊ด์ฐฎ๋ค๊ณ ์ธ๊ธํ๋ค.
ํ์ง๋ง final ํ๋์ ๊ฒฝ์ฐ์๋ ๊ด์ฐฎ์ ๊ทผ๊ฑฐ๋ฅผ ๋ ์ฐพ์๋ด์ผ ํ๋ค.
์ฐ์ hibernate์ ๊ฒฝ์ฐ์๋ ๋ด๋ถ์ ์ผ๋ก ์๋ฐ ๋ฆฌํ๋ ์ ์ field.set์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ final ํ๋์ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ค.
๋ฐ๋ผ์ final ํ๋์ ๋ํด์๋ ๋ฌธ์ ๊ฐ ์์ด ๋ณด์ด์ง๋ง,
javadoc ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด final field๊ฐ field.set์ ๋ค์ด๊ฐ๋ ๊ฒฝ์ฐ final ํ๋๊ฐ ์๋ ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ญ์ง๋ ฌํํ๊ฑฐ๋ ์ฌ๊ตฌ์ฑํ๋ ๋์์๋ง ์๋ฏธ๊ฐ ์์ผ๋ฉฐ ๋ค๋ฅธ ์ปจํ ์คํธ์์ ์ฌ์ฉํ๋ฉด ํ๋ก๊ทธ๋จ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ์ด ํ๋์ ์๋ ๊ฐ์ ๊ณ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ฅผ ํฌํจํ์ฌ ์์ธกํ ์ ์๋ ํจ๊ณผ๊ฐ ๋ฐ์ํ ์ ์๋ค๊ณ ์ค๋ช ํ๊ณ ์๋ค.
์ฆ, Hibernate๊ฐ final ํ๋๋ฅผ ๋ฆฌํ๋ ์ ์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด, ํ๋ก๊ทธ๋จ์ด ์๋ํ ๋๋ก ๋์ํ์ง ์์ ์ํ์ด ์๋ค
๋ํ Hibernate์ ๊ฐ์ JPA ๊ตฌํ์ฒด ์ค ํ๋์ธ Apache OpenJPA๋ final์ด ๋ถ์ผ๋ฉด transient ํ๋๋ก ์ทจ๊ธํด DB์ ์ ์ฅํ์ง ์๋๋ค.
์ด๋ฌํ ๋ถ๋ถ๋ค์ ์ด๋ฃจ์ด ๋ณด์์ ๋, ์์ง๊น์ง๋ Entity์์ val์ ํตํ ์ ์ธ์ ๋ฆฌ์คํฌ๊ฐ ์์ด ๋ณด์ธ๋ค.
3๏ธโฃ var + private set
๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๋ jpa entity๋ฅผ ์ ์ํ ๋ ์ต๋ํ val๋ฅผ ํผํ๋ ๊ฒ์ด ์ข๋ค๋ ๊ฒฐ๋ก ์ ๋ด๋ ธ์ผ๋ฏ๋ก, var์ ์ด์ฉํ๋ ์ด๋ป๊ฒ ํ๋กํผํฐ์ ๋ ธ์ถ์ ๋ง์ ์ ์์์ง์ ๋ํ ์๊ฐ์ ํด๋ด์ผ ํ๋ค.
Kotlin์์๋ ํ๋กํผํฐ๋ฅผ var๋ก ์ ์ธํ์ฌ Hibernate๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋๋ก ํ์ฉํ๋ฉด์๋, ์ธ๋ถ์์๋ Setter๋ฅผ ๋ง๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค.
์ฆ, Java๋ก ๋์ปดํ์ผ๋ ๋ Getter๋ public์ผ๋ก ์ ์งํ๋, Setter๋ private์ผ๋ก ์ ํํ๋ ๋ฐฉ์์ด๋ค.
@Entity
class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0L,
private set // ์ธ๋ถ์์ Setter ํธ์ถ์ ๋ง์
@Column(nullable = false)
var name: String,
private set
)
์์ ๊ฐ์ด private set์ ๋ณ๋๋ก ์ค์ ํด ์ค๋ค๋ฉด ์๋ฐ๋ก ๋์ปดํ์ผ ํ์ ๋์ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
public Long getId() { // Getter๋ public
return this.id;
}
private void setId(Long id) { // Setter๋ private
this.id = id;
}
public String getName() { // Getter๋ public
return this.name;
}
private void setName(String name) { // Setter๋ private
this.name = name;
}
}
์์ ์ฝ๋์ฒ๋ผ getter๋ public์ผ๋ก ์ค์ ๋๋ ๋ฐ๋ฉด setter์ ๋ํด์๋ private๋ก ์ค์ ์ด ๋๋ค.
๐จ๋ฌธ์ ์
ํ์ง๋ง ์์ ์ฝ๋์ฒ๋ผ ์คํํ๋ฉด ์๋ฌ๊ฐ ๋จ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Error: Private setters are not allowed for open properties
์ด๋ ์์์ ๋ค๋ฃจ์๋ Hibernate์ lazy loading์ ๋์ ๋ฐฉ์๊ณผ ๊ด๋ จ์ด ์๋ค.
์ง์ฐ ๋ก๋ฉ์ ์คํํ ๋ ์๋ณธ๊ฐ์ฒด๋ฅผ ์์๋ฐ๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋๋ฐ, ์ด๋์ ํต์ฌ์ ์์์ด๋ค.
๊ทธ๋ฌ๋ ์ฝํ๋ฆฐ์ ๊ฒฝ์ฐ ์๋ฐ์ ๋ฐ๋๋ก open์ ๋ถ์ฌ์ฃผ์ง ์๋ ์ด์ ๊ธฐ๋ณธ์ ์ผ๋ก final class, final method๊ฐ ๋๋๋ฐ, ์ด๋ฌํ ํํ๋ ์์์ด ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ JPA์์ allopen ํ๋ฌ๊ทธ์ธ์ ์ ๊ณตํ๊ณ , property์ ์๋์ผ๋ก open์ด ๋ถ๊ฒ ๋๋ค.
๋ฐ๋ผ์ open์ด ๋ถ์ ํ๋กํผํฐ์๋ private set์ ํ๋ฉด ์ปดํ์ผ ์๋ฌ๊ฐ ๋จ๋ ๊ฒ์ด๋ค.
(kotlin 1.9.x์์ ์ง์ ์คํํด ๋ณด๋๊น ์ปดํ์ผ ์๋ฌ๊ฐ ์ ๋จ๋๋ฐ ์ด ๋ถ๋ถ์ ๋ํ ํจ์น๊ฐ ์งํ๋์๋์ง ํ์ธ์ด ํ์ํ ๊ฒ ๊ฐ๋ค..)
4๏ธโฃ var + protected set
private set์ open class์์ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์กฐ๊ธ ๋ ์ํ๋ ์กฐ๊ฑด์ธ, protected set์ ๋ ์ฌ๋ฆด ์ ์๋ค.
Kotlin์์๋ var + protected set์ ์ฌ์ฉํ๋ฉด, ๊ฐ์ ํจํค์ง๋ ์ธ๋ถ ํด๋์ค์์๋ Setter๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง, ์๋ธํด๋์ค์์๋ Setter๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์ ํํ ์ ์๋ค.
์ฆ, Setter์ ์ ๊ทผ ๋ฒ์๋ฅผ protected๋ก ์ค์ ํ์ฌ, ์ธ๋ถ์์๋ ๊ฐ์ ๋ณ๊ฒฝํ์ง ๋ชปํ์ง๋ง, ์์๋ฐ์ ํด๋์ค์์๋ ๋ณ๊ฒฝํ ์ ์๋๋ก ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
lazy loading ์์ ์์๋ฐ๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ฏ๋ก protected๋ก ์ ์ธ๋ setter๋ ๋ฌธ์ ์์ด ์์๋ฐ์ ์ ์์ ๊ฒ์ด๋ค.
@Entity
open class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0L,
protected set // ์ธ๋ถ์์ ์ง์ Setter ํธ์ถ์ ๋ง๊ณ , ์๋ธํด๋์ค์์๋ ํ์ฉ
@Column(nullable = false)
var name: String,
protected set
)
์์ ๊ฐ์ด protected set์ ์ ์ํด ์ฃผ๋ฉด ์๋ฐ๋ก ๋์ปดํ์ผ ํ์ ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
public Long getId() { // Getter๋ public
return this.id;
}
protected void setId(Long id) { // Setter๋ protected
this.id = id;
}
public String getName() { // Getter๋ public
return this.name;
}
protected void setName(String name) { // Setter๋ protected
this.name = name;
}
}
์์ ๊ฐ์ด setter์ ๋ํด์๋ protected์ ์ ๊ทผ์๊ฐ ๋ถ์ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด ์๋ธ ํด๋์ค์์๋ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ์ง๋ง ์ธ๋ถ์์๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ ์ํ๋ก ๋ง๋ค์ด ์ต๋ํ์ ์บก์ํ๋ฅผ ์งํฌ ์ ์๋ ์ฝ๋๋ผ๊ณ ๋ณผ ์ ์๋ค.
๋ฐ๋ผ์ var+protected set ๋ฐฉ๋ฒ์ด ๊ฐ์ฅ ์ต์ ์ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ ์ ์์ ๊ฒ ๊ฐ๋ค.
๐จ๋ฌธ์ ์
๋ชจ๋ ๋ฐฉ์์๋ trade-off๊ฐ ์๋ฏ์ด var+protected set์ ๋ฐฉ์์๋ ๋ฌธ์ ์ ์ด ์๋ค.
1. ์ฝํ๋ฆฐ์ ๋ถํ์ํ ์ฝ๋๋ฅผ ์ค์ด๊ณ ์ ์ค๊ณ๋ ์ธ์ด์ธ๋ฐ, ์บก์ํ๋ฅผ ์งํค๊ธฐ ์ํด ์ปฌ๋ผ๋ค์ protect set์ ์ ์ํ๋ฉด ์ฝ๋๊ฐ ๋๋ฌด ์ฅํฉํด์ง๋ค.
2. ํ๋กํผํฐ๋ฅผ ์์ฑ์ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ์ด๊ธฐํํ๋ ค ํ ๋ ๋ถํธํจ์ด ์๊ธด๋ค.
@Entity
@Table(name = "`user`")
class User(
name: String,
) {
@Column(nullable = false)
var name: String = name
protected set
}
์์ ์ฝ๋์ฒ๋ผ ์์ฑ์ ๋งค๊ฐ๋ณ์์ ์ ์๋ฅผ ํ๊ณ ์๋์์ ๋ ์ ์๋ฅผ ํด์ค์ผ ํ๋ค๋ ์ ์ด๋ค.
(์์ฑ์ ๋งค๊ฐ๋ณ์์์๋ protected set ์ค์ ์ด ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ)
๐ข ๋ง๋ฌด๋ฆฌ
- ์ฝํ๋ฆฐ์ ์๋ฐ์ ๋ฌ๋ฆฌ ํ๋์ ๊ฐ๋ ์ด ์๋ ํ๋กํผํฐ์ ๊ฐ๋ ์ด๋ค.
- var์ ์๋ฐ๋ก ๋์ปดํ์ผ ๋๋ ๊ณผ์ ์์ field + getter + setter ๊ฐ ์์ฑ๋๋ค.
- val์ ์๋ฐ๋ก ๋์ปดํ์ผ ๋๋ ๊ณผ์ ์์ final field + getter ๊ฐ ์์ฑ๋๋ค.
- ์ฝํ๋ฆฐ์ ๋์ปดํ์ผ ๊ณผ์ ์์ class์ method์ final์ด ๋ถ๋๋ค ํ์ง๋ง JPA์ allopen ํ๋ฌ๊ทธ์ธ์ ๋ฐ๋ผ open์ผ๋ก ๋ฐ๋๋ค. => Hibernate์ lazy loading์ด ๊ฐ๋ฅ์ผ ํ๋๋ก
- ํ๋กํผํฐ๊ฐ ์ธ๋ถ๋ก ๋ ธ์ถ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ญ๊ฐ ์์๊น?
- private ์ ๊ทผ ์ ์ด์ ์ค์ -> ๋ชจ์ ๋ฐ์
- val๋ก ๋ณ์ ์ง์ -> ๊ถ์ฅ์ฌํญ x
- var + private set -> ์ปดํ์ผ ์๋ฌ
- var + protected set -> ๊ทธ๋๋ง ์ต์ ์ ๋ฐฉ๋ฒ
๐ก๊ฐ๊ฐ์ ๋ฐฉ๋ฒ๋ค์๋ ๋ชจ๋ trade-off๊ฐ ๋ฐ๋ฅธ๋ค. ์ฌ์ค ๊ฐ๋ฐ์๋ค์ ์ค์๋ก ์ธํด ๊ฐ์ฒด์ ๊ฐ์ด ์๋์น ์๊ฒ ๋ณ๊ฒฝ๋๋ ๊ฒ๋ง ์๋๋ฉด ๋ฌธ์ ๊ฐ ์๋ ๋ถ๋ถ์ด๋ค. ๊ทธ๋ ๊ธฐ์ ์๋ฌต์ ์ผ๋ก ๊ฐ๋ฐ์๋ค ์ฌ์ด์์ ์ด๋ฌํ ๊ณผ์ ๋ง ์ ์ง์ผ์ง๋ค๋ฉด var๋ง ์จ์ ์ฝ๋๋ฅผ ๊ฐ๊ฒฐํ๊ฒ ์ ์งํ๋ ๊ฒ๋ ์ข์ ๋ณด์ธ๋ค.
๐ ์ถ์ฒ
Introduction to Jakarta Persistence :: Jakarta EE Tutorial :: Jakarta EE Documentation
The persistence provider can be configured to automatically create the database tables, load data into the tables, and remove the tables during application deployment using standard properties in the application’s deployment descriptor. These tasks are t
jakarta.ee
https://docs.jboss.org/hibernate/orm/6.5/userguide/html_single/Hibernate_User_Guide.html#entity-pojo
Hibernate ORM User Guide
Starting in 6.0, Hibernate allows to configure the default semantics of List without @OrderColumn via the hibernate.mapping.default_list_semantics setting. To switch to the more natural LIST semantics with an implicit order-column, set the setting to LIST.
docs.jboss.org
https://docs.jboss.org/hibernate/orm/6.5/userguide/html_single/Hibernate_User_Guide.html#access
Hibernate ORM User Guide
Starting in 6.0, Hibernate allows to configure the default semantics of List without @OrderColumn via the hibernate.mapping.default_list_semantics setting. To switch to the more natural LIST semantics with an implicit order-column, set the setting to LIST.
docs.jboss.org