挨踢部落故事汇(32): Java深坑如何填?

世上本没有坑,踩的人多了也便成了坑。每遇到一次困难,每踩一个坑,对程序员来说都是一笔财富。持续学习是程序员保持竞争力的源泉。本期将分享一个踩坑无数的Java程序猿填坑秘籍。

榆木,一个阅历无数(踩坑)的技术宅男,喜欢了解新技术却不爱太钻研新技术(因为懒,猿届反面角色一枚)。14年毕业至今,在Java开发这条道路上可谓是坑过好些人、也埋过好些坑、也被坑过好些次。因为懒,没有针对他遇到过的问题做过太多的笔记(记录一些棘手问题的解决方法还是个不错的习惯),只是习惯性的去分析为什么出现这样的问题,我们该怎么去避免重复出现。在这里榆木share一下第一次做独立需求的过程。

榆木·Java开发工程师

要成为一个合格的Java程序猿,独立完成需求是一个必须经历的阶段,在这个过程中可能会遇到很多问题,要学会合理的利用资源(官方文档、社区论坛等)去解决问题。在这个阶段应该是踩坑最多、收获最多、成长最快的阶段。

在榆木入职的前3个月里,做的都是一些改bug、完善需求的活,他不需要太多思考,根据客户说的做就成了。三个月之后他的公司顺利拿下了该客户的二期项目,由于人手不够,再加上他在一期维护的时候对业务比较熟悉,老大便让榆木独自承担该项目前置子系统的全部需求。刚开始的时候榆木是很激动的,随之而来的却是不知所措。

榆木都是如何踩坑又填坑的呢?分享一下他的几点经验,希望对开发者有所帮助。

如何同时开启两个SVN服务

因为公司资源不够,老大就要求在原有的服务器上再弄一个SVN服务,于是他开始各种捣腾,可是不管怎么样就是没有办法同时起来两个服务。怎么办,只能找哥哥(google)帮忙咯,因为SVN服务的启动(/etc/init.d/svnserve start )是包含一些默认参数,如 --listen-port指定服务端口 默认是3691,如果要同时起两个SVN服务只需要在启动时指定两个不同的listen-port就OK了。

如下,问题解决:

/etc/init.d/svnserve start   -d -r /svn/repo  第一次第一个库启动  默认3691 /etc/init.d/svnserve --listen-port 9999 -d -r /svn/svndata  第二次指定端口启动

问题搞定,紧接着就是紧张的代码开发,事情有点想不到的顺利,后端接口顺利完工通过测试,榆木开始和前端对接联调,好激动,搞不好可以提前完成任务了。噼里啪啦的搞完就开始测试了。

fastJson序列化问题

所谓没有遇到过bug的程序猿就不是正常的程序猿,一点都不意外,问题来了。同一个对象赋值给HashMap中不同的key 传到前端后,第二个value竟然不能被正常解析....... 他自己写的代码必须不能怂,有问题那就解决问题,于是榆木开始找问题所在,开始模拟数据,发现返回结果如下:

{"o1":{"age":16,"name":"o1"},"2":{"$ref":"$.o1"}}

很容易就能看出来,第二value在这个返回结果中用类似指针的方法("$ref":"$.o1")表示它和“o1”的值一样,看起来像是同一个对象的循环引用哦,那是不是可以把这个循环引用禁止呢?答案是可以的。(有必要说明一下,这里使用的是fastJson)通过SerializerFeature指定禁用循环依赖就可以了。修改前代码如下:

public static void test1() {         TestObject object = new TestObject("o1", 16);         Map<String, TestObject> map = new HashMap<String, TestObject>();         map.put("o1", object);         map.put("o2", object);         System.out.println(new String(JSON.toJSONBytes(map)));     }

输出结果:{"o1":{"age":16,"name":"o1"},"o2":{"$ref":"$.o1"}}

在一个集合对象中存在多条相同数据时,将ist集合对象转化为json对象输出到前台时,JSON默认对第二条数据处理时用"$ref":"$.object".<这里object指第一条数据>,这样的json转化结果输出到前台肯定是不可以使用的,好在JSON有提供禁止关闭引用循环检测的方法,只需要在转化的时候加上SerializerFeature.DisableCircularReferenceDetect  就可以解决了。修改后代码如下:

public static void test1() {        TestObject object = new TestObject("s1", 16);        Map<String, TestObject> map = new HashMap<String, TestObject>();        map.put("o1", object);        map.put("o2", object);        SerializerFeature feature = SerializerFeature.DisableCircularReferenceDetect;        System.out.println(new String(JSON.toJSONBytes(map, feature)));    }

输出结果如下:{"o1":{"age":16,"name":"o1"},"o2":{"age":16,"name":"o1"}}

到这里问题就解决了。不久之后测试通过了,交付客户测试版本,开始和中心联调测试了。

OOM异常处理

