一:目标对象的内部调用无法实施切面
二:实验
1.接口定义
public interface UserManager {
Integer insert(User user);
void updateUser(User user);
}
2.实现类
@Component("userManager")
public class UserManagerImpl implements UserManager {
@Resource
private UserDao userDao;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public Integer insert(User user) {
insert = userDao.insert(user);
updateUser(user);
return insert;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void updateUser(User user) {
userDao.update(user);
System.out.println(1 / 0);
}
}
为了方便测试,update的执行sql如下,更新一下修改人,如下
UPDATE tb_user SET update_user = '1026' where id = #{id,jdbcType=BIGINT}
3.测试方法
@Test
public void testInsert() {
User user = new User();
user.setUserName("201808232313");
user.setPassWord("201808232313");
user.setTelPhone("201808232313");
user.setEmail("[email protected]");
user.setCreateUser("201808232313");
user.setUpdateUser("苍生1");
Integer insert = userManager.insert(user);
logger.debug("testInsert" + insert);
}
4.执行结果,msyql默认可重复读隔离级别,猜测测试方法执行过后数据库的情况,
- 数据插入失败
- 数据插入成功,更新失败
- 数据插入成功,更新成功
5.执行test方法,数据库没有插入记录。到此还没结束,不过一般我们这样写不会什么问题。
三:修改实现类的方法,测试其他情况
1.insert方法中,对update的方法,异常进行处理,没有把异常再次抛出
@Override
@Transactional(propagation = Propagation.REQUIRED)
public Integer insert(User user) {
Integer insert = 0;
insert = userDao.insert(user);
try {
//对方法进行异常处理
updateUser(user);
} catch (Exception e) {
e.printStackTrace();
// throw new RuntimeException(e);
}
return insert;
}
结果发现update方法居然执行成功了,数据被更新,事务失效了。
2.再次修改实现类的方法
@Override
@Transactional(propagation = Propagation.REQUIRED)
public Integer insert(User user) {
Integer insert = 0;
insert = userDao.insert(user);
try {
//对方法进行异常处理
// updateUser(user);
((UserManager) AopContext.currentProxy()).updateUser(user);
} catch (Exception e) {
e.printStackTrace();
// throw new RuntimeException(e);
}
return insert;
}
结果发现update方法的数据被回滚了
3.修改配置文件,在原有的<tx:annotation-driven/> 后增加一句 <aop:config expose-proxy="true"></aop:config>
如下
<tx:annotation-driven/>
<!--配置文件增加下面一行-->
<aop:config expose-proxy="true"></aop:config>
测试发现insert和update都被回滚了
四:总结
事务控制,最简单的方式就是加了注解的方法不对异常处理,发生异常就回滚数据。如果事务比较复杂,就需要考虑事务调用方法,异常处理和事务配置。防止目标对象内部的方法调用失效。
使用AopContext.currentProxy() 配置文件 <aop:config expose-proxy="true"></aop:config>