7์ฃผ์ฐจ ์๋ฃ์ ๋ชจ๋ ํ ํฝ์ ๋ ๊ฐ์ ํฐ ํ๋ฆ์ผ๋ก ์ ๋ฆฌํ ํ์ต ๊ฒฝ๋ก.
1) ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง๊ณผ ORM โ SQL JOIN โ ORM ํจ๋ฌ๋ค์ โ JPA ์ ๋ฌธ โ ์ํฐํฐ ๋งคํ
2) ํธ๋์ญ์ ์ถ์ํ์ ์งํ โ ์๋ ๊ด๋ฆฌ โ PlatformTransactionManager โ @Transactional6์ฃผ์ฐจ์์ JDBC์ JdbcTemplate์ผ๋ก DB ์ ๊ทผ์ ์ตํ๋ค๋ฉด, 7์ฃผ์ฐจ๋ ํ ๋จ๊ณ ๋ ๋์ ์ถ์ํ๋ก ์ฌ๋ผ๊ฐ๋ค.
์ฌ์ ๋ฉ๋ชจ: ์๋ฃ ์ฒซ ๋ถ๋ถ์ "์คํ๋ง ๋น์ด๋?"์ 5์ฃผ์ฐจ Phase 8(ApplicationContext + DI)์ ๋ณต์ต ํฌ์ธํธ์ด๋ฏ๋ก ๋ณธ ์ปค๋ฆฌํ๋ผ์์๋ Phase๋ก ๋ถ๋ฆฌํ์ง ์๊ณ ํ์ต ์ด์ ํ์์ ์งง๊ฒ ๋ค๋ฃฌ๋ค.
[Part A โ ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง๊ณผ ORM]
[Phase 1] SQL JOIN โ ๊ด๊ณํ DB์ ๋ณธ์ง
โ
[Phase 2] ORM ํจ๋ฌ๋ค์ โ ๊ฐ์ฒด์ ๊ด๊ณ์ ๋ง๋จ
โ
[Phase 3] JPA ์
๋ฌธ
โ
[Phase 4] JPA ์ํฐํฐ ๋งคํ
[Part B โ ํธ๋์ญ์
์ถ์ํ์ ์งํ]
[Phase 5] ์๋ ํธ๋์ญ์
์ ํ๊ณ
โ
[Phase 6] PlatformTransactionManager (์ธํฐํ์ด์ค ์ถ์ํ)
โ
[Phase 7] @Transactional (์ ์ธ์ ํธ๋์ญ์
)
์ด 7 Phase ร 24 Unit
| ์ฃผ์ฐจ | ์ฃผ์ | ํต์ฌ ๋ณํ |
|---|---|---|
| 1์ฃผ์ฐจ | OOPยทJVMยทGCยท์ปฌ๋ ์ ยทI/O ๊ฐ๋ก | ์๋ฐ ํฐ ๊ทธ๋ฆผ |
| 2์ฃผ์ฐจ | JVM ๋ด๋ถยท๋ฐ์ดํธ์ฝ๋ยทG1 GC | "์ด๋ป๊ฒ ๋์๊ฐ๋" |
| 3์ฃผ์ฐจ | ์ปฌ๋ ์ ยท์ ๋ค๋ฆญยทํจ์ํ | ์๋ฐ ํํ๋ ฅ |
| 4์ฃผ์ฐจ | ๋ฉํฐ์ค๋ ๋ฉยท๋์์ฑยทExecutor | ๋์์ฑ ์ ๋ณต |
| 5์ฃผ์ฐจ | Atomic + Spring IoC/DI ์ ๋ฌธ | ์๋ฐ โ Spring ๋ค๋ฆฌ |
| 6์ฃผ์ฐจ | ํ ์คํธ + ์น ์ธํ๋ผ + DB ์ ๊ทผ ์งํ | Spring ์ค์ ํ๊ฒฝ |
| 7์ฃผ์ฐจ (์ง๊ธ) | ORM/JPA + ํธ๋์ญ์ ์ถ์ํ | DB ์ถ์ํ์ ์ ์ |
| Day | Phase | ํ์ต ๋ชฉํ |
|---|---|---|
| 1์ผ์ฐจ | Phase 1 | SQL JOIN 4์ข ๋ง์คํฐ |
| 2์ผ์ฐจ | Phase 2 + 3 | ORM ํจ๋ฌ๋ค์ + JPA ์ ๋ฌธ |
| 3์ผ์ฐจ | Phase 4 | JPA ์ํฐํฐ ๋งคํ ์ด๋ ธํ ์ด์ |
| 4์ผ์ฐจ | Phase 5 + 6 | ์๋ ํธ๋์ญ์ โ PlatformTransactionManager |
| 5์ผ์ฐจ | Phase 7 | @Transactional ๋์ ์๋ฆฌ |
| 6์ผ์ฐจ | ์ข ํฉ ์๊ธฐ ์ ๊ฒ + ์ค์ต | ์ ์ฒด ์ ๋ฆฌ |
์๋ฃ ๋ถ๋์ด 5ยท6์ฃผ์ฐจ๋ณด๋ค ๊ฐ๋ฒผ์. 6์ผ ์ผ์ ์ผ๋ก ์ถฉ๋ถํ๋, JPA ์ค์ต์ ๋ ํ๋ ค๋ฉด +3์ผ.
๋ชฉํ: 4๊ฐ์ง JOIN์ ๊ฒฐ๊ณผ๋ฅผ ๋จธ๋ฆฟ์์์ ๊ทธ๋ฆด ์ ์๊ฒ ๋๋ค. JPA๋ฅผ ์ดํดํ๊ธฐ ์ํ ํ์ ๊ธฐ์ด.
์ ์ ์ง์: 6์ฃผ์ฐจ Phase 4 (DB ์ธ์ )
ํต์ฌ ๊ฐ๋
์ JOIN์ด ํ์ํ๊ฐ:
employees (์ง์) departments (๋ถ์)
โโโโฌโโโโโโโโฌโโโโโโโโโโโโ โโโโโโฌโโโโโโโโโโโโโโโ
โidโ name โdept_id โ โ id โ dept_name โ
โโโโผโโโโโโโโผโโโโโโโโโโโโค โโโโโโผโโโโโโโโโโโโโโโค
โ 1โAlice โ 101 โ โ101 โ HR โ
โ 2โBob โ 102 โ โ102 โ Engineering โ
โ 3โCharlieโ NULL โ โ103 โ Sales โ
โโโโดโโโโโโโโดโโโโโโโโโโโโ โโโโโโดโโโโโโโโโโโโโโโ
โ "Alice๊ฐ ์ด๋ ๋ถ์?" ๋ตํ๋ ค๋ฉด ๋ ํ ์ด๋ธ์ ํฉ์ณ์ผ ํจ โ JOIN
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 1.1
ํต์ฌ ๊ฐ๋
"๋ ํ ์ด๋ธ์์ ๊ณตํต๋ ๊ฐ ์ด ์๋ ํ๋ง ๋ฐํ"
SELECT e.id, e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
๊ฒฐ๊ณผ:
id โ name โ department_name
โโโโผโโโโโโโโผโโโโโโโโโโโโโโโโโ
1 โ Alice โ HR
2 โ Bob โ Engineering
Charlie(๋ถ์ NULL) ์ Sales(์ง์ ์์) ๋ ์ ์ธ๋จ.
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 1.2
ํต์ฌ ๊ฐ๋
LEFT JOIN: ์ผ์ชฝ ํ ์ด๋ธ์ ๋ชจ๋ ํ ๋ฐํ, ์ค๋ฅธ์ชฝ ๋งค์นญ ์์ผ๋ฉด NULL
SELECT e.id, e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;
id โ name โ department_name
โโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
1 โ Alice โ HR
2 โ Bob โ Engineering
3 โ Charlie โ NULL โ ๋ถ์ ์๋ ์ง์๋ ํฌํจ
RIGHT JOIN: ์ผ์ชฝ/์ค๋ฅธ์ชฝ์ด ๋ฐ๋
SELECT e.id, e.name, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.id;
id โ name โ department_name
โโโโโโผโโโโโโโโผโโโโโโโโโโโโโโโโโ
1 โ Alice โ HR
2 โ Bob โ Engineering
NULL โ NULL โ Sales โ ์ง์ ์๋ ๋ถ์๋ ํฌํจ
์๊ธฐ ์ ๊ฒ
A LEFT JOIN B ์ B RIGHT JOIN A ๋ ๊ฐ์๊ฐ?์ ์ ์ง์: Unit 1.3
ํต์ฌ ๊ฐ๋
"์์ชฝ ํ ์ด๋ธ์ ๋ชจ๋ ํ ๋ฐํ, ๋งค์นญ ์์ผ๋ฉด NULL"
SELECT e.id, e.name, d.department_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.id;
id โ name โ department_name
โโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
1 โ Alice โ HR
2 โ Bob โ Engineering
3 โ Charlie โ NULL โ ๋ถ์ ์๋ ์ง์
NULL โ NULL โ Sales โ ์ง์ ์๋ ๋ถ์
MySQL์ FULL OUTER JOIN์ ์ง์ํ์ง ์์ โ LEFT JOIN UNION RIGHT JOIN ์ผ๋ก ์ฐํ.
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 1.4
์ ํ ๋งคํธ๋ฆญ์ค:
| ์๋๋ฆฌ์ค | JOIN ์ข ๋ฅ |
|---|---|
| ์์ชฝ์ ๋ชจ๋ ์๋ ๋ฐ์ดํฐ๋ง ํ์ | INNER JOIN |
| ์ผ์ชฝ ํ ์ด๋ธ์ ๋ชจ๋ ๋ฐ์ดํฐ + ๋งค์นญ๋๋ ์ค๋ฅธ์ชฝ | LEFT JOIN |
| ๋ ํ ์ด๋ธ ๋ชจ๋์ ๋ชจ๋ ๋ฐ์ดํฐ | FULL OUTER JOIN |
| "๋ถ์ ์๋ ์ง์๋ง" ๊ฐ์ ์ฐจ์งํฉ | LEFT JOIN + WHERE NULL |
์ค๋ฌด ํ:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ORM์ด ์ ํ์ํ์ง๋ฅผ, ๊ฐ์ฒด์ ๊ด๊ณ ๋ชจ๋ธ์ ๋ณธ์ง์ ๋ฏธ์ค๋งค์น๋ก ์ดํดํ๋ค.
์ ์ ์ง์: 1์ฃผ์ฐจ Phase 1 (OOP), Phase 1 (JOIN)
ํต์ฌ ๊ฐ๋
๊ฐ์ฒด์ ๊ด๊ณํ DB๋ ๋ค๋ฅธ ํจ๋ฌ๋ค์:
| ์ธก๋ฉด | ๊ฐ์ฒด (OOP) | ๊ด๊ณํ DB |
|---|---|---|
| ๋ชจ๋ธ๋ง | ์ํ + ํ๋ | ํ๊ณผ ์ด |
| ์์ | ์์ | ์์ |
| ์ฐ๊ด ๊ด๊ณ | ์ฐธ์กฐ (order.member) | ์ธ๋ ํค (FK) |
| ์๋ณ | ๊ฐ์ฒด ์๋ณ์ (==) | PK |
| ๋ฐ์ดํฐ ํ์ | ํ๋ถ (List, Map, ...) | ์ ํ์ |
โ ์ด ์ฐจ์ด๋ฅผ ๋ฉ์ฐ๋ ์ฝ๋๋ฅผ ๋งค๋ฒ ์์ผ๋ก ์ฐ๋ ๊ฒ ORM ๋ฑ์ฅ ์ ์ ๊ณ ํต
์๊ธฐ ์ ๊ฒ
Order ๊ฐ์ฒด๊ฐ List<OrderItem> ์ ๊ฐ๋ ๊ตฌ์กฐ๋ฅผ RDB๋ก ์ด๋ป๊ฒ ํํํ๋๊ฐ?์ ์ ์ง์: Unit 2.1
ํต์ฌ ๊ฐ๋
ORM (Object-Relational Mapping):
ํจ๊ณผ:
๋์ค์ ORM:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: JPA๊ฐ ์๋ฐ ์ง์์ ORM ํ์ค์์ ์ดํดํ๊ณ , JdbcTemplate/MyBatis์์ ๊ฒฐ์ ์ ์ฐจ์ด๋ฅผ ์ก๋๋ค.
์ ์ ์ง์: 6์ฃผ์ฐจ Phase 7 (JdbcTemplate)
ํต์ฌ ํ๊ณ
JdbcTemplate, MyBatis ๊ฐ์ SQL Mapper ๋:
์์ (JdbcTemplate):
String sql = "SELECT * FROM item WHERE id = ?";
Item item = jdbcTemplate.queryForObject(sql, itemRowMapper, id);
// โ SQL๊ณผ RowMapper๋ฅผ ์ง์ ์์ฑ
โ "SQL ์์ฒด๋ฅผ ์ ์ฐ๋ ๋ฐฉ๋ฒ์ ์์๊น?"
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 3.1
ํต์ฌ ๊ฐ๋
JPA (Java Persistence API):
SQL Mapper vs JPA:
| SQL Mapper (JdbcTemplate, MyBatis) | JPA | |
|---|---|---|
| SQL ์์ฑ | ๊ฐ๋ฐ์ | JPA๊ฐ ์๋ ์์ฑ |
| ๋งคํ | RowMapper๋ก ์๋ | ์ด๋ ธํ ์ด์ ์ผ๋ก ์ ์ธ |
| ๊ฐ์ฒด ๊ทธ๋ํ | ์๋ ์ฒ๋ฆฌ | ์๋ (Lazy Loading) |
| ํ์ต ๊ณก์ | ๋ฎ์ | ๋์ |
| ๋ณต์ก ์ฟผ๋ฆฌ | ์์ | ์ด๋ ค์ (๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ ํ์) |
์๊ธฐ ์ ๊ฒ
show-sql, format-sql)์ ์ ์ง์: Unit 3.2
ํต์ฌ ๊ทธ๋ฆผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Code โ
โ (Item, Member, Order ๊ฐ์ฒด...) โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ JPA API
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ JPA โ โ ๊ฐ์ฒด โ SQL ๋ณํ
โ (Hibernate ๊ตฌํ์ฒด) โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ JDBC API
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ JDBC โ โ Connection, PreparedStatement
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ DB Driver
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DB โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ํต์ฌ ์์น:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 3.3
ํต์ฌ ๊ฐ๋
JPA๋ฅผ ๋ ํธ๋ฆฌํ๊ฒ ์ฐ๊ธฐ ์ํ ๋๊ตฌ๋ค:
Spring Data JPA:
Repository ์ธํฐํ์ด์ค๋ง ๋ง๋ค๋ฉด ์๋ ๊ตฌํfindByName(name) ๊ฐ์ ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ์ฟผ๋ฆฌ ์๋ ์์ฑpublic interface ItemRepository extends JpaRepository<Item, Long> {
List<Item> findByItemNameContaining(String keyword);
// โ ๊ตฌํ์ฒด๋ Spring์ด ์๋ ์์ฑ
}
Querydsl:
queryFactory
.selectFrom(item)
.where(item.price.gt(1000)
.and(item.itemName.contains(keyword)))
.fetch();
์ค๋ฌด ์กฐํฉ: Spring Data JPA + Querydsl (๊ฐ์ฅ ์ผ๋ฐ์ )
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ์๋ฐ ๊ฐ์ฒด๋ฅผ DB ํ ์ด๋ธ๊ณผ ๋งคํํ๋ ์ด๋ ธํ ์ด์ 4์ข ์ ์์ ์ตํ๋ค.
์ ์ ์ง์: Phase 3
ํต์ฌ ๊ฐ๋
@Entity
public class Item {
// ...
}
@Entity: ์ด ํด๋์ค๊ฐ JPA๊ฐ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด์์ ํ์@Entity ๊ฐ ๋ถ์ ๊ฐ์ฒด = ์ํฐํฐ(Entity)์ํฐํฐ์ ์กฐ๊ฑด:
@Entity ์ด๋
ธํ
์ด์
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 4.1
ํต์ฌ ๊ฐ๋
@Entity
public class Item {
@Id
private Long id;
// ...
}
@Id: ํ
์ด๋ธ์ PK ์ปฌ๋ผ๊ณผ ๋งคํ@Id ๊ฐ ๋ฐ๋์ 1๊ฐ (ํน์ ๋ณตํฉ ํค)์๊ธฐ ์ ๊ฒ
@Id ์์ด ์ํฐํฐ๋ฅผ ๋ง๋ค๋ฉด?@IdClass, @EmbeddedId)์ ์ ์ง์: Unit 4.2
ํต์ฌ ๊ฐ๋
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
4๊ฐ์ง ์์ฑ ์ ๋ต:
| ์ ๋ต | ๋์ | ์ ํฉ DB |
|---|---|---|
| IDENTITY | DB์ auto_increment ์ฌ์ฉ | MySQL, PostgreSQL |
| SEQUENCE | DB ์ํ์ค ๊ฐ์ฒด ์ฌ์ฉ | Oracle, PostgreSQL |
| TABLE | ํค ์์ฑ์ฉ ํ ์ด๋ธ ์ฌ์ฉ | ๋ชจ๋ DB (์ฑ๋ฅ โ) |
| AUTO | DB์ ๋ฐ๋ผ ์๋ ์ ํ | (๊ธฐ๋ณธ๊ฐ) |
MySQL์์ IDENTITY ์๋ฏธ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 4.3
ํต์ฌ ๊ฐ๋
@Column(name = "item_name", length = 10)
private String itemName;
์ฃผ์ ์ต์ :
name: DB ์ปฌ๋ผ๋ช
(์ง์ ์ ํ๋ฉด ํ๋๋ช
๊ทธ๋๋ก)length: ๋ฌธ์์ด ์ต๋ ๊ธธ์ด (DDL ์์ฑ ์ ํ์ฉ)nullable: NULL ํ์ฉ ์ฌ๋ถunique: UNIQUE ์ ์ฝcolumnDefinition: ์ปฌ๋ผ DDL ์ง์ ์์ฑ์์:
@Column(name = "user_email", length = 100, nullable = false, unique = true)
private String email;
์๊ธฐ ์ ๊ฒ
@Column ์ต์
์ด DB ์คํค๋ง์ ์ด๋ป๊ฒ ๋ฐ์๋๋๊ฐ? (ํํธ: ddl-auto ์ค์ )length๋ง ์ง์ ํ๋ฉด ๋ค๋ฅธ ์ต์
์ ์ด๋ป๊ฒ ๋๋๊ฐ? (ํํธ: ๊ธฐ๋ณธ๊ฐ)์ ์ ์ง์: Unit 4.4
ํต์ฌ ๊ฐ๋
Spring Boot์ JPA ํตํฉ:
itemName (camelCase)item_name (snake_case)์ฆ:
@Column(name = "item_name") // ๋ช
์์
private String itemName;
// ๋๋
private String itemName; // ์๋์ผ๋ก item_name์ผ๋ก ๋งคํ
โ Spring Boot ํ๊ฒฝ์์ @Column(name = "item_name") ์ ์๋ต ๊ฐ๋ฅ.
์๊ธฐ ์ ๊ฒ
๋ชฉํ: "์ @Transactional ์ด ํ์ํ๊ฐ" ๋ผ๋ ์ง๋ฌธ์ ์ง์ ์ฝ๋๋ก ๋ตํ ์ ์๊ฒ ๋๋ค.
์ ์ ์ง์: 6์ฃผ์ฐจ Phase 6 (ํธ๋์ญ์ ACID)
ํต์ฌ ์๋๋ฆฌ์ค
๊ณ์ข ์ด์ฒด:
์์์ฑ ๋ณด์ฅ ์กฐ๊ฑด:
public void transfer(Connection conn, ...) { // โ Connection์ด ๋งค๊ฐ๋ณ์
accountDao.withdraw(conn, fromId, amount);
accountDao.deposit(conn, toId, amount);
}
โ ๋น์ฆ๋์ค ๋ก์ง์ด Connection์ ์ ๊ฒฝ ์จ์ผ ํจ = ์ถ์ํ ๊นจ์ง
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 5.1
ํต์ฌ ์ฝ๋
public void performTransaction() throws SQLException {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false); // ํธ๋์ญ์
์์
// ๋น์ฆ๋์ค ๋ก์ง 1
PreparedStatement ps1 = conn.prepareStatement("INSERT ...");
ps1.executeUpdate();
// ๋น์ฆ๋์ค ๋ก์ง 2
PreparedStatement ps2 = conn.prepareStatement("UPDATE ...");
ps2.executeUpdate();
conn.commit(); // ๋ชจ๋ ์ฑ๊ณตํ๋ฉด ์ปค๋ฐ
} catch (Exception e) {
if (conn != null) conn.rollback(); // ์คํจ ์ ๋กค๋ฐฑ
throw e;
} finally {
if (conn != null) conn.close(); // ์์ ํด์
}
}
3๊ฐ์ง ํจ์ :
1. ํธ๋์ญ์
๋์: setAutoCommit, commit, rollback ์ฝ๋ ๋งค๋ฒ ๋ฐ๋ณต
2. ์์ธ ๋์: SQLException์ด ๋น์ฆ๋์ค ๋ก์ง๊น์ง ์ ํ
3. JDBC ๋ฐ๋ณต: Connection ์์ฑยทclose ์ฝ๋ ๋ฐ๋ณต
โ 6์ฃผ์ฐจ์ JdbcTemplate์ ๋ถ๋ถ์ ํด๊ฒฐ, ํธ๋์ญ์ ์ ๊ทธ๋๋ก ๋จ์
์๊ธฐ ์ ๊ฒ
๋ชฉํ: Spring์ด ํธ๋์ญ์ ์ ์ด๋ป๊ฒ ์ถ์ํํ๋์ง๋ฅผ ๋ณธ๋ค. 5์ฃผ์ฐจ์ DataSource์ ๊ฐ์ ์ฌ์.
์ ์ ์ง์: Phase 5
ํต์ฌ ๊ฐ๋
"์คํ๋ง ํธ๋์ญ์ ์ฒ๋ฆฌ์ ์ค์ฌ ์ธํฐํ์ด์ค"
ํต์ฌ ๋ฉ์๋:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition def);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
์ญํ :
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 6.1
ํต์ฌ ๊ตฌํ์ฒด
| ๊ตฌํ์ฒด | ์ฌ์ฉ์ฒ |
|---|---|
| DataSourceTransactionManager | JDBC, JdbcTemplate, MyBatis |
| HibernateTransactionManager | Hibernate (์ง์ ์ฌ์ฉ) |
| JpaTransactionManager | JPA |
์ํฉ๋ณ ์ ํ:
Spring Boot์ ์๋ ๊ตฌ์ฑ:
spring-boot-starter-data-jpa โ JpaTransactionManager ์๋ ์ค์ ์๊ธฐ ์ ๊ฒ
@Transactional("name"))์ ์ ์ง์: Unit 6.2
Before (์๋ ๊ด๋ฆฌ):
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false);
try {
userDao.insertUser(conn, "John");
accountDao.updateBalance(conn, 1, -100);
conn.commit();
} catch (Exception e) {
conn.rollback();
throw e;
} finally {
conn.close();
}
After (PlatformTransactionManager):
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition()
);
try {
userDao.insertUser("John"); // Connection ์ ๋ณด์
accountDao.updateBalance(1, -100); // Connection ์ ๋ณด์
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
์ป์ ๊ฒ:
์์ง ๋จ์ ๊ฒ:
์๊ธฐ ์ ๊ฒ
๋ชฉํ: ํธ๋์ญ์ ์ฝ๋์ ๋ณด์ผ๋ฌํ๋ ์ดํธ๋ฅผ ์ด๋ ธํ ์ด์ ํ ์ค๋ก ์ค์ด๋ ๋ง์ง๋ง ๋จ๊ณ. AOP์ ์ฒซ ๋ง๋จ.
์ ์ ์ง์: Phase 6, 5์ฃผ์ฐจ ๋์์ธ ํจํด
ํต์ฌ ๊ฐ๋
ํ๋ก์ ํจํด:
"์๋ณธ ๊ฐ์ฒด์ ๋๋ฆฌ์(Proxy)๋ฅผ ๋ง๋ค์ด์, ์๋ณธ ํธ์ถ ์ ํ์ ์ถ๊ฐ ์์ ์ ๋ผ์ ๋ฃ๋ ํจํด"
[ํด๋ผ์ด์ธํธ] โโ> [Proxy] โโโ
โ ํธ๋์ญ์
์์
โ
[์๋ณธ ๊ฐ์ฒด.๋ฉ์๋()]
โ
โ ์ปค๋ฐ/๋กค๋ฐฑ
โ
โ
Spring์ ํ์ฉ:
@Transactional ์ด ๋ถ์ ๋ฉ์๋๊ฐ ์๋ ๋น์์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 7.1
ํต์ฌ ๊ฐ๋
์ ์ธ์ ํธ๋์ญ์ :
@Service
public class TransferService {
@Transactional
public void transfer(Long fromId, Long toId, int amount) {
accountDao.withdraw(fromId, amount);
accountDao.deposit(toId, amount);
}
}
ํ ์ค ์ด๋ ธํ ์ด์ ์ผ๋ก ๋ค์์ด ์๋:
ํ๋ก์๊ฐ ํ๋ ์ผ (์์ฌ์ฝ๋):
public void transfer(Long fromId, Long toId, int amount) {
TransactionStatus status = txManager.getTransaction(...);
try {
targetService.transfer(fromId, toId, amount); // ์ค์ ๋ฉ์๋
txManager.commit(status);
} catch (Exception e) {
txManager.rollback(status);
throw e;
}
}
ํต์ฌ ํต์ฐฐ:
์๊ธฐ ์ ๊ฒ
์ ์ ์ง์: Unit 7.2
ํต์ฌ ํจ์ 5๊ฐ์ง:
@Service
public class MyService {
@Transactional
private void internal() { } // โ ํ๋ก์๊ฐ ๋ชป ๊ฐ๋ก์ฑ
}
@Service
public class MyService {
public void outer() {
this.inner(); // โ ํ๋ก์ ๊ฑฐ์น์ง ์์ โ ํธ๋์ญ์
์ ๊ฑธ๋ฆผ
}
@Transactional
public void inner() { ... }
}
@Transactional
public void method() throws Exception { // ์ฒดํฌ ์์ธ
throw new IOException(); // โ ๋กค๋ฐฑ ์ ๋จ!
}
// ํด๊ฒฐ
@Transactional(rollbackFor = Exception.class)
REQUIRED (๊ธฐ๋ณธ): ๊ธฐ์กด ํธ๋์ญ์
์์ผ๋ฉด ์ฐธ์ฌ, ์์ผ๋ฉด ์๋ก ์์REQUIRES_NEW: ํญ์ ์ ํธ๋์ญ์
NESTED: ์ค์ฒฉ ํธ๋์ญ์
(Savepoint)@Transactional(readOnly = true)
public List<Item> findAll() { ... }
์๊ธฐ ์ ๊ฒ
@Transactional(readOnly = true) ์ ํจ๊ณผ๋?์ด๋ฒ ์๋ฃ ๋์ ๋ถ์ "์คํ๋ง ๋น์ด๋?"์ 5์ฃผ์ฐจ Phase 8(ApplicationContext + DI)์ ๋ณต์ต ํฌ์ธํธ์ ๋๋ค. ๋ค์ 3๊ฐ์ง๋ฅผ ๋ค์ ์ง๊ณ ๊ฐ์๋ฉด ์ถฉ๋ถํด์:
๋ฐ๋์ ๊น์ด ํ๊ธฐ:
[ ] Phase 1 โ SQL JOIN (Unit 1.1~1.5)
[ ] Phase 2 โ ORM ํจ๋ฌ๋ค์ (Unit 2.1~2.2)
[ ] Phase 3 โ JPA ์
๋ฌธ (Unit 3.1~3.4)
[ ] Phase 4 โ JPA ์ํฐํฐ ๋งคํ (Unit 4.1~4.5)
[ ] Phase 5 โ ์๋ ํธ๋์ญ์
์ ํ๊ณ (Unit 5.1~5.2)
[ ] Phase 6 โ PlatformTransactionManager (Unit 6.1~6.3)
[ ] Phase 7 โ @Transactional (Unit 7.1~7.3)
[ ] ์ข
ํฉ ์๊ธฐ ์ ๊ฒ 24๋ฌธํญ ํต๊ณผ
6์ฃผ์ฐจ์์ ๋ณธ ์ถ์ํ์ ์ฌ์์ด ์ด๋ฒ ์ฃผ์ ๋ ๋ฒ ๋ ๋ฐ๋ณต๋ฉ๋๋ค:
| 6์ฃผ์ฐจ | 7์ฃผ์ฐจ |
|---|---|
| DataSource (์ปค๋ฅ์ ์ถ์ํ) | PlatformTransactionManager (ํธ๋์ญ์ ์ถ์ํ) |
| JdbcTemplate (๋ฐ๋ณต ์ ๊ฑฐ) | @Transactional (๋ณด์ผ๋ฌํ๋ ์ดํธ ์ ๊ฑฐ) |
| SQL ๋งคํ RowMapper | JPA ์ด๋ ธํ ์ด์ ๋งคํ |
โ "Spring์ ๋์์์ด ์ถ์ํํ๋ค" โ 6, 7์ฃผ์ฐจ์ ์ผ๊ด๋ ๋ฉ์์ง.