系统开发中的坑  
这个是在公司分享的一个ppt,整理下发到博客里,记录下,也是避免忘记了

一.幂等性 
二.数据库 
三.代码默认写法 
四.业务设计

一、幂等性  
概念  
不管调用多少次,都应该 产生一样的效果返回一样的结果

案例:  
1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 
2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱 
3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的 
4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。

技术实现(一)  
查询操作  
查询一次和查询多次,在数据不变的情况下,查询结果是一样的。 
select是天然的幂等操作。

技术实现(二)  
删除操作  
删除操作也是天生幂等的,删除一次和多次删除都是把数据删除。 
(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) 
Select * from table_xxxwhere id=#id;

不抛出异常,删除操作都返回true, 注意Dao层代码写法

技术实现(三)  
唯一索引,防止新增脏数据  
案例: 
支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建资金账户多个,那么给资金账户表中的用户ID加唯一索引,所以一个用户新增成功一个资金账户记录要点:唯一索引或唯一组合索引来防止新增数据存在脏数据(当表存在唯一索引,并发新增报错时,再次调用接口会返回成功结果) 
注意点: 
先查询,用唯一索引来查,后新增,新增控制幂等

技术实现(四)  
token机制,防止页面重复提交  
业务要求:页面的数据只能被点击提交一次 
发生原因:由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交 
解决办法:集群环境:采用token加redis(redis单线程的,处理需要排队)单JVM环境:采用token加redis或token加jvm内存 
处理流程:1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间2. 提交后后台校验token,同时删除token,生成新的token返回 
token特点:要申请,一次有效性,可以限流注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用

技术实现(五)  
悲观锁  
获取数据的时候加锁获取,进行业务操作在提select * from table_xxxwhere id = 'xxx' for update; 
建议使用悲观锁:账户一个人拥有,铜宝账户,积分账户,会员等级账户 
不建议使用:产品份额账户。。。几百个人抢一个份额 
注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用,数据库引擎要用Innodb,支持行锁

技术实现(六)  
乐观锁  
乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。乐观锁的实现方式多种多样可以通过version或者其他状态条件: 
1. 通过版本号实现update table_xxxset name=#name#,version=version+1 where version=#version# 
2. 通过条件限制update table_xxxset avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >= 0 
增加额外表来保证单条记录的幂等,一个用户一个幂等。 
要求:avai_amount-#subAmount# >= 0 ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高注意:乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表,上面两个sql改成下面的两个更好update table_xxxset name=#name#,version=version+1 where id=#id# and version=#version#update table_xxxset avai_amount=avai_amount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0

技术实现(七)  
分布式锁,拿不到conn  
还是拿插入数据的例子,如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)

技术实现(八)  
select + insert  
并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了 
注意:核心高并发流程不要用这种方法,每天只执行几次的任务,建议使用,性能好一点

技术实现(九)  
状态机幂等  
在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。 
注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助

技术实现(十)  
对外提供接口的api如何保证幂等  
如银联提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号source+seq在数据库里面做唯一索引,防止多次付款,(并发时,只能处理一个请求) 
重点:对外提供接口为了支持幂等调用,接口有两个字段必须传,一个是来源source,一个是来源方序列号seq,这个两个字段在提供方系统里面做联合唯一索引,这样当第三方调用时,先在本方系统里面查询一下,是否已经处理过,返回相应处理结果;没有处理过,进行相应处理,返回结果。注意,为了幂等友好,一定要先查询一下,是否处理过该笔业务,不查询直接插入业务系统,会报错,但实际已经处理了。

二、数据库  
数据库设计原则  
字段的命名规范化,简洁易懂,cash—取现,不合理,withdraw合理些 
字段名要有注释,方便后人(不是死了的)查找问题 
主键是选择自增的方式,还是带业务含义的主键,还是一个自增方式主键+ 一个业务含义流水要考虑清楚 
字段长度选择,字符串考虑未来扩展性问题,整形有很多种,int(11)和int(2),在性能上并没有优化 
数据库引擎选择innodb 
是否有幂等性业务需求靠数据库唯一索引来完成,索引设置的合理性 
Decimal的长度选择,保留小数点后6位 
同一个系统中各个表中同样含义的字段,名词要一致hk_detail,,HkDetail 
同一个系统前缀一致,tb_share,tb_income_expense, tbShareId, shareId其他表里面存储的(MBA智库百科,查询金融词汇)

