引言

  最近LZ的工作发生了重大变化,以后博文的更新速度可能会再度回温,希望猿友们可以继续关注。

  近期LZ辞掉了项目经理的工作,不过并未离开公司,是转到了基础研发部做更基础的研发,为广大技术人员服务。这会让LZ有更多的时间去研究一些技术方面的东西,LZ打算折腾一下spring的源码,期待有一天可以成为spring代码的贡献者。

  好了,废话说到这里吧,今天先分享两个小问题的解决办法,可能你以后也会遇到的。

DBCP数据源坑爹的地方

  前几天系统出现了一个错误,比较奇葩。中文解释是“无法从套接字读取更多的数据”,原因是connection reset。首先很明显的是,这是数据库的连接出了问题,因为这个错误是在sql执行时报的错。

  从tcp原理上分析,这个错误的原因是因为连接被无缘无故的关闭了,导致连接被重置。于是简单分析过后,怀疑是因为连接长时间没有使用已经失效,但是连接池依然把连接给了应用程序去使用,结果导致使用了已经失效的连接。

  于是LZ简单搜索了一下,发现很多人都说有一个属性可以控制在把连接交给数据源之前,先进行一下可用性的检测。于是LZ打开源码,看了一下这个属性的初始值,结果一看,发现是true。

     /**
* The indication of whether objects will be validated before being
* borrowed from the pool. If the object fails to validate, it will be
* dropped from the pool, and we will attempt to borrow another.
*/
protected boolean testOnBorrow = true;

  这尼玛就奇怪了,已经是true了,那说明借用之前应该已经验证了,为毛还会出现上面的错误?

  LZ不服气,于是在本地启动了一下应用,跟踪了连接获取的过程,发现压根就没验证。于是LZ再次把整个数据源初始化的代码都看了一遍,才发现DBCP最坑爹的地方。看下面的代码。

     // Can't test without a validationQuery
if (validationQuery == null) {
setTestOnBorrow(false);
setTestOnReturn(false);
setTestWhileIdle(false);
}

  LZ看见的时候当时就TM想爆粗口了,这尼玛不是坑爹是什么?validationQuery默认就是空的,这不是相当于testOnBorrow默认是false吗,还在属性上写个true误导我等菜鸟程序猿。如果LZ不是闲着没事看了看初始化的源码,估计还在一直蛋疼这个问题,而且还要面临业务同事的鄙视。

  最终,设置了validationQuery属性以后,解决了这个小小的疑难杂症。各位猿友也要注意下,在使用DBCP时,最好设置一下validationQuery。

  

高端springmvc的滥用

  接下来的故事,是LZ滥用springmvc的故事,幸好LZ在上线之前就发现了这个问题,没有在合作伙伴面前丢人。

  随着公司的发展,需要与合作伙伴进行系统对接,于是LZ需要编写一个处于互联网上的服务端。上一篇博文里LZ简单介绍了加密的过程,本次则是后续LZ在做单元测试过程中发现的问题。

  由于服务端的调用会比较频繁,因此LZ在做单元测试的时候,专门写了并发访问的测试,期待能够简单的得到一个并发量的极限。结果却出乎意料,并发量极限没得到,却发现在跑的过程中,服务端爆了一些空指针错误。

  其实空指针错误也算是java当中最好解决的异常之一了,只要找到堆栈提示的位置,分析一下哪个表达式可能为空就基本上能解决问题。不过这次不同的是,LZ分析完以后,发现得到的结果是“不可能出现空指针异常”。

  怎么会不可能出现呢?看看下面这段简单的代码,这段代码不是真实的代码,但道理一样。

    user.setName("xiaolongzuo");
//某一大堆与user无关的代码以后
user.setSex("1");

  错误提示的是setSex那一行空指针,那么从代码上看,只有user为空时才会报空指针,但是假设user为空,那么在第一行就应该已经报了空指针错误,怎么可能到第三行才报出来呢?所以结论就是“不可能出现空指针异常”。

  后来LZ仔细分析之后才发现,LZ的结论是没错的,但那个结论的前提是程序按照代码编写的顺序执行。很明显,这是由于并发造成的,归根结底,是因为LZ以前从未用过springmvc,本次写服务端,由于希望发布restful风格的服务,因此选择了springmvc,抛弃了struts。

  springmvc的请求上下文是方法,struts的请求上下文是Action。LZ在代码当中错误的将请求作为了Action的属性出现,于是当并发访问时,请求中的参数就可能出现混乱,导致在第一行的时候user还不为空,到第三行的时候,由于请求被另外一个线程更新了,于是导致user为空,出现了奇葩的空指针,更加形象的代码如下。

    ((User)request.getAttribute("user")).setName("xiaolongzuo");
//某一大堆与user无关的代码以后
((User)request.getAttribute("user")).setSex("1");

  解决办法有两种,第一种是去除Action中的request属性,保证线程安全,不过这样的话不少代码会出现编译错误。第二种是使用ThreadLocal,这种办法相对来说比较简单,而且不会出现编译错误,只需要简单的更改几行代码即可。

  最终,LZ采取了第二种办法,再次进行测试时,问题再也没有出现。为了保证错误真正解决了,LZ还特意加大了并发量,多测试了几次,依旧没有出现该问题。

