ก่อนที่จะอธิบายปัญหา ให้ฉันอธิบายสถานที่บางประการ สมมติว่าธุรกรรมฐานข้อมูลได้รับการกำหนดค่าในไฟล์การกำหนดค่า Spring ในลักษณะต่อไปนี้:
<bean id="transactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven ธุรกรรม-manager="transactionManager" />
ขณะนี้มี UserDao และ SecurityService:
@Repository คลาสสาธารณะ UserDao { public User getUser() { // สืบค้นผู้ใช้จากตารางผู้ใช้ return queryObject("select * from user order by id desc Limit 1");
@Service @Transactional public class SecurityService { @Autowired ส่วนตัว UserDao userDao; public void checkUserInfo() { while(true) { User user = userDao.getUser(); if(user != null && "Tom".equals(user.getName ()) { System.out.println("ทอมอยู่ที่นี่"); แตก;
ในระหว่างกระบวนการเรียกเมธอด SecurityService#checkUserInfo() ข้อมูลที่ได้รับผ่านเมธอด userDao#getUser() ยังคงไม่เปลี่ยนแปลง แม้ว่าข้อมูลใหม่ชื่อ Tom จะถูกแทรกในเวลานี้ การวนซ้ำจะไม่สิ้นสุด นอกจากนี้ การลบคำอธิบายประกอบ @Transactional บน SecurityService จะไม่ช่วยอะไร
ก่อนอื่น ฉันคิดว่าอาจเป็นปัญหากับพูลการเชื่อมต่อฐานข้อมูล เช่นเดียวกับเมื่อถูกแทนที่ด้วย Spring ของตัวเอง จากนั้นฉันก็เรียกอ็อบเจ็กต์การเชื่อมต่อโดยตรงจาก JdbcTemplate และใช้วิธี JDBC ดั้งเดิมเพื่อดำเนินการฐานข้อมูล ในเวลานี้ ข้อมูลมีการเปลี่ยนแปลงแบบเรียลไทม์ ดังนั้นฉันคิดว่าธุรกรรมของ Spring ควรจะเชื่อมโยงกับเธรดการดำเนินการปัจจุบัน หลังจากตรวจสอบซอร์สโค้ดแล้ว ฉันพบในเมธอด DataSourceUtils#doGetConnection ที่ Spring สร้างการเชื่อมต่อบนแต่ละ DataSource ของแต่ละเธรดและผูกไว้กับธุรกรรม เนื่องจากไฟล์การกำหนดค่า tx:annotation-driven ทำการผูกธุรกรรมบนเลเยอร์บริการทั้งหมด (คลาสที่มีคำอธิบายประกอบด้วย @Service) การเชื่อมต่อเดียวกันจึงถูกผูกไว้ในเธรดเดียวกันโดยไม่คำนึงว่า @Transactional จะถูกใช้หรือไม่ แต่ไม่ได้ดำเนินการเพียงการดำเนินธุรกิจ .
หลังจากการทดลองและค้นหาข้อมูลมากมาย ในที่สุดฉันก็พบวิธีแก้ปัญหาที่สมบูรณ์แบบ: เพียงเพิ่มคำอธิบายประกอบ @Transactional(propagation = Propagation.NOT_SUPPORTED) ให้กับเมธอด checkUserInfo ข้างต้น แน่นอน คุณยังสามารถรับการเชื่อมต่อและดำเนินการด้วยตนเอง หรือคุณสามารถใช้แพ็คเกจ DateUtils เพื่อดำเนินการได้