【.com原稿】世上本无陷阱,踩的人多了,就会成为陷阱。每一次遇到困难,每一次踩坑,对于程序员来说都是一笔财富。持续学习是程序员竞争力的源泉。本期为踩过无数坑的Java程序员分享一本秘籍。Yumu,一个经历无数(踩坑)的技术书呆子,喜欢了解新技术但不喜欢对新技术过多钻研(因为懒惰,他是猿猴世界的反派)。2014年毕业以来,在Java开发的道路上,可以说是坑过很多人,埋过很多坑,坑过很多次。由于懒惰,我对他遇到的问题并没有做太多的笔记(记录一些疑难问题的解决方案是个好习惯),只是习惯性地分析为什么会出现这样的问题,我们如何才能避免重复出现。这里elm分享一下第一次做独立需求的过程。宇木·Java开发工程师成为一名合格的Java程序员,是独立完成要求的必经阶段。在这个过程中,你可能会遇到很多问题,一定要学会合理利用资源(官方文档、社区论坛等)来解决问题。这个阶段应该是坑最多、收获最多、成长最快的阶段。在Yumu入职的头三个月里,他所做的只是修复错误和改进需求。他不用想太多,按照客户说的去做。三个月后,他的公司成功拿下了客户的二期工程。由于一期维护人手不足,加上自己对业务不熟悉,老板让鱼木单独承担项目的前端子系统。所有需要。一开始,玉木还很兴奋,后来就不知所措了。榆树如何踩坑填坑?分享自己的一些经验,希望对开发者有所帮助。如何同时启动两个SVN服务因为公司资源不够,老板要求在原来的服务器上再创建一个SVN服务,于是开始百般刁难,但无论如何也没有办法同时启动两个服务。怎么办,只能求助大哥(google)了,因为SVN服务的启动(/etc/init.d/svnservestart)里面有一些默认参数,比如--listen-port指定了默认服务端口为3691,如果你想同时启动两个SVN服务,只需要在启动时指定两个不同的listen-port即可。如下,问题解决:/etc/init.d/svnservestart-d-r/svn/repo***firstlibrarystartsdefault3691/etc/init.d/svnserve--listen-port9999-d-r/svn/svndata解决了第二次启动指定端口的问题,紧接着就是紧锣密鼓的代码开发。事情进行的有点出乎意料的顺利。后台接口顺利完成,通过测试。Yumu开始和前端进行连接调试。我太兴奋了,也许我可以提前完成任务了。噼里啪啦之后,测试开始了。fastJson序列化问题所谓没遇到过bug的程序员不是正常的程序员。一点也不奇怪,问题来了。在HashMap中,同一个对象被分配给不同的键。发送到前端后,第二个值无法正常解析。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。”有问题就解决问题,于是Yumu开始查找问题,开始模拟数据,发现返回的结果如下:{"o1":{"age":16,"name":"o1"},"2":{"$ref":"$.o1"}}很容易看出第二个值使用了类似指针的方法("$ref":"$.o1")在这个返回结果中表明它与“o1”的值相同,这看起来像是同一个对象的循环引用,是否可以禁止这种循环引用?答案是肯定的。(需要说明的是这里使用了fastJson)通过SerializerFeature指定禁止循环依赖即可。修改前的代码如下:publicstaticvoidtest1(){TestObjectobject=newTestObject("o1",16);Mapmap=newHashMap();map.put("o1",object);地图。put("o2",object);System.out.println(newString(JSON.toJSONBytes(map)));}输出结果:{"o1":{"age":16,"name":"o1"},"o2":{"$ref":"$.o1"}}当一个集合对象中有多条相同的数据时,当ist集合对象转成json对象输出到前台时,JSON默认对第二条数据处理时,使用"$ref":"$.object"。<这里的object指的是第一条数据>,这样的json转换结果输出到前台一定不能用。好在JSON提供了禁止关闭引用循环检测的方法,在转换时加入SerializerFeature.DisableCircularReferenceDetect即可解决。修改后的代码如下:publicstaticvoidtest1(){TestObjectobject=newTestObject("s1",16);Mapmap=newHashMap();map.put("o1",object);地图。put("o2",object);SerializerFeaturefeature=SerializerFeature.DisableCircularReferenceDetect;System.out.println(newString(JSON.toJSONBytes(map,feature)));}输出结果如下:{"o1":{"age":16,"name":"o1"},"o2":{"age":16,"name":"o1"}}到这里问题就解决了。测试通过后不久,客户测试版交付,开始与中心的联调测试。OOM异常处理Yumu以为到这里就万事大吉了,其实不可能。联调测试两天后,客户反映:“我们的XXX报文数据已经发给中心了,但是中心说没有收到,你看看是什么问题!”客户就是上帝,何雨沐和同事开始查看日志,发现了一些OOM异常。出现异常的场景在数据获取-组消息-MQ转发的环节,然后开始一一排查。Yumu首先想到的可能原因是:1、提取数据生成消息的过程全部在内存中完成。会不会是这里数据太多导致的?2、会不会是消息生成过程中生成了太多对象,没有及时回收?3.会不会是数据传输速度比消息生成速度慢导致等待队列满了?然后他开始做有针对性的修改测试。他把一次性取数据的流程改成批量生成消息,然后测试跑了一段时间没有问题(不包括1);在产生保温的过程中,每次转换后的对象都设置为空Object=null,以便及时回收。运行测试一段时间没有问题(不包括2);第三点,他最想要的是增加线程数(服务器开启超线程,应用程序线程数增加)来提高处理速度,运行一段时间后还是会出现OOM.怎么做?再回到等待队列,能不能对等待队列进行一定的限制?所以Yumu在每次从MQ取消息之前,都增加了对等待队列深度的判断。如果深度大于***线程数的两倍,则放弃对该MQ队列消息的处理。然后继续测试,问题没有再出现。查询慢了怎么办?终于项目上线了,我终于可以松一口气了。可有一天,玉木的老板说客户反映部门查询很慢,要他处理。雨木心想,这应该是个小问题,给数据表加个索引就可以解决了。到了客户现场后,发现原来的表已经建立了索引,但是查询还是很慢,只好查找原因。不得不说explainSQL是一个很好的命令。我发现索引没有生效。仔细对比后发现,关联查询的关联字段在两个表中都有索引。两个表的字符集都是UTF8,但是排序规则一个是utf-bin(二进制存储数据,区分大小写),一个是utf8_general_ci(不区分大小写),所以把数据排序规则改成一致的索引就会生效,查询速度也会提高。PS:mysql中UTF-8编码的排序规则表明utf8_bin将字符串中的每个字符存储为二进制数据,区分大小写。utf8_genera_ci不区分大小写,ci是caseinsensitive的缩写,即不区分大小写。utf8_general_cs是区分大小写的,cs是casesensitive的缩写,即区分大小写。【写在***】雨木梳理了自己这些年踩过的坑,给自己和和自己一起奋斗的小伙伴们一些启发和鼓励。持续学习是保持竞争力的前提;坚实的基础是前进的垫脚石。昂首挺胸,独行(交流),努力(代码),就算被骂屌丝,也要有梦想,以防被逆袭。如果你也愿意分享你的故事,欢迎加入开发者QQ交流群114915964联系群主小关,期待你的精彩故事!【原创稿件,合作网站转载请注明原作者和出处为.com】