本文是对之前开发中遇到的问题的一个总结,文章其实早就写好,但是觉得自己写得不够深入,就让文章一直躺在草稿箱里。昨天突然想起来了,就将文章重新修改了一下,还是发出来吧!
问题1
当时我在开发一个异常日志记录接口,其实业务流程很简单,就是前端提交错误日志到后台,后台接受到信息处理一番,然后插入数据库。因为这个接口的并发量比较高,为了不影响其他业务,并且同时提高响应的速度。于是采用 @Async 注解+ Spring线程池的方案来实现。线程池的配置如下:
<task:annotation-driven executor="jobExecutor"/>
<task:executor id="jobExecutor" pool-size="20" queue-capacity="500" />
使用 task:annotation-driven/ 开启异步时,一定要记得配置executor属性,不然异步使用的线程池其实是
org.springframework.core.task.SimpleAsyncTaskExecutor ,但这个 SimpleAsyncTaskExecutor 不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
关键部分伪代码如下:
@Async
public void test(){
ExceptionLogEntity exceptionLogEntity = new ExceptionLogEntity();
exceptionLogEntity.setXX("");
exceptionLogEntity.setXXX("");
exceptionLogEntity.setIp("");
exceptionLogEntity.setUrl("");
exceptionLogEntity.setBusinessScene("");
exceptionLogEntity.setExceptionType("");
exceptionLogEntity.setExceptionDetailType("");
exceptionLogEntity.setExceptionMessage("");
exceptionLogEntity.setNoticeStatus("");
exceptionLogEntity.setCreateTime(new Date());
exceptionLogEntity.setUpdateTime(new Date());
ExceptionLogEntity insert = exceptionLogDao.insert(exceptionLogEntity);
log.info("实体的主键id=[{}]", insert.getId());
}
代码写完我简单的测试了一下,没啥问题后就告知前端可以对接了。可是奇怪的事情发生了,前端老铁告诉我接口有时会返回错误。我一听就感觉不对劲,心想这么简单的接口,我怎么可能有bug。于是我到日志平台上查询了一下日志,结果还真的是有问题。发现了一个SQL错误,具体错误如下(敏感信息已经处理):
Caused by: java.lang.reflect.InvocationTargetException
INSERT INTO `xx`(`xx`,`xx`,`ip`,`url`,`business_scene`,`exception_type`,`exception_detail_type`,`exception_message`,`notice_status`,`create_time`,`update_time`,`xx`,`member_phone`,`ip`,`url`,`business_scene`,`exception_type`,`exception_detail_type`,`exception_message`,`notice_status`,`create_time`,`update_time`) VALUES('','','','','','','',&