SpringBoot 参数校验组件
一坨一坨的 if/else 参数校验,终于被 SpringBoot 参数校验组件整干净了!数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。 最普通的做法就像下面这样。我们通过 if/else 语句对请求的每一个参数一一校验。 这样的代码,小伙伴们在日常开发中一定不少见,很多开源项目都是这样对请求入参做校验的。 但是,不太建议这样来写,这样的代码明显违背了 单一职责原则。大量的非业务代码混杂在业务代码中,非常难以维护,还会导致业务层代码冗杂! 实际上,我们是可以通过一些简单的手段对上面的代码进行改进的!这也是本文主要要介绍的内容! 废话不多说!下面我会结合自己在项目中的实际使用经验,通过实例程序演示如何在 SpringBoot 程序中优雅地的进行参数验证(普通的 Java 程序同样适用)。 不了解的朋友一定要好好看一下,学完马上就可以实践到项目上去。 并且,本文示例项目使用的是目前最新的 Spring Boot 版本 2.4.5!(截止到 2021-04- ...
Java后端线上问题排查常用命令收藏
作者:xiaolyuh 本文来源:http://r6d.cn/b97q7 内存瓶颈freefree是查看内存使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。 free -h -s 3表示每隔三秒输出一次内存情况,命令如下 123456789101112[1014154@cc69dd4c5-4tdb5 ~]$ free total used free shared buff/cache availableMem: 119623656 43052220 45611364 4313760 30960072 70574408Swap: 0 0 0[1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3 total used free shared buff/cache availableMem: ...
Spring 事务失效的 12 种场景
太坑了!聊聊 Spring 事务失效的 12 种场景前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了。 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据。为了保证操作的原子性(要么同时成功,要么同时失败),避免数据不一致的情况,我们一般都会用到spring事务。 确实,spring事务用起来贼爽,就用一个简单的注解:@Transactional,就能轻松搞定事务。我猜大部分小伙伴也是这样用的,而且一直用一直爽。 但如果你使用不当,它也会坑你于无形。 今天我们就一起聊聊,事务失效的一些场景,说不定你已经中招了。不信,让我们一起看看。 一 事务不生效1.访问权限问题众所周知,java的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。 但如果我们在开发过程中,把有某些事务方法,定义了错误的访问权限,就会导致事务功能出问题,例如: 123456789@Servicepublic class UserService { @Transactional private vo ...
为什么要用消息队列?你项目中是怎么用的
为什么要用消息队列?你项目中是怎么用的?包含原理+BAT案例实践,看完需要5分钟 本文内容预览: 是什么?为什么?1.1 什么是消息队列1.2 为什么要使用消息队列1.3 引入消息队列的带来了哪些问题 怎么样?2.1 支撑七年双11零故障的RocketMQ2.2 快手万亿级kafka集群的平滑扩容2.3 快手/美团对kafka缓存污染的优化2.4 CMQ在微信红包支付场景下的应用 Part1是什么?为什么?1什么是消息队列说到Java中的队列应该都不会陌生。其具有通过先进先出,或者双端进出的方式进行数据管理;通过阻塞以达到自动平衡负载的功能。 消息队列之所以以队列命名,起初也是因为其功能和操作,和java的本地队列有相似之处。所以,我们可以简单的认为消息队列就是为了满足分布式下各服务之间的数据传输、管理和消费的一种中间服务。 2为什么要使用消息队列问:你们的系统中为什么要引入消息队列? 我们总归需要知晓消息队列的使用价值,以及自己的业务场景下的实际痛点才能回答为什么要用消息队列这个问题,才能回答系统引入消息队列的价值所在。 系统间解耦以前几天在后台和关注公号的一个大佬讨论的广告 ...
如何使错误日志更加方便排查问题
作者 | 琴水玉 来源 | https://cnblogs.com/lovesqcc/p/4319594.html 在程序中打错误日志的主要目标是为更好地排查问题和解决问题提供重要线索和指导。但是在实际中打的错误日志内容和格式变化多样,错误提示上可能残缺不全、没有相关背景、不明其义,使得排查解决问题成为非常不方便或者耗时的操作。而实际上,如果编程的时候稍加用心,就会减少排查问题的很多无用功。 在阐述如何编写有效的错误日志之前, 了解错误是怎么产生的, 非常重要。 错误是如何炼成的 对于当前系统来说, 错误的产生由三个地方引入: 1.上层系统引入的非法参数。对于非法参数引入的错误, 可以通过参数校验和前置条件校验来截获错误; 2.与下层系统交互产生的错误。与下层交互产生的错误, 有两种: a.下层系统处理成功了,但是通信出错了, 这样会导致子系统之间的数据不一致; 对于这种情况, 可以采用超时补偿机制,预先将任务记录下来,通过定时任务在后续将数据订正过来。 更好的设计方案 ? b.通信成功了,但是下层处理出错了。 对于这种情况, 需要与下层开发人员沟通, 协调子系统之间的交互; 需要根 ...
如何彻底理解红黑树
作者**:linzworld cnblogs.com/linzworld/p/13720477.html 前言本文主要讲解下最近一直听到的红黑树,看看究竟是什么神仙鬼怪。 二叉树满足以下两个条件的树就是二叉树: 本身是有序树(若将树中每个结点的各子树看成是从左到右有次序的(即不能互换),则称该树为有序树(Ordered Tree)); 树中包含的各个节点的度不能超过 2,即只能是 0、1 或者 2; 简单地理解,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。 二叉查找树要了解红黑树之前,免不了先看下二叉查找树是什么。 维基百科上的定义二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若任意节点的右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值 ...
消息队列中如何保证消息的顺序性
本文选自:advanced-java 作者:yanglbme 问:如何保证消息的顺序性? 面试官心理分析其实这个也是用 MQ 的时候必问的话题,第一看看你了不了解顺序这个事儿?第二看看你有没有办法保证消息是有顺序的?这是生产系统中常见的问题。 面试题剖析我举个例子,我们以前做过一个 mysql binlog 同步的系统,压力还是非常大的,日同步数据要达到上亿,就是说数据从一个 mysql 库原封不动地同步到另一个 mysql 库里面去(mysql -> mysql)。常见的一点在于说比如大数据 team,就需要同步一个 mysql 库过来,对公司的业务系统的数据做各种复杂的操作。 你在 mysql 里增删改一条数据,对应出来了增删改 3 条 binlog 日志,接着这三条 binlog 发送到 MQ 里面,再消费出来依次执行,起码得保证人家是按照顺序来的吧?不然本来是:增加、修改、删除;你楞是换了顺序给执行成删除、修改、增加,不全错了么。 本来这个数据同步过来,应该最后这个数据被删除了;结果你搞错了这个顺序,最后这个数据保留下来了,数据同步就出错了。 先看看顺序会错乱的俩场景 ...
服务端如何防止订单重复支付
服务端如何防止订单重复支付! 作者:废物大师兄 www.cnblogs.com/cjsblog/p/14516909.html 如图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。 这个过程中经常可能遇到的问题是掉单,无论是超时未收到回调通知也好,还是程序自身报错也好,总之由于各种各样的原因,没有如期收到通知并正确的处理后续逻辑等等,都会造成用户支付成功了,但是服务端这边订单状态没更新,这个时候有可能产生投诉,或者用户重复支付。 由于③⑤造成的掉单称之为外部掉单,由④⑥造成的掉单我们称之为内部掉单 为了防止掉单,这里可以这样处理: 1、支付订单增加一个中间状态“支付中”,当同一个订单去支付的时候,先检查有没有状态为“支付中”的支付流水,当然支付(prepay)的时候要加个锁。支付完成以后更新支付流水状态的时候再讲其改成“支付成功”状态。 2、支付中心这边要自己定义一个超时时间(比如: ...
读 MySQL 源码再看 INSERT 加锁流程
读 MySQL 源码再看 INSERT 加锁流程有一个问题,我还是彻底被问蒙了。他的问题是这样的: 加了插入意向锁后,插入数据之前,此时执行了 select…lock in share mode 语句(没有取到待插入的值),然后插入了数据,下一次再执行 select…lock in share mode(不会跟插入意向锁冲突),发现多了一条数据,于是又产生了幻读。会出现这种情况吗? 这个问题初看上去很简单,在 RR 隔离级别下,假设要插入的记录不存在,如果先执行select…lock in share mode 语句,很显然会在记录间隙之间加上 GAP 锁,而 insert 语句首先会对记录加插入意向锁,插入意向锁和 GAP 锁冲突,所以不存在幻读;如果先执行 insert 语句后执行 select…lock in share mode 语句,由于 insert 语句在插入记录之后,会对记录加 X 锁,它会阻止 select…lock in share mode 对记录加 S 锁,所以也不存在幻读。两种情况如下所示: 先执行 INSERT 后执行 SELECT: 先执行 SELEC ...
高并发场景下,到底先更新缓存还是先更新数据库?
高并发场景下,到底先更新缓存还是先更新数据库?1 在大型系统中,为了减少数据库压力通常会引入缓存机制,一旦引入缓存又很容易造成缓存和数据库数据不一致,导致用户看到的是旧数据。 为了减少数据不一致的情况,更新缓存和数据库的机制显得尤为重要,接下来带领大家踩踩坑。 Cache asideCache aside也就是旁路缓存,是比较常用的缓存策略。 (1)读请求常见流程 Cache aside 读请求 应用首先会判断缓存是否有该数据,缓存命中直接返回数据,缓存未命中即缓存穿透到数据库,从数据库查询数据然后回写到缓存中,最后返回数据给客户端。 (2)写请求常见流程 Cache aside 写请求 首先更新数据库,然后从缓存中删除该数据。 看了写请求的图之后,有些同学可能要问了:为什么要删除缓存,直接更新不就行了?这里涉及到几个坑,我们一步一步踩下去。 Cache aside踩坑Cache aside策略如果用错就会遇到深坑,下面我们来逐个踩。 踩坑一:先更新数据库,再更新缓存 如果同时有两个写请求需要更新数据,每个写请求都先更新数据库再更新缓存,在并发场景可能会出现数据不一致的情况。 先更 ...
JVM垃圾回收详解(重点)
如果没有特殊说明,都是针对的是 HotSpot 虚拟机。 本文基于《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》进行总结补充。 常见面试题: 如何判断对象是否死亡(两种方法)。 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。 如何判断一个常量是废弃常量 如何判断一个类是无用的类 垃圾收集有哪些算法,各自的特点? HotSpot 为什么要分为新生代和老年代? 常见的垃圾回收器有哪些? 介绍一下 CMS,G1 收集器。 Minor Gc 和 Full GC 有什么不同呢? 前言当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。 堆空间的基本结构Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收。 Java 堆是垃圾收集器管理的主要区域,因此也被称作 GC 堆(Garbage Collected Heap)。 从垃圾回收的角度来说,由于现在收集器基本都采用分代垃 ...
Java内存区域详解
如果没有特殊说明,都是针对的是 HotSpot 虚拟机。 本文基于《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》进行总结补充。 常见面试题: 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和直接指针两种方式) 前言对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C++程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。 运行时数据区域Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 JDK 1.8 和之前的版本略有不同,我们这里以 JDK 1.7 和 JDK 1.8 这两个版本为例介绍。 JDK 1.7: JDK 1.8: 线程私有的: 程序计数器 虚拟机栈 ...