ปกติเวลาเราเขียน service ของ spring ขึ้นมา เราจะใช้ AOP (Aspect Oriented Programming) ช่วยในการ manage transaction ให้ เพียงแค่ใส่ annotation @Transactional (org.springframework.transaction.annotation.Transactional) ไว้บน class หรือ method ที่ต้องการ เมื่อ spring ทำ reflection มาเจอ มันก็จะเช็คว่า method ไหนต้องการให้มี transaction บ้าง มันก็จะ begin / commit transaction ให้ โดยผ่านทาง proxy method แล้ว proxy method ก็ค่อยไปเรียก method จริงๆ อีกที การทำแบบนี้ถือว่าสะดวกมาก เพราะเราไม่ต้อง manage transaction เอง (spring จัดการให้แล้ว) ซึ่งก็ช่วยลด code ที่ซ้ำซ้อนและไม่สำคัญทาง business logic ออกไปได้ในระดับหนึ่งครับ
แต่การใช้ AOP มันมีเงื่อนไขอยู่ว่า service instance นั้นจะต้องถูกสร้างขึ้นมาจาก spring เท่านั้น (เราจะ new instance เองไม่ได้) เพราะ spring จะต้องเอาไปครอบด้วย proxy method (ทำ AOP) อีกทีครับ
จากเงื่อนไขการใช้ AOP ข้อนี้ทำให้มีบางเหตุการณ์ที่เราไม่สามารถใช้ transaction จาก AOP ได้ เช่น การเรียกใช้งาน method นั้นๆ โดยตรง โดยไม่ผ่าน proxy method ประมาณนี้
MyService.java
... ... ... import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; @Service @Transactional(propagation = Propagation.REQUIRED) public class MyServiceImpl implements MyService{ @Override public void methodA(){ for(int i=0; i<10 ;i ++){ methodB(); } } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB(){ } }จาก code ข้างบน methodA() ทำการเรียกใช้งาน methodB() 10 ครั้ง
ทุกครั้งที่เรียกใช้งาน methodB() ต้องการให้ new transaction ใหม่เสมอ
คำถาม methodB() ถูก new transaction ขึ้นมาใหม่หรือไม่
คำตอบ ไม่ครับ เพราะ methodA() เรียกใช้งาน methodB() โดยตรง โดยไม่ผ่าน proxy method (แต่ถ้าผ่าน proxy method methodB() จะถูก new transaction ขึ้นมาใหม่เสมอ เนื่องจากมี annotation @Transactional(propagation = Propagation.REQUIRES_NEW) กำกับอยู่)
คำถาม อ้าว ถ้าเรียกตรงๆ แล้ว new transaction ไม่ได้ แล้วเราจะทำยังไงล่ะ?
คำตอบ เราก็ต้อง manage transaction เองยังไงล่ะครับ ดังนี้
MyService.java
... ... ... import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; @Service @Transactional(propagation = Propagation.REQUIRED) public class MyServiceImpl implements MyService{ @Autowired private PlatformTransactionManager transactionManager; @Override public void methodA(){ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); for(int i=0; i<10 ;i ++){ transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { try { methodB(); //**** } catch (Exception ex) { status.setRollbackOnly(); } } }); } } @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB(){ } }แค่นี้ เราก็สามารถ new transaction ให้ methodB() ใหม่ทุกครั้ง โดยเรียกใช้งานตรงๆ จาก methodA() ได้แล้วครับ
ซึ่งการ new transaction จะเกิดขึ้นเมื่อมีการเรียก transactionTemplate.execute() และเซต transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
reference : http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch11s06.html
ไม่มีความคิดเห็น:
แสดงความคิดเห็น