自以为是
在我的想象当中,以为只要给这个方法注释成@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