๋ชฉ์ฐจ
JPA ๋ฑ์ฅ๋ฐฐ๊ฒฝ
JDBC์์ MyBatis๋ก ๋์ด์ค๋ฉด์ ์ผ์ ๋ถ๋ถ ํธ๋ฆฌํด์ก์ง๋ง ์์ง๋ ๋ถํธํจ์ ์กด์ฌํ๋ค
1. ๊ฐ์ฒด๋ง๋ค ๋ฐ๋ณต๋๋ CRUD, ๋งตํ์ฝ๋ ์์ฑ
@Mapper
@Repository
public interface MemberRepository {
@Insert("insert into member(name, age) values(#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertAnno(Member member);
@Select("select * from member where id=#{id}")
Member selectAnno(Long id);
}
๊ฐ์ฒด๋ง๋ค insert, select, update, delete.... ์ง๋ฃจํ๊ฒ ๋ฐ๋ณต๋๋ CRUD์ฝ๋๋ค์ ์์ฑํด์ฃผ์ด์ผํ๋ค
DB์ ์ ์ฅํ ๋๋ ๊ฐ์ฒด์์ SQL๋ฌธ์ผ๋ก ๋ณํํด์ฃผ๊ณ , DB์ ๊ฐ์ ๋ฐ์์ฌ๋๋ SQL๋ฌธ์์ ๊ฐ์ฒด๋ก ๋ณํํด์ฃผ๊ณ ,,
๊ทธ๋๋ง MyBatis์์๋ ๊ฐํธํด์ง๊ธดํ์ง๋ง ๊ฐ์ฒด๋ง๋ค ๋น์ทํ SQL๋ฌธ์ "์ง์ " ๋ฐ๋ณตํด์ ์์ฑํด์ฃผ๊ณ ๋งตํํด์ผํ๋ค.
2. ์ํฐํฐ ์ ๋ขฐ ๋ฌธ์
public void process(String id){
Member member = memberRepository.find(id);
member.getTeam(); //Team์ ๊ฐ์ ธ์ฌ ์ ์์๊น?
member.getOrder().getDelivery(); //Delivery๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์๊น?
}
member.getTeam();
> ์ด๊ฒ์ด ๊ฐ๋ฅํ๋ ค๋ฉด find๋ฉ์๋๊ฐ member์ team์ joinํด์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ณด์ฅํด์ผํ๋ค.
member.getOrder().getDelivery();
> ์ด๊ฒ์ด ๊ฐ๋ฅํ๋ ค๋ฉด find๋ฉ์๋๊ฐ member, order, delivery๋ฅผ ๋ชจ๋ joinํด์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ณด์ฅํด์ผํ๋ค.
> select๋ฌธ์ join์ ๋ฐ๋ผ ํ์๋ฒ์๊ฐ ๊ฒฐ์ ๋์ด๋ฒ๋ฆฐ๋ค.
3. ๊ฐ์ฒด์ RDB์ ํจ๋ฌ๋ค์ ๋ถ์ผ์น
public class Member{
private Long id;
private Long teamId;
private String username;
}
private class Team{
private Long id;
private String name;
}
create table member(
member_id bigint primary key,
team_id bigint,
username varchar,
foreign key (team_id) references team(id)
);
create table team(
team_id bigint primary key,
name varchar
);
๊ฐ์ฒด๋ฅผ SQL๋ก ๋ณํ ์ ํธ๋ฆฌํจ์ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ฒด์ ๊ทธ๋๋ก ๋ฐ์ํ๋ค.
๊ฐ์ฒด์ ์ฐ๊ด๊ด๊ณ๊ฐ ์๋๊ฐ? NO
ํ ์ด๋ธ์ ์ฐ๊ด๊ด๊ณ๊ฐ ์๋๊ฐ? YES
๊ฐ์ฒด๋ฅผ ํ ์ด๋ธ์ ๋ง์ถ์ด ๋ชจ๋ธ๋งํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด ๊ฐ์ ์ฐ๊ด๊ด๊ณ๋ ์์์๊ฐ ์๋ค!
๊ฐ์ฒด์งํฅ ๊ด์ ์์ teamId๋์ Team์ ๋ฃ์ผ๋ฉด ์ด๋จ๊น? SQL์์ Team์ joinํด์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ๋ณด์ฅ๋์ด์ผํ๋ค.
joinํด์ ๊ฐ์ ธ์๋๋ฐ Team๋ด์ฉ์ด ์ฌ์ฉ๋์ง ์๋๋ค๋ฉด?? Member๋ง ๊ฐ์ ธ์ค๋ ์ฟผ๋ฆฌ๋ฌธ์ ์จ์ Team์ null๋ก ๋์ผํ๋??? ๐ค๐ค
์ด๋ฐ ๊ณ ๋ฏผ์์ ๋์จ ๊ฒ์ด ORM ๊ธฐ์ ์ด๋ค
[ORM] Object-Relational Mapping : ๊ฐ์ฒด-๊ด๊ณ ๋งตํ
๊ฐ์ฒด๋ ๊ฐ์ฒด๋๋ก ์ค๊ณํ๊ณ , DB๋ DB๋๋ก ์ค๊ณํ์
๋๋ค ์ค๊ฐ์ ๋ด๊ฐ(=ORM) SQL๋ฌธ ์์์ ์์ฑํ๊ณ ๊ฐ์ฒด๋ก ๋งตํํด์ค๊ฒ!!!
๋ฐ์ดํฐ ์ฝ์
์ > Entity ๋ถ์ > Insert SQL ์์ฑ > JDBC API ์ฌ์ฉ > ํจ๋ฌ๋ค์ ๋ถ์ผ์น ํด๊ฒฐ |
๋ฐ์ดํฐ ์กฐํ ์ > Select SQL ์์ฑ > JDBC API ์ฌ์ฉ > ResultSet ๋งคํ > ํจ๋ฌ๋ค์ ๋ถ์ผ์น ํด๊ฒฐ |
[JPA] Java Persistence API : ์๋ฐ์ ORM ๊ธฐ์ ํ์ค
์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ↔ [JPA] ↔ JDBC API ↔ DB
JPA๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ JDBC ์ฌ์ด์์ ๋์ํ๋ค.
Member ํ ์ด๋ธ์ ์ปฌ๋ผ์ด ์ถ๊ฐ๋๋ฉด??
- ๊ธฐ์กด : ๋ชจ๋ SQL๋ฌธ์ ์ฐพ์์ ํ๋๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผํ๋ค.
- JPA : JPA๊ฐ SQL๋ฌธ์ ์์์ ์์ฑํด์ฃผ๊ธฐ๋๋ฌธ์, Member ํด๋์ค์ ํ๋๋ง ์ถ๊ฐํด์ฃผ๋ฉด๋๋ค.
=> ์ ์ง๋ณด์์ฑ ์ฆ๊ฐ
๊ฐ์ Member๋ฅผ ๊ฐ์ง๊ณ ์จ๋ค๋ฉด??
Long memberId = 100L;
Member member1 = repository.find(Member.class, memberId);
Member member2 = repository.find(Member.class, memberId);
- ๊ธฐ์กด : member1 != member2
- JPA : member1 == member2
=> ๋์ผํ ํธ๋์ญ์ ์์ ์กฐํํ ์ํฐํฐ๋ ๊ฐ์์ ๋ณด์ฅํด์ค๋ค.
JPA์ ์ฑ๋ฅ ์ต์ ํ
1์ฐจ ์บ์์ ๋์ผ์ฑ(identity) ๋ณด์ฅ | ์ ์์์ฒ๋ผ ๊ฐ์ 100๋ฒ์ Member๋ฅผ ์กฐํํ ๋, 1๋ฒ์งธ find๋ DB์์ ๊ฐ์ ๊ฐ์ ธ์ค๊ณ , 2๋ฒ์งธ find๋ ์บ์์์ ๊ฐ์ ๊ฐ์ ธ์จ๋ค. => ์กฐํ ์ฑ๋ฅ ํฅ์ |
ํธ๋์ญ์
์ ์ง์ํ๋ ์ฐ๊ธฐ ์ง์ฐ (transactional write-behind) |
ํธ๋์ญ์
์ ์ปค๋ฐํ ๋๊น์ง๋ insert SQL๋ฌธ๋ค์ ๋ชจ์๋๋๋ค JDBC BATCH SQL ๊ธฐ๋ฅ์ ์ฌ์ฉํด์ ํ๋ฒ์ SQL๋ฌธ์ ์ ์กํ๋ค |
์ง์ฐ ๋ก๋ฉ(Lazy Loading) | ์๋ ์ฐธ๊ณ |
//์ง์ฐ๋ก๋ฉ : ๊ฐ์ฒด๊ฐ ์ค์ ์ฌ์ฉ๋ ๋ ๋ก๋ฉ
Member member = repository.find(memberId); // select * from member;
Team team = member.getTeam();
String teamname = team.getName(); // select * from team;
//์ฆ์๋ก๋ฉ : JOIN์ ์ฌ์ฉํ์ฌ ์ฐ๊ด๋ ๊ฐ์ฒด๊น์ง ๋ฏธ๋ฆฌ ์กฐํ
Member member = repository.find(memberId); // select member.*, team.* from member join team..
Team team = member.getTeam();
String teamname = team.getName();
JPA ํ๊ฒฝ์ค์
maven ์ฌ์ฉ ์
pom.xml์ ๋ํ๋์ ์ถ๊ฐ
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.6.4.Final</version>
</dependency>
resources/META-INF/persistence.xml ์์ฑ
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
<persistence-unit name="persistenceConfig">
<properties>
<!-- datasource ์์ฑ -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!-- ์ต์
-->
<!-- SQL๋ฌธ ๋ก๊ทธ ์ถ๋ ฅ -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<!-- JPA ํ์ค์ ๋ง์ถ ์๋ก์ด ํค ์์ฑ ์ ๋ต ์ฌ์ฉ -->
<property name="hibernate.id.new_generator_mappings" value="true"/>
<!-- ์ ํ๋ฆฌ์ผ์ด์
์คํ ์์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ ์๋ ์์ฑ -->
<!-- <property name="hibernate.hbm2ddl.auto" value="create"/> -->
</properties>
</persistence-unit>
</persistence>
gradle ์ฌ์ฉ ์
build.gradle์ ๋ํ๋์ ์ถ๊ฐ
implementation 'org.hibernate:hibernate-entitymanager:5.6.4.Final'
resources/application.properties์ ๋ด์ฉ ์์ฑ
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=va
spring.datasource.password=
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=create
* hibernate.hbm2ddl.auto : DDL์ ์ ํ๋ฆฌ์ผ์ด์ ์คํ ์์ ์ ์๋์ผ๋ก ์์ฑํด์ค๋ค.
- create : ๊ธฐ์กด ํ ์ด๋ธ ์ญ์ ํ ๋ค์ ์์ฑ
- create-drop : create์ ๊ฐ์ผ๋ ์ข ๋ฃ์์ ์ ํ ์ด๋ธ drop
- update : ๋ณ๊ฒฝ๋ถ๋ง ๋ฐ์ํ๋ค
- validate : ์ํฐํฐ์ ํ ์ด๋ธ์ด ์ ์ ๋งคํ๋์๋์ง๋ง ํ์ธํ๋ค
- none : ์ฌ์ฉํ์ง ์๋๋ค.
์ค์ ์๋ฒ์์๋ ๋ฐ๋์ validate, none๋ง ์ฌ์ฉํ๋๋ก ํ๋ค.
EntityManager
JPA์ persistenceํด๋์ค๋ persistence.xml ๋๋ application.properties ์ค์ ์ ๋ณด๋ฅผ ์กฐํํ ๋ค์,
EntityManagerFactory๋ฅผ ์์ฑํ๋ค.
EntityManagerFactory๋ EntityManager๋ฅผ ๋ง๋ค์ด์ฃผ๋ ๊ฐ์ฒด์ด๋ค.
EntityManager๋ ํธ๋์ญ์ ์ ์ฒ๋ฆฌํ ๋ ํญ์ ์๋ก ์์ฑํ๋ ๊ฐ์ฒด์ด๋ค
์ฃผ์!
EntityManagerFactory๋ DB์ ์ฐ๊ฒฐํ๊ธฐ๋๋ฌธ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์ ํ๋๋ง ์์ฑํด์ ๊ณต์ ํด์ผํ๋ค.
EntityManager๋ ์ฐ๋ ๋๊ฐ์ ๊ณต์ ํ์ง ์๊ณ ์ฌ์ฉ ํ ๋ฒ๋ ค์ผํ๋ค.
jpa์ ๋ชจ๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ ํธ๋์ญ์ ์์์ ์คํ๋์ด์ผํ๋ค.
public static void main(String args[]){
//EntityFactory ์์ฑ
//์ค์ ์ ๋ณด persistence-unit ํ๊ทธ์ name๋ช
์
๋ ฅ
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("persistenceConfig")
//EntityManager ์์ฑ
EntityManager em = emf.createEntityManager();
//EntityTransaction ์์ฑ
EntityTransaction tx = em.getTransaction();
//ํธ๋์ญ์
์์
tx.begin();
try{
Member member = new Member(1, "hello");
em.persist(member);
} catch(Exception e){
tx.rollback();
}
em.close();
emf.close();
}
JPA์ CRUD ๋ฉ์๋
๊ฐ๋ฐ์ ์์ฑ | JPA ์ฒ๋ฆฌ | |
์ ์ฅ | member.setTeam(team); jpa.persistent(member); |
insert into team ... insert into member ... |
์กฐํ | Member member = jpa.find(Member.class, memberId); member.getTeam(); //๊ฐ๋ฅ |
select member.*, team.* from member join team ... |
์์ | member.setName("๋ณ๊ฒฝํ ์ด๋ฆ"); | |
์ญ์ | jpa.remove(member); |
ํ๋์ ์ปฌ๋ผ ๋งคํ
@Entity //jpa๊ฐ ๊ด๋ฆฌํ ๊ฐ์ฒด
public class Member{
@Id //DB์ PK์ ๋งคํํ ํ๋
@GeneratedValue(strategy = GenerationType.AUTO) //์๋ ์ฆ๊ฐํ๋ ํ๋์ ๊ฐ์ ์ฑ์์ค๋ค.
private Long id;
@Column(name = "USERNAME") //DB์ ์ปฌ๋ผ๋ช
๊ณผ ๊ฐ์ฒด์ ํ๋๋ช
์ด ๋ค๋ฅผ๋ ๋งคํํด์ค ์ ์๋ค.
private String name;
private int age;
@Temporal(TemporalType.TIMESTAMP) //์๊ฐ ํ์
์ ๋งคํํ๋ค
private Date regDate;
@Enumerated(EnumType.STRING) //Enumํ์
์ ๋งคํํ๋ค
private MemberType memberType;
@Lob //CLOB, BLOB์ ๋งคํํ๋ค
private String blob;
}
์ด๋ ธํ ์ด์ ์ javax.persistence์ ์๋ ๊ฒ์ ์ฌ์ฉํ์
@GeneratedValue
- GenerationType.IDENTITY : MySQL์ผ๋ ์ฌ์ฉํ๋ค.
- GenerationType.SEQUENCE: ORACLE์ผ๋ ์ฌ์ฉํ๋ค.
- GenerationType.TABLE : ๋ชจ๋ DB์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค. ํค ์์ฑ์ฉ ํ ์ด๋ธ์ผ๋ ์ฌ์ฉํ๋ค.
- GenerationType.AUTO: ๋ฐฉ์ธ์ ๋ฐ๋ผ ์๋ ์ง์ ํ๋ค (๊ธฐ๋ณธ๊ฐ)
@Enumerated ์ ๊ธฐ๋ณธ๊ฐ์ EnumType.ORDINAL์ด๋ค.
์ด๊ฒ์ Enum์ index๊ฐ์ผ๋ก ๋งคํํ๊ธฐ๋๋ฌธ์ ์ค๊ฐ์ enum์ด ์ถ๊ฐ๋๋ฉด ์ซ์๊ฐ ๋ค ๊ผฌ์ฌ๋ฒ๋ฆฐ๋ค.
๋ฐ๋์ String์ผ๋ก ์ค์ ํด์ enum์ ๊ธ์๋ฅผ ๋ฃ์ด์ฃผ์.
์ฐ๊ด๊ด๊ณ ๋งคํ
๋จ๋ฐฉํฅ ๋งคํ A → B
@Entity
public class Member{
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
@Column(name = "USERNAME")
private String username;
}
@Entity
private class Team{
@Id @GeneratedValue
private Long id;
@Column(name = "NAME")
private String name;
}
Member์ Team์ ๊ด๊ณ๊ฐ N : 1 ์ด๋ฏ๋ก Member์ team์ @ManyToOne์ ์์ฑํ๋ค.
Team ํ ์ด๋ธ์ TEAM_ID ์ปฌ๋ผ๊ณผ ์ฐ๊ฒฐ๋ ๊ฒ์ด๋ @JoinColumn์ TEAM_ID๋ฅผ ์์ฑํ๋ค.
์ค์ ๋ก Member๋ฅผ ์กฐํํ๋ฉด JPA๊ฐ DB์ "select ~ from member left outer join team ~" SQL๋ฌธ์ฅ์ ์ ์กํ๋ค.
@ManyToOne(fetch = FetchType.LAZY) ๋ก ์ค์ ํ๋ฉด
Member ์กฐํ ์ JPA๊ฐ Member์ ๋ํ ๋ด์ฉ๋ง selectํด์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค.
์ดํ Team๊ฐ์ฒด๋ฅผ ์กฐํํ๋ฉด ๊ทธ ์๊ฐ์ JPA๊ฐ Team์ ๋ํด์๋ง select๋ฌธ์ ์ ์กํ๋ค.
//์ง์ฐ๋ก๋ฉ : ๊ฐ์ฒด๊ฐ ์ค์ ์ฌ์ฉ๋ ๋ ๋ก๋ฉ
Member member = repository.find(memberId); // select * from member;
Team team = member.getTeam();
String teamname = team.getName(); // select * from team;
์๋ฐฉํฅ ๋งคํ A ↔ B
@Entity
public class Member{
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
@Column(name = "USERNAME")
private String username;
}
@Entity
private class Team{
@Id @GeneratedValue
private Long id;
@Column(name = "NAME")
private String name;
@OneToMany(mappedBy = "team") //โ
โ
โ
โ
โ
private List<Member> members = new ArrayList<Member>();
}
ํ ์ด๋ธ์ ์ฐ๊ฒฐ๊ด๊ณ์ ๋ฐฉํฅ์ฑ์ด ์๊ธฐ๋๋ฌธ์ ๊ทธ ์์ฒด๋ก ์๋ฐฉํฅ ๊ด๊ณ๊ฐ ์ฑ๋ฆฝ๋๋ค. Member ↔ Team
๊ฐ์ฒด์ ์๋ฐฉํฅ ๊ด๊ณ๋ Member → Team 1๊ฐ, Member ← Team 1๊ฐ = ๋จ๋ฐฉํฅ ์ฐ๊ฐ๊ด๊ณ 2๊ฐ๊ฐ ์ฐ๊ฒฐ๋ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด Member์ team ๊ฐ์ ์์ ํ ํ์ Team์ members๋ฅผ ์์ ํ๋ฉด..?
๋๋ค ์ ๋ฐ์ดํธ๊ฐ ๋์ด์ผํ๋๋ฐ ๊ทธ๋ผ ๋ฐ์ดํฐ์ ์ ๋ขฐ์ฑ์ด ๋จ์ด์ง๊ฒ๋๋ค
๊ทธ๋์ ๋ ์ค ํ๋๋ก ์ธ๋ํค๋ฅผ ๊ด๋ฆฌํ์! ํ๊ณ ๊ท์น์ด ์๊ธฐ๊ฒ ๋๋ค
์๋ฐฉํฅ ๋งคํ ๊ท์น
- ๊ฐ์ฒด์ ๋ ๊ด๊ณ ์ค ํ๋๋ฅผ ์ฐ๊ฐ๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ์ง์
- ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ๋ง์ด ์ธ๋ํค๋ฅผ ๊ด๋ฆฌ(๋ฑ๋ก, ์์ )
- ์ฃผ์ธ์ด ์๋ ์ชฝ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅ
- ๊ฐ์ฒด ๋ ๋ค ์์ ํ๋ฉด ์ฃผ์ธ์ชฝ ๋ฐ์ดํฐ๋ง ์์ ๋จ.
- ์ฃผ์ธ์ @JoinColumn์ ์์ฑํ๊ณ , ์ฃผ์ธ์ด ์๋ ์ชฝ์ mappedBy ์์ฑ์ ์์ฑํ๋ค.
๋๊ตฌ๋ฅผ ์ฃผ์ธ์ผ๋ก?
- ์ธ๋ํค๊ฐ ์๋ ๊ณณ์ ์ฃผ์ธ์ผ๋ก!
(๊ธฐ์กด ์ฝ๋์์๋ Member์์ Long teamId ๊ฐ ์กด์ฌํ์๋ค.)
์ฃผ์!!!
JPA์ ๋ด๋ถ๊ตฌ์กฐ
์์์ฑ ์ปจํ ์คํธ : ์ํฐํฐ๋ฅผ ์๊ตฌ ์ ์ฅํ๋ ํ๊ฒฝ
์์์ฑ ์ปจํ ์คํธ๋ EntityManager๋ฅผ ํตํด ์ ๊ทผํ ์ ์๋ค.
์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ฉด
- 1์ฐจ ์บ์๋ฅผ ์ฌ์ฉํ ์ ์๊ณ
- ๋์ผ์ฑ์ ๋ณด์ฅ๋ฐ๊ณ
- ํธ๋์ญ์ ์ ์ง์ํ๋ ์ฐ๊ธฐ ์ง์ฐ์ด ๊ฐ๋ฅํ๊ณ
- ๋ณ๊ฒฝ์ ๊ฐ์งํ ์ ์๊ณ (Dirty Checking)
- ์ง์ฐ์ ๋ก๋ฉํ ์ ์๋ค(Lazy Loading)
์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ
- ๋น์์(new/transient)
: ์์์ฑ ์ปจํ ์คํธ์ ์ ํ ๊ด๊ณ๊ฐ ์๋ ์ํ
: Member member = new Member();
- ์์(managed)
: ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋์ด ์์์ฑ ์ปจํ ์คํธ๊ฐ ๊ด๋ฆฌํ๋ ์ํ
: em.persist(member);
- ์ค์์(detached)
: ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋์๋ค๊ฐ ๋ถ๋ฆฌ๋ ์ํ
: em.detach(member);
- ์ญ์ (removed)
: ์ญ์ ๋ ์ํ
: em.remove(member); ๊ฐ์ฒด๋ฅผ DB์์ ์ญ์ ํ ์ํ
JPA ๋์๋ฐฉ์
์กฐํ
Member member = new Member();
member.setId("member1");
member.setUsername("ํ์1");
em.persist(member);
//์์์ฑ ์ปจํ
์คํธ์ 1์ฐจ ์บ์์ key๋ member1๋ก, value๋ Entity์์ฒด๊ฐ ์ ์ฅ๋๋ค
//(key๋ @Id๊ฐ ๋ถ์ ๊ฐ์ด ๋๋ค)
Member findM1 = em.find(Member.class, "member1")
//1์ฐจ ์บ์์์ ์กฐํ
Member findM2 = em.find(Member.class, "member2");
//1์ฐจ ์บ์์ ์์ผ๋ฉด DB์์ ์กฐํ
//DB์กฐํ ๊ฒฐ๊ณผ๊ฐ์ 1์ฐจ ์บ์์ ์ ์ฅํ ํ, findM2์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํด์ค๋ค
์์ฑ
Member member1 = new Member("Lisa");
Member member2 = new Member("Happy");
em.persist(member1);
em.persist(member2);
// member1, member2 1์ฐจ ์บ์์ ์ ์ฅ
// ํด๋น insert๋ฌธ 2๊ฐ๋ฅผ ์ฐ๊ธฐ์ง์ฐSQL์ ์ฅ์์ ์ ์ฅํด๋๋ค
tx.commit();
// insert๋ฌธ 2๊ฐ๋ฅผ DB์ ์ ์กํ๋ค (flush)
// DB์ commit์ ์คํํ๋ค
์์
Member insertMember = new Member();
insertMember.setUsername("stark");
member.setAge(20);
em.persist(insertMember);
// ์์์ฑ ์ปจํ
์คํธ์ 1์ฐจ ์บ์์ ์ ์ฅ๋๋ค.
// ์ด๋, insertMember์ ์ค๋
์ท์ ์ฐ์ด์ ๋ณด๊ดํ๋ค.
Member member = em.find(Member.class, "stark");
// insertMember == member
member.setUsername("tony");
member.setAge(10);
tx.commit();
// ์์์ฑ ์ปจํ
์คํธ์ insertMember์ ์ค๋
์ท๊ณผ ๋ณ๊ฒฝ๋ member๋ฅผ ๋น๊ตํด์
// ์๋์ผ๋ก update๋ฌธ์ DB์ ์ ์กํ๋ค.
์ ์ด๋ ๊ฒ ๋์ํ ๊น? ์๋ฐ์ List๋ฅผ ์๊ฐํด๋ณด์.
List<Member> ์์ Member๋ฅผ ํ๋ ๊บผ๋ธ ํ ๊ฐ์ ์์ ํ๊ณ ๋ค์ List์ ๋ด๋๊ฐ?? NO
=> ๊ฐ์ฒด์งํฅ์ฒ๋ผ ๋์ํ๊ฒ ํ๊ธฐ์ํด์ em.update() ์ด๋ฐ ๋ฉ์๋๊ฐ ์๋ ๊ฒ์ด๋ค!
์ญ์
Member member = em.find(Member.class, "memberA");
em.remove(member);
tx.commit();
//์ปค๋ฐ ์์ ์ delete๋ฌธ DB์ ์ ๋ฌ๋๋ค
์์์ฑ ์ปจํ ์คํธ๋ฅผ ํ๋ฌ์ ํ๋ ๋ฐฉ๋ฒ
flush : SQL๋ฌธ์ DB์ ์ ์กํด์ ์ค์ ๋ก ์ ์ฉํ๋ ๊ฒ = ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐํํ๋ ๊ฒ์ด ๋ชฉ์ ์ด๋ค.
- em.flush() : ์ง์ ํธ์ถ
- transaction.commit() : flush ์๋ํธ์ถ
- JPQL ์ฟผ๋ฆฌ ์คํ : flush ์๋ํธ์ถ
์ง์ฐ๋ก๋ฉ LAZY๋ฅผ ์ฌ์ฉํด์ ํ๋ก์๋ก ์กฐํ
์ฃผ์!! ์ง์ฐ๋ก๋ฉํ๋ ค๋ฉด ์์์ฑ ์ปจํ ์คํธ๊ฐ ํ์ฑํ๋์ด์์ด์ผํ๋ค!!
Member member = em.find(Member.class, 1L);
//์ด๋ Member์ Team์๋ ํ๋ก์๊ฐ์ฒด(๊ฐ์ง๊ฐ์ฒด)๊ฐ ์ฑ์์ ธ์๋ค.
Team team = member.getTeam();
//์์ง Team์ ํ๋ก์๊ฐ์ฒด
team.getName();
//์ค์ team์ ์ฌ์ฉํ๋ ์์ ์ DB์กฐํํ์ฌ Team์ด ์ฑ์์ง๋ค
JPA์ ๊ฐ์ฒด์งํฅ ์ฟผ๋ฆฌ
JPQL : SQL์ ์ถ์ํํ์ฌ ๊ฐ์ฒด๋ฅผ ๋์์ผ๋กํ๋ ๊ฐ์ฒด์งํฅ ์ฟผ๋ฆฌ ์ธ์ด
SQL๊ณผ ๋ฌธ๋ฒ ์ ์ฌํ๋ค.
JPQL์ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๊ณ , SQL์ ํ ์ด๋ธ์ ๋์์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
from ๋ค์๋ ํ ์ด๋ธ ์ด๋ฆ์ด ์๋ ์ํฐํฐ ์ด๋ฆ์ ์ฌ์ฉํ๋ค
๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ๋ค
๋ณ์นญ์ด ํ์์ด๋ค(m)
String jpql = "select m from Member m where m.name like '%hello%'";
// String jpql = "select m from Member m where m.age > 18";
List<Member> result = em.createQuery(jpql, Member.class).getResultList();
// getResultList() : ๊ฒฐ๊ณผ๊ฐ ๋ฆฌ์คํธ๋ก ๋ฐํ๋๋ค.
Member result = em.createQuery(jpql, Member.class).getSingleResult();
// getSingleResult() : ๊ฒฐ๊ณผ๊ฐ ์ ํํ ํ๋ ๋ฐํ๋๋ค. (ํ๋๊ฐ ์๋๋ฉด ์์ธ๊ฐ ๋ฐ์๋๋ค)
String jpql = "select m from Member m where m.username =: username";
query.setParameter("username", usernameParam);
// ์ฟผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ๊ฐ ์
๋ ฅ๋๋ค
String jpql = "select m.username from Member m";
String username = em.createQuery(jpql, String.class);
// member์ ํ๋์ ํด๋น๋๋ ๊ฐ๋ง ๊ฐ์ ธ์ฌ ์ ์๋ค.
String jpql = "select new com.example.dto.UserDTO(m.username, m.age) from Member m";
UserDTO user = em.createQuery(jpql, UserDTO.class);
// ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ฒ๋ผ new ์ฐ์ฐ์๋ฅผ ํตํด DTO๋ก ๋ฐ๋ก ์กฐํํ ์ ์๋ค.
String paging = "select m from Member m order by m.name desc";
List<Member> result = em.createQuery(jpql, Member.class)
.setFirstResult(int startPosition) //์กฐํ ์์ ์์น(0๋ถํฐ)
.setMaxResults(int maxResult) //์กฐํํ ๋ฐ์ดํฐ ์ (N๊ฐ ๊ฐ์ ธ์)
.getResultList();
// ํ์ด์ง ์ฒ๋ฆฌ ๊ฐ๋ฅ
String innerJoin = "select m from Member m join m.team t";
String outerJoin = "select m from Member m left [outer] join m.team t";
// join
String fetchJoin = "select m from Member m join fetch m.team";
// fetch join : ์ํฐํฐ ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ํ๋ฒ์ ์กฐํํ ์ ์๋ค.
// ๋ณ์นญ ์ฌ์ฉ ๋ถ๊ฐ
// ๋ชจ๋ Lazy ๋ก๋ฉ์ผ๋ ์ด๋๋งํผ์ ๋ฌด์กฐ๊ฑด joinํด์ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผํ๋ค! ํ ๋ ์ฌ์ฉํ๋ค.
// SQL๋ฌธ์ผ๋ก๋ select m.*, t.* from Member m inner join team t on m.team_id = t.id
์ฐธ๊ณ
'๐พ Database' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA]์์์ฑ ๊ด๋ฆฌ : ๋ด๋ถ ๋์ ๋ฐฉ์ (0) | 2022.02.21 |
---|---|
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ (0) | 2022.02.20 |
[MyBatis] ๋์์๋ฆฌ, ์ฌ์ฉ๋ฐฉ๋ฒ ์ ๋ฆฌ (0) | 2022.01.27 |
[JDBC] ์ฌ์ฉ๋ฐฉ๋ฒ (0) | 2022.01.26 |
[MyBatis] String์ ๋๊ฒผ์๋ Out of range value for column ์ค๋ฅ ํด๊ฒฐ..? (0) | 2022.01.25 |