榆木以为到这里就万事大吉了,然而是不可能的。联调测试两天之后,客户反馈说:“我们的XXX报文数据已经往中心发过了呀,可是中心说他们没有收到,你们查下是什么问题呗!”客户就是上帝呀,榆木和他的同事开始查询日志,发现有一些OOM的异常。异常产生的场景是在取数据-组报文-MQ转发这个环节,然后就开始一个一个点的排查了。

榆木首先想到的可能原因有:

1、数据取出来生成报文这个过程都是在内存中做的,会不会是这里数据太多导致?

2、会不会是报文生成过程产生了过多Object没有来得及回收?

3、会不会是数据发送慢于报文生成的速到导致等待队列爆满?

然后开始针对性的做修改测试,他将一次性取数据生成报文的过程改成批量去做,然后测试运行一段时间没有问题(排除 1);在生成保温过程中,将每一个转化后的对象置为空Object=null,以便及时回收,测试运行一段时间没有问题(排除2);在第三点上面,他最先想的是增加线程数量( 服务器开启超线程、应用中增加线程数量)去提升处理速率,运行一段时间之后还是会出现OOM。怎么办呢?再次回到了等待队列上面来,能不能在一定程度上对等待队列做个限制呢?于是榆木在每次从MQ取消息之前增加了对等待队列的深度的判断,如果深度大于最大线程数量的2倍,就放弃本次MQ队列消息的处理。然后继续测试,问题没有再出现。

查询慢怎么办?

最终项目上线了,终于可以松一口气了。可是有一天,榆木的老大说客户反映部分查询很慢,让他去处理一下。榆木心里想着,这个应该是个小问题,给数据表加索引就能搞定。到了客户现场之后发现,原来的表是有索引的,可查询还是慢,不得已只能去找原因了。不得不说,explain SQL是个不错的命令,发现索引没有生效,经过仔细的比对,发现该关联查询的关联字段在两个表中都有索引, 两个表的字符集都是UTF8,但是排序规则一个是utf-bin(二进制存储数据,大小写区分),一个是utf8_general_ci(大小写不敏感),所以把数据排序规则改成一致索引生效,查询速度也就上来了。

PS: mysql中的UTF-8编码的排序规则说明

utf8_bin将字符串中的每一个字符用二进制数据存储,区分大小写。

utf8_genera_ci不区分大小写,ci为case insensitive的缩写,即大小写不敏感。

utf8_general_cs区分大小写,cs为case sensitive的缩写,即大小写敏感。

【写在最后】

榆木整理了下这些年踩的坑,给自己也给正在和他挣扎在挨踢坑里的小伙伴们一些启发与鼓励。持续学习是保持竞争力的前提;夯实的基础是进阶的垫脚石。抬头走不独行(exchange)、埋头干(code),就算被称作屌丝,也还是要有梦想,万一逆袭了呢。

 如果你也愿意分享你的故事,请加51CTO开发者QQ交流群 114915964联系群主小官,期待你精彩的故事!

时间: 2024-10-13 16:13:55

挨踢部落故事汇(32): Java深坑如何填?的相关文章

挨踢部落故事汇(4):程序猿的跳槽感悟

互联网是一个变化快,人员流动频繁的行业,程序猿的选择很重要,毕竟每个人的职业生涯大概有三十多年,一念之差可能就轻易毁掉 1/10.对于程序猿来说,每一次改变要深思熟虑,如果在当前的团队2年内没有找到自己的机会,也不要垂头丧气,深呼吸,继续寻找新契机. 反省不是去后悔,而是为前进铺路.哈韩浪子是一个涉世未深的程序猿,一个保持stay simply,sometimes naive的专心码农. 哈韩浪子·Java开发 用历史的眼光站在未来看现在 平日里的哈韩浪子是个爱读书的呆萌90后,在书的海洋里,他

挨踢部落故事汇(3):入行IT自学成才

临河而羡鱼,不如归家织网.授人以鱼,不如授之以渔.不忘初心,方得始终. 研究生期间参与的企业项目坚定了益达进入IT行业的决心.那份执着与看待问题的思维,使他在开发路上愈战愈勇.在益达看来,处理问题的思维就相当于一个软技能,是学会了就不会跑掉的东西.问题的本质.触类旁通.借鉴思想,严谨性这些都是他的思维要素.遇到问题多思考,多问what,why,有耐心,不急躁,多沟通,层层排查最终找解决办法. 益达·大数据开发 学生时代脱颖而出 益达高考选择的是电子信息科学与技术专业,计算机学习占比居多.他从几乎

挨踢部落故事汇(9):女程序媛的开发梦

