天天看點

Spring 的事務測試

自以為是

在我的想象當中,以為隻要給這個方法注釋成@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