主键的设计  
每个表都应该设置一个ID主键,最好的是一个INT型,并且设置上自动增加的AUTO_INCREMENT标志,这点其实应该作为设计表结构的第一件必然要做的事!! 
个人强烈建议:自增id主键+全局唯一序列号 
100xxxxxx-广东省, 200xxxxxx-黑龙江 
遍历需求的对于自增ID的表来说很容易实现 
主键设计: 
1.自增 
2.15位时间戳+业务标志+rand 32 
3.分布式全局唯一,UUID或额外系统主键生成系统支持

数据库字段长度的优化  
类型 
占用字节 
范围 
tinyint   1    -128~127 
smallint  2    -32768~32767 
mediumint 3    -8388608~8388607) 
int       4    -2147483648~2147483647 
bigint    8    +-9.22*10的18次方

原则: 
不浪费空间, 能用小的数据类型干嘛占用那么多空间 
方便以后扩容 
能用int,不影响业务理解,不用char 
Tinyint(30)------30个字节---10, 000000000000000000010, 
例子 
direction收支方向,就收和支两个值,一定用tinyint(1)

数据库表名的命名  
原则: 
同一个应用都相同前缀,如tbj_aaa,tbj_bbb 
简洁,见名知意

数据库字段的命名  
原则: 
同一个含义的字段各个表中名称一致 
尽量用专业词汇 
简洁,见名知意 
例子 
持仓的专业词汇是position,份额是share,所以份额表示tb_share 
用户份额id,没有用tb_share_id而是用share_id,简洁易懂

设计索引  
原则: 
根据业务需求设计索引 
索引不要过多,影响插入更新性能 
如果有幂等性需求,设置数据库唯一索引 
例子 
如铜板账户,userId设置为唯一索引,一个人只能有一个铜板账户 
收支流水表的userID设置普通索,查询效率高 
Create_time默认加索引。。。。 
A,b,c组合索引,,A**,ABX XXB XXC, a+b+c, 按位加索引

字段类型的选择  
原则: 
整形效率高于字符串,高于datetime 
时间long形式时间建议加 
日期:int20121212,2100000 2010000 
长度过程用text,remark,varchar1024,默认截取,前端,append,/n 
如果表数据量很大,主键用bigint 
例子 
occur_date用整形不用datetime,20121212,查询频繁用整形效率高 
因为每个表未来的数据量都会很大,用bigint

如何避免全表扫描,如何避免误删数据  
原则: 
全表扫描会造成数据库挂掉,OOM 
索引值很少,走索引也会全表扫描 
删数据时,加limit限制和where后必须有条件 
例子 
DAO层面限制不走索引的查询sql 
DAO层面限制索引值少的查询sql 
Delete from tb_positionwhere id=142343 limit 1;

怎么分表?  
深入理解业务,根据业务特性来分表,根据查询需求来分表 
案例: 
1.代金券分表(季度分) 
2.每日收益分表(userId取余) 
3.对账分表(按月分) 
4.微信红包分表(年度+用户分)

分表后怎么查询?  
前端要配合改,尽量不支持后台聚合查询 
案例: 
I.微信红包查询收支明细, 只能按年查询 
II.按月查询 
III.查询历史等

缓存和DB数据一致  

索引字段上进行运算会使索引失效  
尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: 
SELECT * FROM T1 WHERE F1/2=100 应改为: SELECT * FROM T1 WHERE F1=100*2 
禁止如下sql: 
Select * from table_xxxwhere nvl(filed_xx)=xxx;(红色字体不能加函数)

Sql的编写  
一个xml里不要有两个表名,不做关联表查询,因为mysql接不了那么多客 
下面的写法不对,不要给字段加函数 

Sql通用查询的优化  
Sql1: 
select * from coupon where status=1 and use_time>’2016-03-14 00:00:00’ and use_time<’2016-03-15 00:00:00’; 
Sql2: 
select * from coupon where use_time>’2016-03-14 00:00:00’ and use_time<’2016-03-15 00:00:00’and status=1; 
默认前提: 
status,use_time都是索引字段 
由于where后面索引一般生效顺序是从前到后,所以sql1是先走索引status再走use_time,sql2是先走索引use_time,后走status。 
优化手段:先走的索引影响条数越少越好

三、代码默认写法  
如何保证小数点后计算准确性  
1.保留两位有效数字的值,要保留小数点后六位BigDecimal进行计算 
案例: 
非标产品收益 
2. 保留六位有效数字的值,要保留小数点后20位BigDecimal进行计算 
案例: 
铜宝账户

SimpleDateFormat不是线程安全的  
每次要new,不new,原因都查不到

如何避免全表扫描和误删数据—DAO层就禁止掉  

