คุณควรวาง@Transactional
ในDAO
ชั้นเรียนและ / หรือวิธีการของพวกเขาหรือมันจะดีกว่าที่จะใส่คำอธิบายประกอบชั้นเรียนบริการที่กำลังเรียกใช้วัตถุ DAO? หรือเหมาะสมที่จะอธิบายคำว่า "เลเยอร์" ทั้งคู่?
คุณควรวาง@Transactional
ในDAO
ชั้นเรียนและ / หรือวิธีการของพวกเขาหรือมันจะดีกว่าที่จะใส่คำอธิบายประกอบชั้นเรียนบริการที่กำลังเรียกใช้วัตถุ DAO? หรือเหมาะสมที่จะอธิบายคำว่า "เลเยอร์" ทั้งคู่?
คำตอบ:
ฉันคิดว่าการทำธุรกรรมเป็นของเลเยอร์บริการ มันเป็นสิ่งที่รู้เกี่ยวกับหน่วยงานและการใช้เคส เป็นคำตอบที่ถูกต้องหากคุณมี DAO หลายตัวที่ถูกฉีดเข้าไปในบริการที่ต้องทำงานร่วมกันในการทำธุรกรรมครั้งเดียว
โดยทั่วไปฉันเห็นด้วยกับคนอื่น ๆ ที่ระบุว่าการทำธุรกรรมมักจะเริ่มในระดับการให้บริการ (ขึ้นอยู่กับความละเอียดที่คุณต้องการแน่นอน)
อย่างไรก็ตามในเวลาเดียวกันฉันก็เริ่มเพิ่ม@Transactional(propagation = Propagation.MANDATORY)
ไปที่เลเยอร์ DAO ของฉัน (และเลเยอร์อื่น ๆ ที่ไม่ได้รับอนุญาตให้เริ่มต้นการทำธุรกรรม แต่ต้องมีคนที่มีอยู่) เพราะมันง่ายกว่ามากในการตรวจสอบข้อผิดพลาดที่คุณลืมเริ่มต้นธุรกรรมในผู้โทร เช่นบริการ) หาก DAO ของคุณมีคำอธิบายประกอบด้วยการแพร่กระจายภาคบังคับคุณจะได้รับข้อยกเว้นระบุว่าไม่มีธุรกรรมที่ใช้งานอยู่เมื่อมีการเรียกใช้เมธอด
ฉันยังมีการทดสอบการรวมที่ฉันจะตรวจสอบถั่วทั้งหมด (bean post processor) สำหรับคำอธิบายประกอบนี้และล้มเหลวหากมีการเพิ่มความคิดเห็นที่@Transactional
มีการแพร่กระจายอื่น ๆ นอกเหนือจากการบังคับใช้ใน bean ที่ไม่ได้อยู่ในเลเยอร์บริการ ด้วยวิธีนี้ฉันแน่ใจว่าเราจะไม่เริ่มต้นการทำธุรกรรมในชั้นที่ผิด
@Transactional
คลาสการนำไปใช้งานของบริการและฉันควรใส่@Transactional(propagation = MANDATORY)
ในการใช้งานคลาส DAO (พื้นที่เก็บข้อมูล) หรือไม่
คำอธิบายประกอบการทำธุรกรรมควรวางไว้รอบการดำเนินงานทั้งหมดที่แยกออกไม่ได้
ตัวอย่างเช่นการโทรของคุณคือ "เปลี่ยนรหัสผ่าน" ที่ประกอบด้วยสองการดำเนินงาน
ดังนั้นในข้างต้นหากการตรวจสอบล้มเหลวควรเปลี่ยนรหัสผ่านด้วยหรือไม่ ถ้าเป็นเช่นนั้นการทำธุรกรรมควรจะประมาณ 1 และ 2 (ดังนั้นที่ชั้นบริการ) หากอีเมลล้มเหลว (น่าจะมีความล้มเหลวที่ปลอดภัยในเรื่องนี้ดังนั้นมันจะไม่ล้มเหลว) ดังนั้นมันควรย้อนกลับรหัสผ่านการเปลี่ยนแปลงและการตรวจสอบหรือไม่?
@Transactional
เหล่านี้เป็นชนิดของคำถามที่คุณจะต้องมีการถามว่าการตัดสินใจที่จะใส่
คำตอบที่ถูกต้องสำหรับสถาปัตยกรรมสปริงดั้งเดิมคือการวางความหมายของธุรกรรมไว้ในคลาสบริการเนื่องจากเหตุผลที่คนอื่น ๆ ได้อธิบายไว้แล้ว
แนวโน้มที่เกิดขึ้นใหม่ในฤดูใบไม้ผลิคือไปสู่การออกแบบที่ขับเคลื่อนด้วยโดเมน (DDD) Spring Rooเป็นตัวอย่างของแนวโน้มที่ดี แนวคิดคือการทำให้โดเมนวัตถุ POJOs สมบูรณ์ยิ่งขึ้นกว่าในสถาปัตยกรรม Spring ทั่วไป (โดยปกติจะเป็นโลหิตจาง ) และโดยเฉพาะอย่างยิ่งการทำธุรกรรมและความหมายการคงอยู่บนวัตถุโดเมนเอง ในกรณีที่จำเป็นทั้งหมดคือการดำเนินการ CRUD อย่างง่ายผู้ควบคุมเว็บดำเนินการโดยตรงบน POJOs วัตถุโดเมน (พวกเขาทำงานเป็นหน่วยงานในบริบทนี้) และไม่มีระดับบริการ ในกรณีที่จำเป็นต้องมีการประสานงานระหว่างวัตถุโดเมนคุณสามารถมี Service bean ที่จัดการได้ด้วย@Transaction
ตามประเพณี คุณสามารถตั้งค่าการเผยแพร่ธุรกรรมบนวัตถุโดเมนเป็นสิ่งที่ต้องการREQUIRED
เพื่อให้วัตถุโดเมนใช้ธุรกรรมที่มีอยู่เช่นธุรกรรมที่เริ่มต้นที่ service bean
เทคนิคเทคนิคนี้ทำให้การใช้ AspectJ <context:spring-configured />
และ Roo ใช้คำจำกัดความประเภท AspectJ เพื่อแยกความหมายเอนทิตี (การทำธุรกรรมและการคงอยู่) จากวัตถุสิ่งของในโดเมน (โดยทั่วไปคือฟิลด์และวิธีการทางธุรกิจ)
กรณีปกติคือคำอธิบายประกอบในระดับเลเยอร์บริการ แต่ขึ้นอยู่กับความต้องการของคุณ
คำอธิบายประกอบในเลเยอร์บริการจะส่งผลให้การทำธุรกรรมนานกว่าคำอธิบายประกอบในระดับ DAO ขึ้นอยู่กับระดับการแยกธุรกรรมที่สามารถแยกแยะปัญหาได้เนื่องจากธุรกรรมที่เกิดขึ้นพร้อมกันจะไม่เห็นการเปลี่ยนแปลงของกันและกันเช่น อ่านซ้ำได้
การใส่คำอธิบายลงใน DAOs จะทำให้ธุรกรรมสั้นที่สุดเท่าที่จะเป็นไปได้ด้วยข้อเสียเปรียบว่าการทำงานของชั้นบริการของคุณจะไม่เปิดเผยในการทำธุรกรรมครั้งเดียว (ย้อนกลับได้)
ไม่ควรใส่คำอธิบายประกอบทั้งสองเลเยอร์หากตั้งค่าโหมดการเผยแพร่เป็นค่าเริ่มต้น
ฉันวาง@Transactional
บน@Service
เลเยอร์และตั้งrollbackFor
ข้อยกเว้นใด ๆ และreadOnly
เพื่อเพิ่มประสิทธิภาพการทำธุรกรรมเพิ่มเติม
โดยค่าเริ่มต้น@Transactional
จะมองหาRuntimeException
(ข้อยกเว้นที่ไม่ได้ตรวจสอบ) โดยการตั้งค่าการย้อนกลับเป็นException.class
(การตรวจสอบข้อยกเว้น) มันจะย้อนกลับสำหรับข้อยกเว้นใด ๆ
@Transactional(readOnly = false, rollbackFor = Exception.class)
หรือเหมาะสมที่จะอธิบายคำว่า "เลเยอร์" ทั้งคู่? - ไม่ควรใส่หมายเหตุประกอบทั้งเลเยอร์บริการและเลเยอร์ dao - หากต้องการตรวจสอบให้แน่ใจว่ามีการเรียกใช้เมธอด DAO เสมอ (แพร่กระจาย) จากชั้นบริการที่มีการเผยแพร่ "ข้อบังคับ" ใน DAO สิ่งนี้จะให้ข้อ จำกัด บางอย่างสำหรับวิธีการ DAO จากการถูกเรียกจากเลเยอร์ UI (หรือตัวควบคุม) นอกจากนี้ - เมื่อหน่วยทดสอบเลเยอร์ DAO โดยเฉพาะ - การมีคำอธิบายประกอบ DAO จะช่วยให้มั่นใจได้ว่าจะได้รับการทดสอบสำหรับการทำงานของทรานแซคชัน
propagation=Propagation.REQUIRES_NEW
การทำธุรกรรมที่ซ้อนกันสามารถเกิดขึ้นได้ถ้าคุณใช้ มิฉะนั้นสำหรับกรณีส่วนใหญ่รวมถึง propogation = ข้อบังคับ DAO จะเข้าร่วมในธุรกรรมที่มีอยู่ที่เริ่มต้นโดยชั้นบริการ
นอกจากนี้ Spring แนะนำให้ใช้คำอธิบายประกอบบนคลาสที่เป็นรูปธรรมเท่านั้นและไม่ใช่ส่วนต่อประสาน
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
สำหรับการทำธุรกรรมในระดับฐานข้อมูล
ส่วนใหญ่ฉันใช้@Transactional
ในระดับวิธีของ DAO เพียงอย่างเดียวดังนั้นการกำหนดค่าสามารถเป็นวิธีเฉพาะ / ใช้ค่าเริ่มต้น (จำเป็น)
วิธีการ DAO ที่รับการดึงข้อมูล (เลือก .. ) - ไม่จำเป็นต้องทำเช่น
@Transactional
นี้อาจทำให้เกิดค่าใช้จ่ายเนื่องจากการทำธุรกรรม interceptor / และ AOP proxy ที่ต้องดำเนินการด้วยเช่นกัน
วิธีการของ DAO ที่ทำการแทรก / อัพเดตจะได้รับ @Transactional
บล็อกที่ดีมากในการทำธุรกรรม
สำหรับระดับแอปพลิเคชัน -
ฉันใช้ธุรกรรมเพื่อตรรกะทางธุรกิจฉันต้องการให้สามารถย้อนกลับได้ในกรณีที่เกิดข้อผิดพลาดที่ไม่คาดคิด
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}
Transactional
inJava
โดยปกติหนึ่งควรใส่ธุรกรรมที่ชั้นบริการ
แต่ตามที่ระบุไว้ก่อนหน้านี้อะตอมมิกซิตี้ของการดำเนินการเป็นสิ่งที่บอกเราว่าจำเป็นต้องมีคำอธิบายประกอบอย่างไร ดังนั้นหากคุณใช้เฟรมเวิร์กเช่น Hibernate ซึ่งการดำเนินการ "บันทึก / อัพเดต / ลบ / ... /" เดียวในวัตถุนั้นมีโอกาสที่จะแก้ไขแถวหลายแถวในตารางต่างๆ (เนื่องจากการเรียงซ้อนผ่านกราฟวัตถุ) ของ แน่นอนควรมีการจัดการธุรกรรมในวิธี DAO เฉพาะนี้
@Transactional
ควรใส่คำอธิบายประกอบรอบการปฏิบัติการทั้งหมดที่แยกออกไม่ได้ การใช้@Transactional
การเผยแพร่ธุรกรรมจะได้รับการจัดการโดยอัตโนมัติในกรณีนี้หากมีการเรียกวิธีอื่นโดยวิธีปัจจุบันวิธีการนั้นจะมีตัวเลือกในการเข้าร่วมธุรกรรมที่กำลังดำเนินอยู่
ลองทำตัวอย่าง:
คือเรามี 2 แบบจำลองและCountry
City
การทำแผนที่เชิงสัมพันธ์ของCountry
และCity
รูปแบบเป็นเหมือนหนึ่งCountry
สามารถมีหลายเมืองดังนั้นการทำแผนที่เป็นเช่น
@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Lazily
ที่นี่ประเทศแมปไปยังหลายเมืองที่มีการเรียกพวกเขา ดังนั้นที่นี่มาบทบาทของ@Transactinal
เมื่อเราดึงประเทศวัตถุจากฐานข้อมูลแล้วเราจะได้รับข้อมูลทั้งหมดของวัตถุประเทศ LAZILY
แต่จะไม่ได้รับการตั้งค่าของเมืองเพราะเราเป็นเมืองเรียก
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
เมื่อเราต้องการเข้าถึงชุดของเมืองจากวัตถุในประเทศเราจะได้รับค่า Null ในชุดนั้นเพราะวัตถุของชุดที่สร้างขึ้นเท่านั้นชุดนี้ไม่เริ่มต้นด้วยข้อมูลเพื่อรับค่าของชุดที่เราใช้@Transactional
เช่น
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
ดังนั้นโดยทั่วไปแล้ว@Transactional
บริการสามารถทำการโทรหลายครั้งในการทำรายการเดียวโดยไม่ต้องปิดการเชื่อมต่อกับจุดสิ้นสุด
@Transactional
เป็นจริง
มันจะดีกว่าที่จะมีมันในชั้นบริการ! นี่เป็นคำอธิบายที่ชัดเจนในบทความหนึ่งที่ฉันพบเมื่อวานนี้! นี่คือลิงค์ที่คุณสามารถตรวจสอบได้!
@Transactional
ควรใช้กับบริการชั้นเป็นมันมีเหตุผลทางธุรกิจ ชั้น DAO มักจะมีการดำเนินการ CRUD ฐานข้อมูลเท่านั้น
// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
เลเยอร์บริการเป็นสถานที่ที่ดีที่สุดในการเพิ่ม@Transactional
คำอธิบายประกอบเนื่องจากตรรกะทางธุรกิจส่วนใหญ่อยู่ที่นี่ซึ่งมีพฤติกรรมการใช้งานรายละเอียดในระดับรายละเอียด
สมมติว่าเราเพิ่มลงใน DAO และจากบริการที่เรากำลังเรียก 2 ชั้น DAO หนึ่งล้มเหลวและความสำเร็จอื่น ๆ ในกรณีนี้ถ้า@Transactional
ไม่อยู่ในบริการหนึ่งฐานข้อมูลจะกระทำและอื่น ๆ จะย้อนกลับ
ดังนั้นคำแนะนำของฉันคือใช้คำอธิบายประกอบนี้อย่างชาญฉลาดและใช้ที่ชั้นบริการเท่านั้น
ก่อนอื่นเรามากำหนดว่าเราต้องใช้ธุรกรรมที่ไหน?
ฉันคิดว่าคำตอบที่ถูกต้องคือ - เมื่อเราต้องตรวจสอบให้แน่ใจว่าลำดับของการกระทำจะเสร็จสิ้นพร้อมกับการดำเนินการปรมาณูเพียงครั้งเดียวหรือไม่มีการเปลี่ยนแปลงใด ๆ แม้ว่าการกระทำอย่างใดอย่างหนึ่งจะล้มเหลว
เป็นวิธีปฏิบัติที่รู้จักกันดีในการนำตรรกะทางธุรกิจมาใช้ในการบริการ ดังนั้นวิธีการบริการอาจมีการกระทำที่แตกต่างกันซึ่งจะต้องดำเนินการเป็นหน่วยทางลอจิคัลเดียวของการทำงาน ถ้าเป็นเช่นนั้น - แล้ววิธีการดังกล่าวจะต้องมีการทำเครื่องหมายว่าการทำธุรกรรม แน่นอนว่าไม่ใช่ทุกวิธีที่จำเป็นต้องมีข้อ จำกัด ดังกล่าวดังนั้นคุณไม่จำเป็นต้องทำเครื่องหมายบริการทั้งหมดว่าเป็นการทำธุรกรรมการทำธุรกรรม
และยิ่งกว่านั้น - อย่าลืมคำนึงว่า@Transactionalชัดอาจลดประสิทธิภาพของวิธีการ ในการดูภาพรวมคุณต้องรู้ระดับการแยกธุรกรรม การรู้ว่าอาจช่วยให้คุณหลีกเลี่ยงการใช้@ ธุรกรรมที่ไม่จำเป็นต้องใช้
ดีกว่าที่จะเก็บ@Tractactionalในเลเยอร์กลางแยกระหว่าง DAO และ Service Layer เนื่องจากการย้อนกลับมีความสำคัญมากคุณสามารถวางการจัดการ DB ทั้งหมดของคุณลงในชั้นกลางและเขียนตรรกะทางธุรกิจใน Service Layer เลเยอร์กลางจะโต้ตอบกับเลเยอร์ DAO ของคุณ
สิ่งนี้จะช่วยคุณในหลาย ๆ สถานการณ์เช่นObjectOptimisticLockingFailureException - ข้อยกเว้นนี้เกิดขึ้นหลังจากธุรกรรมของคุณสิ้นสุดลงเท่านั้น ดังนั้นคุณไม่สามารถจับมันในชั้นกลาง แต่คุณสามารถจับในชั้นบริการของคุณตอนนี้ สิ่งนี้จะเป็นไปไม่ได้หากคุณมี @Transactional ในเลเยอร์บริการ แม้ว่าคุณสามารถจับในตัวควบคุม แต่ตัวควบคุมควรจะสะอาดที่สุด
หากคุณกำลังส่งจดหมายหรือ SMS ในเธรดแยกหลังจากตัวเลือกบันทึกลบและอัปเดตทั้งหมดคุณสามารถทำสิ่งนี้ได้ในบริการหลังจากธุรกรรมเสร็จสมบูรณ์ในเลเยอร์กลางของคุณ อีกครั้งหากคุณพูดถึง @Transactional ในเลเยอร์บริการคุณจะได้รับจดหมายแม้ว่าธุรกรรมของคุณจะล้มเหลว
การมีเลเยอร์ @Transaction ตรงกลางจะช่วยทำให้โค้ดของคุณดีขึ้นและง่ายต่อการจัดการ มิฉะนั้นถ้าคุณใช้ในเลเยอร์ DAO คุณอาจไม่สามารถย้อนกลับการดำเนินการทั้งหมดได้ หากคุณใช้ในเลเยอร์บริการคุณอาจต้องใช้AOP (Aspect Oriented Programming) ในบางกรณี
ในอุดมคติแล้วเลเยอร์บริการ (ผู้จัดการ) แสดงถึงตรรกะทางธุรกิจของคุณและดังนั้นจึงควรมีคำอธิบายประกอบด้วย@Transactional
. บริการชั้นอาจเรียก DAO ที่แตกต่างกันเพื่อดำเนินการฐานข้อมูล สมมติว่าสถานการณ์ที่คุณมีการดำเนินงาน DAO เป็นจำนวน N ในวิธีการบริการ หากการดำเนินการ DAO ครั้งที่ 1 ของคุณล้มเหลวผู้อื่นอาจยังคงผ่านไปและคุณจะสิ้นสุดสถานะฐานข้อมูลที่ไม่สอดคล้องกัน คำอธิบายประกอบเลเยอร์บริการสามารถช่วยให้คุณประหยัดจากสถานการณ์ดังกล่าว
ฉันชอบที่จะใช้@Transactional
ในชั้นบริการที่ระดับวิธี
@Transactional
ใช้ใน service layer ซึ่งถูกเรียกโดยใช้ controller layer ( @Controller
) และ service layer call ไปยัง DAO layer ( @Repository
) เช่นการดำเนินการที่เกี่ยวข้องกับฐานข้อมูล