Java work note
2016-09-25Java单测注意事项
SQL:
update user set name = 'a' where age = 1;
数据库-user
ID | name | age |
---|---|---|
1 | a | 1 |
2 | b | 2 |
以上SQL执行结果是:
Query OK, 1 row affected (0.00 sec)
Rows matched:2 Changed:1 Warnings:0
⚠️ matched:2,changed:1
而在代码做单测时若测试如下接口:
public interface UserMapper{
@Update("update user set name = 'a' where age = 1")
int updateUser();
}
⚠️ 结果返回2,指的是matched结果,而不是实际changed的数量
⚠️使用mock做单测时,serviceImpl的实现类使不允许有@Transactional
注释的,否则无法通过测试,事务控制应该在Dao层处理。
public class Test {
public static void main(String[] args) {
System.out.println("result=" + new Test().test());;
}
static int test()
{
int x = 1;
System.out.println("1111");
try{
System.out.println("222");
return x;
}
finally{
System.out.println("333");
++x;
}
}
}
`111
222
333
result=1`
注意:这里涉及到一个栈帧的问题。 在catch中执行的时候,return之前是需要去执行finally的。执行finally之前,把当前要返回的值的引用保存到一个slot【槽】中,也就是说return已经执行,但是还没返回(debug模式下可以看的很清楚),把当前要返回的值保存起来了。 然后执行finally,执行完finally,再从slot中取出要返回的值进行返回。如果返回的是一个对象的引用的话,那么将是finally执行后的值。如果是一个基本类型的话,那么返回的就只是那个基本类型的值了。 【在这里需要注意一点的是,引用类型修改会反映到返回值中,是因为存储在slot中的是对象的引用。在finally中修改的时候,修改的内容已经保存到堆中的对象了。此时return,会反映出修改后的结果。】
Transactional 使用
mysql的表是有事务安全( 比如:InnoDB)和非事务安全(比如:ISAM、MyISAM)之分的 注意
情况1: 不加事务控制,都成功
```java public void a() { System.out.println(“a:” + epsxSupplierMapper.insertTest(“a”, 1)); //入库成功 b(); }
public void b() throws Exception{
System.out.println("b:" + epsxSupplierMapper.insertTest("b", 2)); //入库成功
int x = 10/0;
} ```
情况2: b()加失效,原因是动态代理控制事务切面在a()上
public void a() {
System.out.println("a:" + epsxSupplierMapper.insertTest("a", 1)); //入库成功
b();
}
@Transactional // `失效`
public void b() throws Exception{
System.out.println("b:" + epsxSupplierMapper.insertTest("b", 2)); //入库成功
int x = 10/0;
}
情况3:
@Transactional
public void a() {
System.out.println("a:" + epsxSupplierMapper.insertTest("a", 1)); //入库回滚
b();
}
public void b() throws Exception{
System.out.println("b:" + epsxSupplierMapper.insertTest("b", 2)); //入库回滚
int x = 10/0;
}
情况4 正确方式, 注意: spring.aop.proxy-target-class=true; @EnableTransactionManagement
public void a() {
System.out.println("a:" + epsxSupplierMapper.insertTest("a", 1)); //入库成功
Test aTest = (Test) AopContext.currentProxy(); // 注意这里
aTest.b();
}
@Transactional
public void b() throws Exception{
System.out.println("b:" + epsxSupplierMapper.insertTest("b", 2)); // 入库回滚
int x = 10/0;
}
情况5
@Transactional //只要这里加上,不论b()是否增加@Transactional,只要b失败,a就回滚
public void a() {
System.out.println("a:" + epsxSupplierMapper.insertTest("a", 1)); // 入库回滚
Test aTest = (Test) AopContext.currentProxy(); // 注意这里
aTest.b();
}
@Transactional
public void b() throws Exception{
System.out.println("b:" + epsxSupplierMapper.insertTest("b", 2)); // 入库回滚
int x = 10/0;
}