Spring里提供了对大处理的多线程支持。对一个service的方法来说,这个@Async注解就可以简单实现处理的多线程化。(至于excutors的配置和异步支持的开启不再赘述)
说说我踩上的两个坑。
1.有个CSV的上传操作和插入DB操作,数据量比较大,故考虑异步,当然选择最简单的@Async是最理想的。DB操作中有底层包填入登录用户的功能。
而此时bug出现。这个service死活填不进去操作者!底包的问题?service问题?
仔细研究发现:系统的底层包对数据库操作者的自动填入是放在MDC中的,而这个可恶的MDC是基于线程的,用户登录会从Spring的框架中取出来,放入MDC中,退出则删除,而Async是脱离Spring mvc管理的。自然根本没有在DB登录的线程里存储。
解决方案:为了改动量更小,这里打破了一般的流程,不用底包的自动填入,而是前台controller传入登录者参数,手动塞登录者。
2.系统有个操作履历的功能,具体实现也用的异步记录,当时想法是履历成功与失败,快速还是慢速都不影响前台的操作。
此时bug出现。在连接测试中才发现,T﹏T填入的操作者是null?!而且时而出现,时而不出现。
分析:直接调用的Spring的securitycontext,与坑1类似,这时候是在另外的线程,取不到登录者!之所以本地测试没问题,默认Spring是一个线程!见图
具体分析过程画了个草稿图。
心得:必须要再深入了解下Spring的原理。不然还有坑。只是Google是会踩很多坑的,很多时候效率也不一定是最高的。这时候想问题做事多一些焦虑是好事,而用的时候多想想具体场景会不会有这样那样的问题。把时间多花在这些地方!