OSIV (Open Session in View)
กลไกของ Hibernate ที่เปิด Session ตั้งแต่ request เข้ามา (ก่อนถึง Controller) แล้วปิดตอน response ออกไป เป็นค่า default ของ Spring Boot: spring.jpa.open-in-view=true
Session vs Transaction
- Session = ห้องทำงาน — Hibernate ใช้ track entity, จัดการ lazy load
- Transaction = คำสั่งงานในห้อง — สำเร็จทั้งหมด (commit) หรือยกเลิกทั้งหมด (rollback)
- Session 1 ตัวมีได้หลาย Transaction
ปัญหา (Before Fix)
เมื่อใช้ RoutingDataSource สำหรับ read-write splitting โดยไม่มี LazyConnectionDataSourceProxy:
Request เข้า
→ OSIV เปิด Session → ยืม connection จริงทันที
→ RoutingDataSource เช็ค: readOnly = false (ยังไม่มี @Transactional)
→ เลือก MASTER ❌
→ เข้า Service → @Transactional(readOnly=true) เริ่ม (สายไปแล้ว!)
→ Query ใช้ Master connection เดิม
ผลลัพธ์: Replica ไม่เคยถูกใช้จริงเลย แม้ log จะแสดง “Routing to: REPLICA” — เพราะ log พิมพ์ตอน Aspect ทำงาน (หลัง @Transactional) แต่ connection ถูกยืมไปก่อนแล้วตอน OSIV เปิด Session
วิธีแก้ (After Fix)
แก้ 2 อย่างใน DataSource configuration:
1. afterPropertiesSet()
ต้องเรียกเองเพราะ routingDataSource ไม่ได้เป็น Bean ตรง ๆ อีกแล้ว (ถูก wrap ก่อน return) IoC Container จึงไม่เรียกให้อัตโนมัติ
2. LazyConnectionDataSourceProxy
ครอบ routingDataSource ไว้ ให้ OSIV ได้ connection ปลอมไปก่อน พอมี query จริง ๆ ที่ @Transactional กำหนด readOnly แล้ว จึงค่อยยืม connection จริง
routingDataSource.afterPropertiesSet(); // confirm map พร้อม
return new LazyConnectionDataSourceProxy(routingDataSource); // wrap ด้วย proxyลำดับเหตุการณ์หลังแก้
Request เข้า
→ OSIV เปิด Session → ได้ proxy ปลอม (ยังไม่ยืมจาก pool)
→ เข้า Service → @Transactional(readOnly=true) เริ่ม
→ Query จริง → proxy ยืม connection จริงตอนนี้
→ RoutingDataSource เช็ค: readOnly = true
→ เลือก REPLICA ✅
หมายเหตุ HikariCP
HikariCP สร้าง connection ไว้ล่วงหน้าตอน app start แล้วให้ยืม-คืน ปัญหาไม่ใช่เรื่องสร้าง connection แต่เป็นเรื่อง ยืมจาก pool ไหน (Master/Replica) และ ยืมตอนไหน (ก่อน/หลัง @Transactional)
Related
- Spring Boot — OSIV เปิดเป็น default
- IoC Container — เกี่ยวข้องกับ
afterPropertiesSet() - Spring — framework ตัวแม่