日志是为了查问题,所以怎么记日志?  
用户ID,异常原因这是必须要记录的,其他的业务关键信息也要记录下来 
核心业务流程,请求参数,执行完业务影响数据要记录下来,info日志 
核心业务流程,执行时间要记录下来,info日志 
一个类中每条日志都要是唯一的,不然你怎么知道是那块代码出来的日志 
日志要漂亮,要格式化,打印出来的才漂亮 
案例: 

出问题了可不可以立即关掉,开关?  
核心业务系统要有开关,重大异常时可以随时关掉,,服务降级 
案例: 
交易系统全局开关,新手体验金开关

只用一次的系统,单独开发,独立部署  
一些促销活动和营销活动临时开发,要临时部署,不要影响主业务系统 
案例: 
支付宝5福 
15年春晚微信摇一摇 
activity

经常扩展的常量类用java类不用枚举  
枚举在增加变量,新老版本,序列化,反序列化中不太友好

JOB什么标准?  
支持重复执行,幂等,这是基础 
F(x),F(Y) 是两个幂等操作:所以:f(x) +f(y)也是幂等的 
JOB跑一半断电了,支持重跑修复 
JOB返回结果要有,查询多少数据,处理了多少,失败了多少,成功了多少 
JOB执行时间比较久的,继承AbstractJob来写,支持中断, sorce->trade> 
几个JOB之间应该是互斥关系,可以独立跑,不要搞依赖

代码看着要美丽,漂亮  
不要有黄点提示 
不要用deprecate的方法和类,慢慢改掉 
特别长的方法名,类名不漂亮 
代码块是个方块,一行不要超一屏幕,横着拉代码太难看 
竖着不要超过一屏幕,一个原理 
嵌套不要超过三层,看不懂 
一句话解决的,不要写一堆。啰嗦,多用apache工具类 
代码看着要有结构感觉,不要不换行 
注释要点睛

一个流程多次用到的数据,提前放内存  
一些DB的配置数据,dubbo调用的获取的需要多次使用的数据等 
查询一次,放到内存,多次使用,不用每次用到再去查询

敏感信息,加密  
身份证,姓名,银行卡号,密码等核心数据,存储时要加密存储 
看业务需求,哪些字段还需要加密 
考虑加密算法的性能 
RSA < DES < AES < MD5 
MD5----》签名----》完整性,正确性 
RSA----》加密----》安全性 
加密算法的安全性 
看复杂度选择,一般和性能成反比

去掉过多的if else  
改成键值对配置形式,取配置便于维护,配置的选择看情况 

数据库、应用、前端、含义的一致性  
一个含义的字段,要用一个英文单词,别多个英文单词一个含义,搞死人的

怎么做遍历?  
有自增主键的遍历 
select * from table_xxxwhere status = #status and limit 1000; id > #lastQueryId 
优点:性能高,不漏数据,遍历数据状态变更不会造成位移 
缺点:暂时没发现 
非自增主键遍历 
select * from table_xxxwhere status = #status and id > #lastQueryIdlimit 1000; 
每次取出最后一条ID,进行下一次查询,性能极高,强哥推荐,好片 
是否是带状态更新的遍历: 
会可能存在位移差,存在漏数据 
解决办法: 
1. id>#lastId, limit 100, order没有自增主键 
2. Create_time索引,create_time>=#lastCreateTime, limit 100;支持幂等 
3. 存在新增数据的遍历,做临时表,临时表做业务重复判断。 
4. create_time半开查询create_time>= egtCreateTimeand create_time<ltCreateTime

容错  
异步怎么做? 
同步怎么做,超时时间? 
对方接口的承受能力? 
容错代码是正常代码的2倍以上? 
doPay,,,,超时了,,,但是它成功了。。。。反查。。。。

一眼看的懂。一眼看不懂,一定有问题  
一眼看不懂,怎么维护 
一眼看不懂是流程设计问题还是命名问题,反正是有问题的 
业务领域也是,很清晰,看得懂

四、业务设计  
怎样做重构?  
复杂简单化 
简单标准化 
标准流程化 
流程自动化 
做成一个标准的模式,大家都认为这么做合理,这事就成了 
案例:交易流程,充值流程,做成品牌

根据状态机设计业务  
业务核心点 
业务边界点 
业务对接点 
核心业务状态机

服务升降级  
服务自动升降级 
案例: 
铜板街交易核心汇总,铜宝系统,卡券,可以挂。挂掉不影响交易

