记录工作中的一个踩坑点
背景:
项目使用ssm,mybatis+mybatis plus,定时任务用的spring的@Scheduled注解,
现状:
同事在定时任务中注入业务service对数据库写操作,程序报错
错误信息:
### Error updating database. Cause: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
### The error may exist in com/mpi/imes/dao/sys/SysLogDao.java (best guess)
### The error may involve com.mpi.imes.dao.sys.SysLogDao.insert!selectKey
### The error occurred while handling results
### SQL: SELECT SEQ_SYS_LOG.NEXTVAL FROM DUAL
### Cause: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy21.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy530.insert(Unknown Source)
at com.baomidou.mybatisplus.service.impl.ServiceImpl.insert(ServiceImpl.java:98)
at com.mpi.imes.service.sys.SysLogServiceImpl.saveLog(SysLogServiceImpl.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Nat
原因:
因为整合了mybatis-plus,mybatis-plus有一个自动填充数据的拦截器,比如新增数据自动填充时间、创建人,修改的时候自动填充修改时间,再看该拦截器:
这里因为是定时任务调用(非web请求调用),会导致这里的request.getSession出错,错误就是上面截图,具体原因可以看源码。
临时解决方案,针对IllegalStateException一场特殊处理
public class BaseMetaObjectHandler extends MetaObjectHandler {
@Autowired
private HttpServletRequest request;
@Override
public void insertFill(MetaObject metaObject) {
try {
AdminContext adminContext = (AdminContext) request.getSession()
.getAttribute(AdminContext.SESSION_CONTEXT_NAME);
if (adminContext != null) {
setFieldValByName("creatorId", adminContext.getAdminId(), metaObject);
setFieldValByName("creator", adminContext.getName(), metaObject);
setFieldValByName("createTime", System.currentTimeMillis(), metaObject);
} else {
setFieldValByName("creatorId", 0L, metaObject);
setFieldValByName("createTime", System.currentTimeMillis(), metaObject);
}
} catch (Exception e) {
if (e instanceof IllegalStateException) {
return;
}
throw new RuntimeException(e.getMessage());
}
}
@Override
public void updateFill(MetaObject metaObject) {
try {
AdminContext adminContext = (AdminContext) request.getSession()
.getAttribute(AdminContext.SESSION_CONTEXT_NAME);
if (adminContext != null) {
setFieldValByName("updaterId", adminContext.getAdminId(), metaObject);
setFieldValByName("updater", adminContext.getName(), metaObject);
setFieldValByName("updateTime", System.currentTimeMillis(), metaObject);
} else {
setFieldValByName("updaterId", 0L, metaObject);
setFieldValByName("updateTime", System.currentTimeMillis(), metaObject);
}
} catch (Exception e) {
if (e instanceof IllegalStateException) {
return;
}
throw new RuntimeException(e.getMessage());
}
}
}
感悟
很多时候,我们遇到问题,就一股脑的去网络搜索,大概率也会搜到类似的问题,甚至相同的问题。但是我觉得除了解决问题外,我们更应该思考问题、分析问题,解决问题的同时,锻炼自己独立思考和分析能力。
针对上面这个问题,后来我就感觉自己是被网络信息给误导,导致我刚开始没有独立去思考问题、去分析问题,一味地想在网络中寻找到一样的问题,然后解决掉。其实中途很多次我有想过上面的原因,但是都被网络信息淹没。
处理问题,首先靠自己独立思考,先找到原因,再解决问题,举一反三,处理其他问题。一味靠网络来得到答案,往往只能知其然,但不知其所以然,我们要做的,就是锻炼自己的思考和分析能力,并知其然知其所以然。