有很多错误由于需要是多线程是才会发生,导致经常在开发时很难发现,

import java.lang.reflect.ParameterizedType;
import java.util.List; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils; import com.google.gson.Gson;
import com.qdyq.common.criteria.Criteria;
import com.qdyq.common.orm.BaseEntity;
import com.qdyq.common.orm.BaseMapper;
import com.qdyq.common.orm.MySqlSessionFactoryBean; import qdyq.api.service.CommonService;
import qdyq.api.service.exception.MapperNameErrorException; @Service("common")
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CommonServiceImpl implements CommonService { //private String entityName;
private ThreadLocal<String> entityNameSafe = new ThreadLocal<String>(); @Autowired
private MySqlSessionFactoryBean sqlSessionFactory; public List list(Criteria criteria) {
BaseMapper mapper = getMapper();
System.out.println(mapper.getClass().getName());
return mapper.getBy(criteria);
} public BaseEntity getById(Long id) {
BaseMapper mapper = getMapper();
return mapper.getById(id);
} public int save(String entityJson) {
BaseMapper mapper = getMapper();
BaseEntity entity = (BaseEntity) new Gson().fromJson(entityJson, this.getEntityClass()); if(entity==null){
System.err.println(Thread.currentThread().getId() + entityJson + this.entityNameSafe.get());
} if (entity.getId() == null)
return mapper.insert(entity);
else
return mapper.update(entity);
} public int save(BaseEntity entity) { this.setEntityName(entity.getClass().getSimpleName()); BaseMapper mapper = getMapper(); System.err.println(mapper.getClass().getName() + Thread.currentThread().getId()); if (entity.getId() == null)
return mapper.insert(entity);
else
return mapper.update(entity);
} public int countBy(Criteria criteria) {
BaseMapper mapper = getMapper();
return mapper.countBy(criteria);
} public void setEntityName(String entityName) {
this.entityNameSafe.set(entityName);
//this.entityName = entityName;
} public Class getEntityClass() {
String daoName = this.sqlSessionFactory.getPkgName() + "." + this.entityNameSafe.get() + "Dao";
Class daoInterface;
try {
daoInterface = Class.forName(daoName);
return (Class) ((ParameterizedType) daoInterface.getGenericInterfaces()[0]).getActualTypeArguments()[0];
} catch (ClassNotFoundException e) {
throw new MapperNameErrorException("无效的entityName" + daoName, e, daoName);
} catch (Exception e) {
throw new MapperNameErrorException("未注册的entityName" + daoName, e, daoName);
}
} public List listAss(Criteria criteria) {
BaseMapper mapper = getMapper();
return mapper.getAssBy(criteria);
} public List all() {
BaseMapper mapper = getMapper();
return mapper.findAll();
} public int delete(Object[] id) {
BaseMapper mapper = getMapper();
return mapper.deleteByIds(id);
} protected BaseMapper getMapper(){
String daoName = this.sqlSessionFactory.getPkgName() + "." + this.entityNameSafe.get() + "Dao";
Class daoInterface;
System.err.println(daoName + Thread.currentThread().getId());
HttpServletRequest request = null;
try{
daoInterface = Class.forName(daoName);
request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
return (BaseMapper) context.getBean(daoInterface);
}catch(Exception e){
throw new RuntimeException("无法获取到mapper:" + this.entityNameSafe.get());
} } public int saveAll(List<BaseEntity> list) {
BaseMapper mapper = getMapper();
return mapper.insertAll(list);
} public int removeBy(Criteria criteria){
BaseMapper mapper = getMapper();
return mapper.removeBy(criteria);
} public static void main(String[] args){
//String json = "{id:485,lastTraceDate:'2017-11-09T10:20:37.293Z'}"; }
}

这是一个公共的类,能满足一般的增删改查功能,通过参数,entityName来确定具体使用哪个mapper来完成任务,mapper只要有一个公共的基类,就可以实现上述

功能,但是由于网络请求是多线程的,所以及易导致entityName的冲突,因为原先的entityName只是一个本地字符串,而springmvc的对象又是单例的,这就导致错误的发生

ThreadLocal<String>是一种解决办法,第二种办法是把该对象配置成原型模式,也可以避免错误的发生.

既然类成员变量容易导致错误,哪么request会不会导致错误,因为这次错误引起了思考果断做了测试,
@ResponseBody
@RequestMapping(value = "/save/{entityName}", method = RequestMethod.POST)
public Object save(@PathVariable String entityName, String entityJson,HttpServletRequest request) {
this.getService().setEntityName(entityName);
System.err.println("============================");
System.err.println(request.hashCode());
System.err.println(this.request.hashCode());
System.err.println(this.request.getParameter("entityJson"));
System.err.println(this.request.getClass().getName());
System.err.println(request.getClass().getName());
System.err.println("============================");
return getService().save(entityJson);
}

this.request是通过@Autowired注入的,打印结果到显示this.request始终是一个对象,但是它的获取结果却始终都是正确的,因为它并不是一个对象而是一个代理,也就是说它是线程安全的.但是作为参数传进来的request就不是线程安全的,如果你把它保存在一个成员变量里,后果是很严重的,因为使用过期的request会导致现有request参数的丢失,具体原因还不太清楚,感觉应该是request这个对象里使用缓存之类的东西造成的.

一个request引发的bug的更多相关文章

  1. 一个排序引发的BUG

    你好呀,我是why. 前两天在 Git 上闲逛的时候又不知不觉逛到 Dubbo 那里去了. 看了一下最近一个月的数据,社区活跃度还是很高的: 然后看了一下最新的 issue,大家提问都很积极. 其中看 ...

  2. 一个空格引发的bug

    好久没写博客了. 我们的一个项目用的thinkphp框架,当在debug模式下面运行很正常,但切换到生产模式时,刷新页面第一次可以正常显示,刷新第二次会出现错误如下: Fatal error: Cal ...

  3. 一个 passive 引发的bug

    不是什么很难的东西,权且做个记录. 首先说下背景,目前的项目中,需要同时绑定 wheel 和 scroll 事件. 绑定 wheel,目的是开发 ctrl + wheel 缩放页面功能,此功能与浏览器 ...

  4. 一个字体引发的bug

    delphi 7 中默认字体样式为‘MS Sans Serif’,一般情况下子级控件会继承父级一些属性,其中包括字体(包括字体大小,字体样式,颜色等)属性.如果动态创建控件且需要修改字体颜色或者大小时 ...

  5. Spring 循环引用(一)一个循环依赖引发的 BUG

    Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...

  6. 由一个emoji引发的思考

    由一个emoji引发的思考 从毕业以来,基本就一直在做移动端,但是一直就关于移动端的开发,各种适配问题的解决,在日常搬砖中处理了就过了,也没有把东西都沉淀下来,觉得甚是寒颜.现就一个小bug,让我们来 ...

  7. 安卓微信overflow-x overflow-y引发的bug

    今天xgo文章图片页上线用微信扫页面发现一个bug,页面可以双击放大缩小. 找了半天原因,发现是图片描述设置了overflow-y引发的bug. 建议在微信场景里满屏显示不能滚动的页面里慎用overf ...

  8. QByteArray引发的bug

    QByteArray引发的bug 在接收UDP数据的函数里,有如下代码片段 if(0x10 == data.size() && 0xCA == (unsigned char)data. ...

  9. PHP 中一个 False 引发的问题,差点让公司损失一百万

    PHP 中一个 False 引发的问题,差点让公司损失一百万 一.场景描述 上周我一个在金融公司的同学,他在线上写一个 Bug,差点造成公司损失百万.幸好他及时发现了这个问题并修复了.这是一个由 PH ...

随机推荐

  1. JavaScript中的ononline事件和onoffline事件

    关于这个时间的描述到处都有,但基本上都是说离线在线什么的我一下子还没反应过来.后再在这里看到了一句话:"断开网络再联网试试,就可以看到连线的提示."这才反应过来,原来指的是网络状态 ...

  2. 深度系统 deepin 15.9 关闭桌面

    深度系统 deepin 15.9 关闭桌面 由于特别的原因,关闭深度的桌面. sudo systemctl disable lightdm 如果需要在命令模式进入桌面可以使用以下命令. sudo se ...

  3. 原生JS实现选中的radio变为未选中

    需求如下,radio已经选中,再点击,取消选中状态. 效果如链接:演示地址 直接上代码: <!DOCTYPE html> <html> <head> <met ...

  4. Windows7 Autoconfiguration IPv4 Address 导致无法上网

    Windows7 Autoconfiguration IPv4 Address 导致无法上 (2010-03-30 16:44:57) 转载▼ 标签: 杂谈 分类: 电脑软件问题 Windows7 A ...

  5. DevExpress中GridControl的使用笔记(转)

    转自:https://www.jianshu.com/p/badc1d2f0841 注:练习例子为: DxApplication1 -> XtraForm1 , 例子上传到本博中 2019.4. ...

  6. Linux updatedb命令详解

    Linux updatedb命令 updatedb 命令用来创建或更新 locate 命令所必需的数据库文件. updatedb 命令的执行过程较长,因为在执行时它会遍历整个系统的目录树,并将所有的文 ...

  7. 记录一个源码安装mysql5.6的方法

    https://www.jb51.net/article/118853.htm 如果之前源码安装过mysql5.6的话,卸载方法如下:rm -rf /var/lib/mysql/rm -rf /usr ...

  8. HUE安装过程中的一些坑

    1. gcc: error: krb5-config:: No such file or directory 执行安装krb5-devel yum provides krb5-config 得到提示: ...

  9. @RequestParam、@ReqeustBody、@ReponseBody认识

    简介: @RequestParam和@RequestBody均是处理request body部分的注解,都用于获取请求部分的参数. @ResponseBody是用于响应部分的注解 1. @Reques ...

  10. 玩了下opencv的aruco(python版)

    简单的玩了下opencv里头的aruco,用的手机相机,手机装了个 ip摄像头,这样视频就可以传到电脑上了. 首先是标定,我没打印chessboard,直接在电脑屏幕上显示,拍了17张,大概如下: 又 ...