认真对待每一天.勇敢迈出第一步,改变就在不远处. 小包是个率真爽朗的女程序媛,从不搽脂抹粉的她,工作起来,是可以抛去一切形象的,散乱的头发,苦逼加班的黑眼圈,俨然一个男程序猿形象.但她的骨子里却散发着永不服输的气质.不加班的时候她喜欢宅在家里看书,或者和朋友出去旅游. 小包·Android开发 专业实训改变命运 小包的程序嫒之路说起来还挺有意思的,高考填志愿的时候因为目标大学不能选择其他专业,于是大学她就学的软件开发专业,大三时学校安排她到一家培训机构进行为期两个月的专业实训.这次的实训也算是小

挨踢部落故事汇(5):扩展新IT领域,用代码改变世界

思想驱动未来!"写一个程序,就像是在创造一个东西,我猜每个程序猿都有一颗改变世界的心."--by疯狂学校 本期主人公疯狂学校是个既懂前端又会后台,上的了厅堂下的了厨房的杂食程序员.大学期间他学的是软件工程专业,对于一个基本没怎么接触电脑的他来说,这无疑是一个挑战. 疯狂学校·Java开发 热衷开发,从C#到Java,从前端到后台,无一不通 由于对电脑基础比较差,刚开学时疯狂学校一有空就去机房练打字,这样坚持了两个月,感觉才慢慢追上了同学的水平.在这个过程中他感觉到从量变到质变,感受到自

挨踢部落故事汇(12):习惯成就技能提升

作为一个普通的芸芸大众,资深宅男,码农,狂爵的生活除了工作之外,还喜欢看书,听歌,静坐.对政府项目深有研究,目前是CMS核心开发团队成员,普通程序员组长.狂爵13年毕业后就开始从事Java CMS产品开发,目前所在公司是航天集团下属单位,开发的项目都是政府项目.他参与开发过国家某保密单位内网(三级等宝,信息迁移,数据摆渡,信息密级权限),国家电网内网升级改造,中工网系统WebLogic集群升级,水利部(财务门户.水资源监控应用门户.单点登录系统.信息门户),国防科工局内部福利系统(伪电商)项目及

挨踢部落故事汇(16):技术人疲倦期的最佳实践

Coeus喜欢和朋友聊技术.怼产品.鄙销售.谈梦想.借着兴致与大家分享这几年遇到坑,经历的疲倦期和技术瓶颈,希望对大家有一定帮助. Coeus·新浪安徽站PHP主管 Coeus工作六年有余,一直从事PHP相关的Web开发工作.前端.服务器运维也做过,私活.技术顾问.个人规划的项目也接触做过.曾在小公司打过杂,也在外企熬过夜,目前在国内一家老牌互联网地方站做技术主管.这六年的工作期间Coeus踩过很多坑,做出了很多选择,很幸运的每一次都挺了过来.秘籍很简单:不能则学,不知则问,耻于问人,决无长进.

挨踢部落故事汇(13):扬长避短入行Oracle开发

"他人笑我太疯癫,我笑他人是怎么看出来的呢?"一个被数据库耽误的段子手的座右铭竟是酱紫风趣幽默.在介绍胖子职业之前,先认识他这个人,也许你不会相信胖子是个程序猿,而且还是个头脑冷静,思想沉着数据库工程师.胖子平时的爱好是激烈对抗的蓝足球,喜欢徒步旅行,喜欢脱口秀讲段子,喜欢编剧拍视频.这样外向的人和程序猿攻城狮的标签几乎没有半点联系. 胖子·Oracle数据库开发 扬长避短,结缘Oracle开发 如果不是大学选择了软件工程专业(这个在胖子大学之前,什么也不知道的专业),也许他现在会像池

挨踢部落故事汇(14):分享助力运维能力的提升

本期主人公大师兄,人称翔神,目前就职于某知名商城架构部Linux运维工程师一职,熟悉高并发,负载均衡,Redis集群高可用,运维开发等,喜欢和同道中人分享运维那些事儿. 大师兄·Linux运维工程师 转眼间,大师兄毕业已经三年多了,从IT界的小白到Linux运维大神,他也算拥有一技之长,坚持投资自己的大脑,是他最骄傲的事.从C语言,到Linux运维,到Python的运维开发,再到Java,一路不断学习,挑战自我,内心感慨,特写成文章分享,和开发者们共勉. 踏足IT,时刻在分享 虽然大师兄是计算机

挨踢部落故事汇(17):我与永恒之蓝战斗的两天两夜

redhat9i是个80后网络工程师,跟大多数IT男一样,喜欢倒腾,他的兴趣爱好非常广泛,无线电通信.应急救援.吹笛子.中医理疗.摄影等等. redhat9i·网络工程师 相识51CTO redhat9i主要活跃在51CTO论坛上,喜欢在论坛上和大家探讨问题.交流经验,认识了不少同行,帮他解决了很多问题,使得redhat9i技术能力得到很大进步,在当时的大区他也算能指导其他代理商工作的人了.自此就扎根在51CTO论坛上了,从版块版主做到现在的超级版主,每天登录论坛已经成为redhat9i的一种习