一个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 ...
随机推荐
- 提取excel表数据成json格式的以及对图片重命名
开发那边的需求 1.功夫熊猫以及阿狸布塔故事集都是属于剧集的.意思就是有很多集,这里称他们为tv最下面这几行第一列没名字的都是单集的,这里称它们为mv需要统计所有工作表里面的数据把tv放一个大的jso ...
- vmware上虚拟机:Network error: Connection refused 排查
问题分析 vmware配置的fedora虚拟机, 主机能ping通虚拟机, 虚拟机也能ping通主机.但是用PUTTY连接虚拟机的时候出现 Network error: Connection refu ...
- EVM项目管理
详细参照:https://zhuanlan.zhihu.com/p/33925657 报告日实际: 按预算完成 按原始cpi完成 按时完成
- ssh登录原理及免密登录配置
ssh登录原理参考: https://www.cnblogs.com/hukey/p/6248468.html ssh登录有两种方式: 1):用户名密码登录 2):基于秘钥的登录 ssh免密登录指的就 ...
- Windows下面Node和NPM的绿色安装及配置
1,Node安装 Windows版本可以在http://nodejs.org/#download下面选择msi安装版或者绿色版.其实Node的安装主要是Node.exe文件deploy和有关环境变量的 ...
- 【总结】Java异常分类
链接:https://www.nowcoder.com/questionTerminal/3ded1983c85c4ae197e005bd31777bc7来源:牛客网 Throwable是所有异常的根 ...
- 生成3位的序列号_仅仅CASE WHEN的简单应用
PNo, , ) AS sn INTO #temp1 FROM tbl_test SELECT ), sn) ), sn) ), sn) END AS sn, PNo FROM #temp1
- windows短路径转换成长路径
参考: https://blog.csdn.net/wxqian25/article/details/43951281 https://docs.microsoft.com/en-us/windows ...
- RMAN-06900 RMAN-06901 ORA-19921
转自http://blog.itpub.net/12778571/viewspace-700360/ 1.连接到rman中$ rman target/Recovery Manager: Release ...
- 通过jedis远程访问redis服务器
一.jedis简介 类似于mysql数据库,一般开发都需要通过代码去访问redis服务器,对于主流的开发语言,redis提供了访问的客户端接口. https://redis.io/clients 而对 ...