@Transactional 事务代理失效问题
在Spring中是通过aop增强对@Transactional注解标注的方法进行事务代理的。
但是如果通过 this 调用该方法,那么这个注解就会失效,也就是事务代理失效。
原因:
aop的实现原理是在管理的bean中匹配切入点,然后对bean执行的方法进行增强。
而通过 this 调用,这个 this 是不被 Spring 管理的,如何找到它并且匹配切入点呢??
简而言之,只有当该方法是被 Spring 的代理对象执行时,aop增强才会生效。
事务加入问题
1 | public Class Test { |
代码中存在一个被代理对象调用并标注 @Transactional
注解的 proxyFunc
方法,其内部通过 this 指针调用了两个数据库操作。
这里的两个数据库操作会加入 proxyFunc 的事务吗?
答案:会。
原因:因为 proxyFunc 已经被 @Transactional 增强了,开启了事务,那么其内部所有的数据库操作都会加入这个事务。
事务冒泡问题
1 | public Class Test { |
还是一样的代码,不过这次给数据库操作1标注了 @Transactional(propagation = Propagation.NOT_SUPPORTED)
不支持事务的注解,也表示不会加入其他事务。
那么这个注解会生效吗?
答案:不会
原因:因为数据库操作1是通过 this 调用的,而不是 proxy 代理对象,不会被aop“增强”,也就是注解失效!
不是最外层是 proxy 代理的,内部就都是它代理,可以回想一下 aop 增强的实现代码,本质是在目标方法的外层再包装一层逻辑,所以这个 proxy 只会包装最外层的注解增强代码,无法处理内部。
那事务冒泡配置注解什么时候使用呢?
可以在其他 service 的代码中使用,通过注入其代理对象,然后使用目标方法,这时候由于是 proxy 代理的,注解就会正常生效。
1 | public Class OtherService { |
1 | public Class Test { |
如果需要分离方法体单独封装,又不能通过 this 调用,该如何保证目标方法事务生效呢
答案:手动获取代理对象,然后通过代理对象调用目标方法;
1 | public Class TestService { |
获取工作目录根路径
通过 System 方法获取环境属性。
1 | String rootWorkPath = System.getProperty("user.dir") |
拼接其他路径
使用 java.nio.file
下的 Paths
工具类
1 | String path = Paths.get(rootWorkPath, "path1", "path2 ...") |
线程安全
不可变对象也是线程安全的。
如 List、String 等。
但是引用提升至 List 的 ArrayList 实例同样是线程不安全的。
异步下,对 ArrayList 的插入操作,会导致 length 和 列表元素 出现错乱。
为什么大部分类都是线程不安全的?
因为线程安全会影响性能,应交由开发者自由控制。