小结

  本文没有高大上的技术,更多的算是LZ自己的一个问题记录,猿友们下次见!

分享两个你可能不知道的Java小秘密的更多相关文章

  1. 震惊!90%的程序员不知道的Java知识!

    震惊!90%的程序员不知道的Java知识! 初学Java的时候都会接触的代码 public static void main(String[] args){ ... } 当时就像背公式一样把这行代码给 ...

  2. 你可能不知道的java、python、JavaScript以及jquary循环语句的区别

    一.概述 java循环语句分为四种形式,分别是 while, do/while, for, foreach: python中循环语句有两种,while,for: JavaScript中循环语句有四种, ...

  3. 【总结】你所不知道的Java序列化

    我们都知道,Java序列化可以让我们记录下运行时的对象状态(对象实例域的值),也就是我们经常说的对象持久化 .这个过程其实是非常复杂的,这里我们就好好理解一下Java的对象序列化. 1. 首先我们要搞 ...

  4. 分享几个你可能不知道的交互式Git 命令

    摘要:本文中讲述的几个交互式 Git 命令可以帮助你将文件的特定部分组合成提交. 本文分享自华为云社区<Git你有可能不知道交互式暂存>,作者:龙哥手记. 本节中的几个交互式 Git 命令 ...

  5. 你所不知道的java编程思想

    读thinking in java这本书的时候,有这么一句话“在编译单元的内部,可以有一个公共(public)类,它必须拥有与文件相同的名字” 有以下疑问: 在一个类中说可以有一个public类,那是 ...

  6. 你所不知道的 Java 之 HashCode

    之所以写HashCode,是因为平时我们总听到它.但你真的了解hashcode吗?它会在哪里使用?它应该怎样写? 相信阅读完本文,能让你看到不一样的hashcode. 使用hashcode的目的在于: ...

  7. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

  8. Java你可能不知道的事(3)HashMap

    概述 HashMap对于做Java的小伙伴来说太熟悉了.估计你们每天都在使用它.它为什么叫做HashMap?它的内部是怎么实现的呢?为什么我们使用的时候很多情况都是用String作为它的key呢?带着 ...

  9. java你可能不知道的事(2)--堆和栈

    在java语言的学习和使用当中你可能已经了解或者知道堆和栈,但是你可能没有完全的理解它们.今天我们就一起来学习堆.栈的特点以及它们的区别.认识了这个之后,你可能对java有更深的理解. Java堆内存 ...

随机推荐

  1. 烂泥:centos安装及配置DNS服务器

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 要在centos配置DNS服务器,要先安装DNS软件BIND.当然我们也可以安装其他的DNS软件,比如国内的开源DNS软件DNSPod. 在此我们以通过 ...

  2. Syslog-ng

    一.简介 与 syslog相比 ,syslog-ng 具有众多高级的功能:更好的网络支持,更加方便的配置,集中式的网络日志存储,并且更具有弹性.比如,使用syslogd时,所有的iptables日志与 ...

  3. poj 3237 Tree [LCA] (树链剖分)

    poj 3237 tree inline : 1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高. 2. 很明显,类 ...

  4. 简单好用的日志管理工具 Logrotate

    前言 日志就像程序的生命记录仪,详细记录下了程序运行的点点滴滴. 慎重的选择记录哪些日志:在茫茫日志海中寻找真正记录问题的日志,你是不想经历的: 精心的定时压缩转移日志:故障发生了,日志却丢了,此时的 ...

  5. UESTC 916 方老师的分身III --拓扑排序

    做法: 如果有a<b的关系,则连一条a->b的有向边,连好所有边后,找入度为0的点作为起点,将其赋为最小的价值888,然后其所有能到的端点,价值加1,加入队列,删去上一个点,然后循环往复, ...

  6. POJ 2263 Heavy Cargo 多种解法

    好题.这题可以有三种解法:1.Dijkstra   2.优先队列   3.并查集 我这里是优先队列的实现,以后有时间再用另两种方法做做..方法就是每次都选当前节点所连的权值最大的边,然后BFS搜索. ...

  7. UESTC 1227 & POJ 3667 Hotel

    非常细腻的线段树题目啊,后来还是有个细节写错了,查了一个晚上..就不分析了. 代码: #include <iostream> #include <cstdio> #includ ...

  8. Loadrunner:场景运行较长时间后报错:Message id [-17999] was not saved - Auto Log cache is too small to contain the message.

    loadrunner运行时间较长后,跑数据过程老是失败,有如下error: Message id [-17999] was not saved - Auto Log cache is too smal ...

  9. 转: CentOS 6.4安装pip,CentOS安装python包管理安装工具pip的方法

    from: http://www.linuxde.net/2014/05/15576.html CentOS 6.4安装pip,CentOS安装python包管理安装工具pip的方法 2014/05/ ...

  10. CSS padding margin border属性

    主要定义四个区域:内容(content).内边距(padding).边框(border)和外边距(margin) margin:层的边框以外留的空白 background-color:背景颜色 bac ...