一个request引发的bug
有很多错误由于需要是多线程是才会发生,导致经常在开发时很难发现,
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的更多相关文章
- 一个排序引发的BUG
你好呀,我是why. 前两天在 Git 上闲逛的时候又不知不觉逛到 Dubbo 那里去了. 看了一下最近一个月的数据,社区活跃度还是很高的: 然后看了一下最新的 issue,大家提问都很积极. 其中看 ...
- 一个空格引发的bug
好久没写博客了. 我们的一个项目用的thinkphp框架,当在debug模式下面运行很正常,但切换到生产模式时,刷新页面第一次可以正常显示,刷新第二次会出现错误如下: Fatal error: Cal ...
- 一个 passive 引发的bug
不是什么很难的东西,权且做个记录. 首先说下背景,目前的项目中,需要同时绑定 wheel 和 scroll 事件. 绑定 wheel,目的是开发 ctrl + wheel 缩放页面功能,此功能与浏览器 ...
- 一个字体引发的bug
delphi 7 中默认字体样式为‘MS Sans Serif’,一般情况下子级控件会继承父级一些属性,其中包括字体(包括字体大小,字体样式,颜色等)属性.如果动态创建控件且需要修改字体颜色或者大小时 ...
- Spring 循环引用(一)一个循环依赖引发的 BUG
Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...
- 由一个emoji引发的思考
由一个emoji引发的思考 从毕业以来,基本就一直在做移动端,但是一直就关于移动端的开发,各种适配问题的解决,在日常搬砖中处理了就过了,也没有把东西都沉淀下来,觉得甚是寒颜.现就一个小bug,让我们来 ...
- 安卓微信overflow-x overflow-y引发的bug
今天xgo文章图片页上线用微信扫页面发现一个bug,页面可以双击放大缩小. 找了半天原因,发现是图片描述设置了overflow-y引发的bug. 建议在微信场景里满屏显示不能滚动的页面里慎用overf ...
- QByteArray引发的bug
QByteArray引发的bug 在接收UDP数据的函数里,有如下代码片段 if(0x10 == data.size() && 0xCA == (unsigned char)data. ...
- PHP 中一个 False 引发的问题,差点让公司损失一百万
PHP 中一个 False 引发的问题,差点让公司损失一百万 一.场景描述 上周我一个在金融公司的同学,他在线上写一个 Bug,差点造成公司损失百万.幸好他及时发现了这个问题并修复了.这是一个由 PH ...
随机推荐
- 我发起了一个 支持 ServerFul 架构 的 .Net 开源项目 ServerFulManager
大家好, 我发起了一个 支持 ServerFul 架构 的 .Net 开源项目 ServerFulManager . ServerFulManager 的 目标 是 实现一个 支持 ServerFu ...
- Windows 数字化器类输入设备--笔设备分析(1)(原创)
一.前言: 参考microsoft公司的链接:https://developer.microsoft.com/zh-cn/windows/hardware 将对Windows数字化器类输入设备--笔设 ...
- mysql 设置初始密码
mysqladmin -uroot password "123" 设置初始密码 由于原密码为空,因此-p可以不用 mysqladmin -uroot -p"123&quo ...
- git bash的一些使用经验
1.最开始使用git的时候, git remote -v 查看远程仓库 报了一个错误fatal: not a git repository (or any of the parent director ...
- [蓝桥杯]PREV-13.历届试题_网络寻路
题目描述: 代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #define LEN ...
- ThinkPhp框架分页查询和部分框架知识
一.一个条件的查询数据 查询数据自然是先要显示出数据,然后根据条件进行查询数据 (1)显示出表的数据 这个方法我还是写在了HomeController.class控制器文件中 (1.1)写了一个方法s ...
- 6.824 LAB1 环境搭建
MIT 6.824 LAB1 环境搭建 vmware 虚拟机 linux ubuntu server 安装 go 官方安装步骤: 下载此压缩包并提取到 /usr/local 目录,在 /usr/l ...
- ScheduledThreadPoolExecutor线程池scheduleAtFixedRate和scheduleWithFixedDelay的区别
ScheduledFuture<?> result = executor.scheduleAtFixedRate(task,2, 5, TimeUnit.SECONDS); 在延迟2秒之后 ...
- 解决Flask局域网内访问不了的问题
在服务器上使用http://127.0.0.1:5000可以访问,但是在局域网内通过服务器IP地址访问不了,解决办法为:设置Flask为任何地址均可以访问,post设置为‘0.0.0.0’, if _ ...
- 20175236 JAVA MyCP(课下作业)
具体描述: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内容 ...