自以為是
在我的想象當中,以為隻要給這個方法注釋成@Transactional, 就會處理事務,然而并非我想象的那樣,今天測試了下事務,記錄下
測試
1.首先建立一個JUnit 類來進行測試第一種方式
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:/applicationContext.xml" })
public class SpringTransTester {
@Resource
private UserMoneyMapper userMoney;
@Transactional
public void doInsert() {
UserMoney ins = new UserMoney();
ins.setId("2");
ins.setBalance(100.00);
userMoney.insert(ins);
ins.setId("2"); // ID相同,會抛出異常
ins.setBalance(99.00);
userMoney.insert(ins);
}
@Test
public void testTrans() {
List<UserMoney> list = userMoney.qryQuick("yangmf");
doInsert();
System.out.println("testTrans");
}
}
資料庫中插入了一條記錄,第二條出現了錯誤,但是沒有進行復原
百度查了下資料:
通一個類裡面如果A方法沒有事務,調用帶事務B方法,這樣B方法的事務會被忽略。
2. 改造下,把事務的方法單獨放到Service中
// 注意該類放到Spring能掃描到的地方
@Service
public class SpringTransService {
@Resource
private UserMoneyMapper userMoney;
@Transactional
public void doInnerInsert() {
UserMoney ins = new UserMoney();
ins.setId("2");
ins.setBalance(100.00);
userMoney.insert(ins);
ins.setId("2"); // ID相同,會抛出異常
ins.setBalance(99.00);
userMoney.insert(ins);
}
public void doInsert() {
doInnerInsert();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:/applicationContext.xml" })
public class SpringTransTester {
@Autowired
private SpringTransService service;
@Test
public void testTrans() {
service.doInsert();
System.out.println("testTrans");
}
}
這樣其實和第一種方法一樣,由本類的方法來調用事務, 效果和第一個一樣, 但是如果在doInsert上面也加上@Transactional,那麼事務會起作用(doInnerInsert,的注解可以去掉)
3. 再改造下
// 注意該類放到Spring能掃描到的地方
@Service
public class SpringTransService {
@Resource
private UserMoneyMapper userMoney;
@Transactional
public void doInsert() {
UserMoney ins = new UserMoney();
ins.setId("2");
ins.setBalance(100.00);
userMoney.insert(ins);
ins.setId("2"); // ID相同,會抛出異常
ins.setBalance(99.00);
userMoney.insert(ins);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:/applicationContext.xml" })
public class SpringTransTester {
@Autowired
private SpringTransService service;
@Test
public void testTrans() {
service.doInsert();
System.out.println("testTrans");
}
}
這樣可以,插入第二條是出現了一次,記錄沒有插入進去
4. 再測試下抛出Exception異常
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:/applicationContext.xml" })
public class SpringTransTester {
@Autowired
private SpringTransService service;
@Test // 加上抛出異常
public void testTrans() throws Exception {
service.doInsert();
System.out.println("testTrans");
}
}
@Service
public class SpringTransService {
@Resource
private UserMoneyMapper userMoney;
// 手動抛出異常
@Transactional
public void doInsert() throws Exception {
UserMoney ins = new UserMoney();
ins.setId("2");
ins.setBalance(100.00);
userMoney.insert(ins);
ins.setId("3"); // ID不同相同,會抛出異常
ins.setBalance(99.00);
userMoney.insert(ins);
throw new Exception("測試事務");
}
}
異常抛出了,事務沒有起作用,資料都存進去了會, 如果把Exception改成RuntimeException,事務會進行復原,看來異常不能簡單的寫個Exception。可以繼承RuntimeException