java系统开发注意事项相关推荐

  1. 电商 php 颜色数据怎么敲?_来客说电商|电商系统开发注意事项

    来客B2B2C多用户电商系统打造支持自营+招商入驻经营模式的电商平台(类似京东.天猫的经营模式),创新模块化设计整合运营商,供货商,批发商,入驻商,分销商,门店于一体,各个模块可自由拆分组合,可以让商 ...

  2. c java 系统开发_java开发系统内核:使用C语言开发系统应用程序

    更详细的讲解和代码调试演示过程,请参看视频 用java开发C语言编译器 如果你对机器学习感兴趣,请参看一下链接: 机器学习:神经网络导论 我们的操作系统通过增添内核接口导出机制后,已经可以作为平台,运 ...

  3. java 多线程开发注意事项

    多线程开发的三大特性 有序性 可见性 对修改后的数据可以看到拥有可见性 原子性 代码在执行的时候必须一次执行完,一次成功或者是一次失败,一次线程对一段代码有掌控,就像事务里面的原子一样 线程,本地内存 ...

  4. Java安全开发注意事项

    互联网安全架构设计 前言 一.如何防御xss攻击? 二.抓包如何防止篡改数据? 三.对接口实现加密 四.相关安全架构设计方案说明 前言 本文是对Java开发做安全的架构设计. 一.如何防御xss攻击? ...

  5. java springboot VUE 在线学习平台系统开发mysql数据库web结构java编程计算机网页源码maven项目前后端分离

    一.源码特点   springboot VUE 在线学习平台系统是一套完善的完整信息管理类型系统 前后端分离,结合springboot框架和VUE完成本系统,对理解JSP java编程开发语言有帮助系 ...

  6. java建站系统开发教程系列之设计表结构

    java建站系统开发教程系列之设计表结构 根据需求设计表结构如下: SET FOREIGN_KEY_CHECKS=0; -- Table structure for tbl_articles -- - ...

  7. 一套Java架构开发的电商系统要多少钱

    每种类型的电商App系统成本都不一样,不同类型的功能呢不同,直接导致成本的差异.在开发过程中,使用的技术.编程语言不同,同样也会影响价格.比如h5类型的开发速度快,但是功能简单.性能差,成本自然低:如 ...

  8. Java全栈开发---Java ERP系统开发:商业ERP(一)UML建模工具的使用

    一.ERP简介 (一)什么是ERP(企业资源计划) 科普-ERP(企业资源规划)简介 ERP系统是企业资源计划, 由美国 Gartner Group 公司于1990年提出.企业资源计划是 MRP II ...

  9. Java Web 后台中餐饮业报表系统开发实例

    本期葡萄城公开课,我们诚邀石家庄品智技术有限公司,高级软件工程师--刘永政先生,为大家在线分享餐饮业报表系统设计模式,以及在 HTML5 报表浏览器.Java 架构中跨平台使用ActiveReport ...

最新文章

  1. Android源码下载资料
  2. 决策树 python 结果画图_scikit-learn决策树的python实现以及作图
  3. 微信生成带参数的二维码,合成海报,扫码后推送小程序?
  4. java short字段_Java Field setShort()用法及代码示例
  5. win10系统卷影复制服务器,如何使用Windows卷影拷贝服务恢复文件和文件夹
  6. 关于范围for语句的使用
  7. kaldi语音识别实战pdf_FSMN网络结构在语音识别声学模型的实践
  8. easyui控件事件监听委托给jquery事件监听,keyup取最新值问题
  9. 功能至上!国内外最实用的协作类软件盘点
  10. Python科学计算函数库介绍
  11. JAVAweb开发中Ajax教程
  12. 掘金8000亿早教市场,启蒙APP们还面临哪些难题?
  13. 资本家的收割阴谋---空气币FIL“挖矿”庞氏骗局还能坚持多久?
  14. 人生性格、爱情与酒场哲学
  15. 计算机科学内容基础,计算机科学的基础pdf
  16. 南京航空航天大学计算机组成原理,2017年南京航空航天大学计算机科学与技术学院829计算机专业基础之计算机组成原理考研题库...
  17. git diff与linux diff的输出格式之unified format
  18. 第二章 第二课 Scratch作品:一闪一闪亮晶晶(自己画角色)
  19. 洛谷P2036 PERKET
  20. 【练一下1】糖尿病遗传风险检测挑战赛 【讯飞开放平台】

热门文章

  1. 图:邻接矩阵表示法创建无向图并深度优先搜索遍历
  2. 发明专利、实用新型专利——下载步骤
  3. Java编程思想读书笔记——初始化与清理(二)
  4. Linux--解决Windows和Ubuntu之间的复制粘贴问题
  5. Java基本知识——继承与组合
  6. 大众点评CAT开源监控系统剖析
  7. 如何批量下载天堂图片网上多个精美作品并保存一个目录
  8. 从阿里巴巴发行价看A股新股投资机会
  9. 细分市场或成为OA产品同质化的救星|企服三会系列报道
  10. SRC赏金平台汇总介绍