文章列表

从技术谈到管理,把系统优化的技术用到企业管理

作者:ailin888

很多技术人员在职业上对自己要求高,工作勤奋,承担越来越大的责任,最终得到信任,被提拔到管理岗位。但是往往缺乏专业的管理知识,在工作中不能从整体范围优化工作流程,仍然是“个人贡献者”的工作方式,遇到问题自己上,经常耽误了本职工作。于是翻了很多书,看了很多文章,学习了很多“为人处世的艺术”和“企业发展的战略”,最终把自己干成了研发部主管,技术却逐渐荒废。管理工作是什么呢,技术和管理是截然不同的两条发展方向吗? 不是的。技术和管理都要做到量化分析,全局优化,存在很多相似的方法。这里用一个系统性能优化的场景举个例子,大家可以体会一下: 公司里有一个程序,运行在10台服务器的集群上。现在业务量增加了,请求处理不完。老板把你找来,要你优化这个程序。接到这个头疼的任务,你把开发测试运维各个部门的人都找来开会想办法,有人说数据库该升级了,有人说代码写的太烂要优化,有人说机器太少再加5台,还有人说我们要改架构上云,上了云以后就再也没有这种问题了。你该听谁的呢? 先别着急动手。有一句话叫做“没有度量就没有优化”,首先要“度量”这个现象。先把设计人员找来,了解一下这个程序是什么功能,工作流程是什么样的。 程序架构:这个程序处理图片识别的业务,从网络端口接收图片,识别图片里面的信息,然后在图片库里进行对比,最后输出相似图片。处理过程是这样的: 搞清楚程序架构,接下来我们需要度量数据。有一些数据很容易得到,还有一些数据似乎没人搞得清。于是你给研发团队布置了一个任务,让他们在程序里面埋点,尽快收集一些数据指标。开发人员改了一版程序,部署上去。在生产线上跑了一天,得到一些数据指标: 输入:每天需要处理100万张图片,这是从上游工序收集到的 识别函数:识别1张图片平均时间是0.5秒 比对函数:比对1个图片的平均时间是0.4秒 现在我们计算一下:处理1张图片的时间是0.9秒(0.5 + 0.4),1台机器1天可以处理图片96000(86400 / 0.9),10 台机器1天可以处理图片96万(96000 * 10),达不到100万。要完成每天100万的处理量,需要服务器10.4台(100万 / 96000),约等于11台。 是不是告诉老板必须要买服务器了呢:“需要买1台服务器,带GPU的!”。先别着急。 我们分析一下程序运行过程:识别函数和比对函数是串行执行的。识别函数忙碌的时候,比对函数是空闲的,它在等待识别的结果。同样的,比对函数忙碌的时候,识别函数也是无事可做的。也就是说,服务器的资源并没有得到充分利用,GPU卡和数据库的资源都有很大的浪费。 怎样提高资源利用率呢?可以改变一下程序的架构,调整成下面这样: 把原来的程序一分为二,分别部署在两台服务器上,中间用一个消息队列交换数据。现在两个程序都可以充分利用服务器的资源。我们再来计算一下吞吐量: 程序X:处理一个图片需要0.5秒,1台服务器1天处理图片172800(86400 / 0.5),100万图片需要服务器 5.8 台(100万 / 172800),约等于6台。 程序Y:处理一个图片需要0.4秒,1台服务器1天处理图片216000(86400 / 0.4),100万图片需要服务器 4.6台(100万 / 216000),约等于5台。 仍然需要服务器11台,好像没有什么改进嘛。我们再分析一下:原方案需要11台带GPU的服务器,现在只需要6台,我们省下了5块GPU卡,这已经是一笔不少的费用。 架构师又提供了一个信息:在原方案里面,识别函数和比对函数串行执行,所以只能用同样的并发线程数执行。新方案已经分离到两个程序中,所以比对函数就可以设置更高的并发线程数,可以提高到原来的4倍。 这是一个好消息,程序Y的吞吐量可以提高4倍,这样一来,只需要1.16台服务器就可以处理完100万数据,约等于2台。 按照改进后的架构,只需要6台带GPU的服务器,再加2台不带GPU的服务器,总计需要8台服务器。不仅可以完成处理任务,还可以预留一些GPU卡,以备以后业务发展。 例子说完了,以上就是优化一个IT系统运行效率的过程。其实,企业管理也是相似的过程,只是优化的对象不再是机器和程序,而是人的活动。在一家软件企业,有需求收集、产品研发、项目实施等多个流程,有时这些流程会有卡顿、缓慢的现象,看上去和一个IT系统的问题是一样的。有一个著名的问题是:“在你的团队里,只涉及一行代码的变更需要多久才能上线?” 从需求到交付,这个路程有多远。我们可能经常会遇到这样的问题:某个现场运维反馈了一个缺陷,看上去只是很小的问题,修复也不麻烦,却花了很长时间才解决。事后回顾这个问题,每个部门的人都有话要说: 运维:我一发现这个问题,就在Jira平台上提出来了,当时开发也没有回复,我就下班了。 开发:我当时正在开发新版本的功能,写一段很复杂的代码。看到这个问题的时候,已经是下班时间了。运维只描述了问题现象,没有说明现场部署的版本。我不知道在哪个版本上修复这个问题,只好在最新的发布版上先把它改掉了,然后把包发给测试。我在Jira上也回了消息,要求运维把现场版本号发出来; 测试:我收到开发的包,打算做一下测试。整个集成环境已经升级了,我需要把测试环境恢复到老的版本。这事我搞了一上午,下午的时候搞了一遍测试,发现几个缺陷,把问题提给开发了。 开发:我收到测试提的Bug,修改以后又发了一个版。这次应该没问题了。 运维:环境上的包没有版本标识,我花了很长时间核对所有版本的Md5码,才找到了版本号,在Jira上回了。这个问题很紧急,我想尽快解决,于是就拿测试给我的最新版,想尝试安装一下。我不知道这个包能不能兼容现场的环境,只能试试看。我在预发布环境上搞了一天,也没把他装上去,看起来是不行的。 开发:我看到现场版本号,这是一个非常老的版本,已经一年多了。我进入这个项目才三个月,在微信上AT了好几个人。代码基线也不知道在哪里,找了很久才找到。修复之后已经很晚了。还是要交给测试测一下。 测试:集成环境还是要恢复一下,我搞了三个小时。测试确认没有问题,就交给运维了。 运维:我收到安装包,在预发布环境上试了一下,没什么问题。生产环境要麻烦一些,我一开始只更新了一个节点,发现问题仍然间歇性的出现。后来才知道要还有2个节点也要部署。这次搞了一天,下次再有这样的情况,我就知道怎么做了。 从每个人的角度看,自己都很忙碌,花了很多时间解决问题。但是从缺陷解决的角度看,事情在不断的卡顿、等待。在这些劳动过程中,真正有效的、能产生价值的劳动占多少呢?这就是DevOps需要解决的价值流动问题,需要建立一套体系,衡量这个流程,不断优化它。

C语言与JAVA

作者:ailin888

java从根本上说是c之后的一种改进语言,纯面向对象的一种编程语言(当然比起Ruby还是差一点),有了C语言的基础固然对学习java有帮助,因为在某种程度上java语言和C语言是比较接近的。但是如果没有学习过C语言也完全没有问题,这两者并不存在依赖关系,直接学习java语言是完全可以的。我本然便是如此。 楼主如果没有任何基础,我推荐您选择一本叫做java学习笔记的书,林信良编著的,对于初学者应该是不错的选择,能够认真看完这本书的内容,通过SCJP考试应该不是问题了! 另外,我也收集了一些java和C的不同点供楼主参考: 1. Java没有预处理指令。(如C中的#define , #include , #ifdef等)。C中的常量定义在Java中用static final来取代。 2. Java中没有C中的全局变量。 3. Java中的主类型的size是确定的,而C中主类型的size跟平台相关。 4. Java中没有了指针,它使用了类似的句柄来取代指针,但是Java中不允许对句柄进行加减,没有取地址操作符之类的东东。 5. Java有垃圾收集机制,不需要自己释放空间。 6. Java没有goto语句。Java在C提供的控制语句基础上增加了异常处理和标签break和continue语句。这些可以替代goto的作用。 7. C要求一个方法或块中使用的所有局部变量的定义在该方法或块的最开始处定义,而Java允许这些定义在方法或块的任意地方出现。 8. Java不要求在调用一个函数以前已经定义了该函数,可以在调用点后面定义。而C有这个要求。 9. Java不支持C中的strut 和 union类型。Java支持方法重载。 10. Java不支持C中的enum关键字。 11. Java不支持C中的bitfields能力。 12. Java不支持C的typedef。 13. Java不支持C的方法指针。 14. Java不支持C的可变参数表。 希望您满意!

C语言中文网推出辅导班啦

作者:ailin888

ava语言最早由Sun Microsystems公司研发,由James Gosling发起并于1995年作为Sun Microsystems公司Java平台的核心组件面世(亦即Java 1.0[J2SE])。 截止目前(2013年6月),Java已更新至Java 1.7。随着Java的不断发展,Java变得越来越流行,为了适应不同平台的需求,Java也出现了多种配置,例如,J2EE用来开发企业级应用,而J2ME则用来开发手机应用。 后来,Sun Microsystems公司将各个J2版本重新命名为Java SE、Java EE、和Java ME,以达到Java“一次编写,到处运行”的目的。 Java的特征 面向对象:Java是一种面向对象语言,对于Java来说,一切皆是对象。由于Java基于对象模型,所以可以很容易实现对Java的扩展。 平台无关性:Java语言的设计不针对某种具体平台结构,这点不像C/C++等编程语言,在编译时,是将Java程序编译成与具体体系结构无关的字节码。字节码可以发布在互联网上并且由Java虚拟机(JVM)解释执行。 简单性:Java是一种简单易学的语言。你如果理解了Java面向对象的基本概念,学习Java将更加轻松。 安全性:Java的安全特性确保Java可以用来开发无病毒、难篡改的系统。Java的认证技术是基于公钥加密的。 体系结构中立:Java编译器生成与平台无关的目标文件,这种目标文件可以在任何存在Java运行时系统的处理机下运行。 可移植性:Java语言与平台无关,Java语言规范中也没有规定任何与具体实现相关的内容,这使得Java具有可移植性。编译器和Java依据POSIX方便移植的限制,用ANSI C语言写成。 健壮性:Java主要通过在编译期以及运行时的错误检查,来尽可能排除未知的错误。 多线程:Java支持多线程编程,使用Java可以编写同时执行多个任务的程序。这种特征使得开发者可以构建稳定的交互式应用程序。 解释运行:Java字节码在运行时被转换为本机代码,并且不在任何地方存储。由于链接过程是一个渐进的、轻量级的过程,所以开发更迅速且更易于分析。 高性能:即时编译技术使得Java具有高性能特性 分布式:Java可以应用于分布式的互联网环境中。 动态性:Java是一种比C/C++更具有动态特性的语言,它可以适应不断变化的环境。Java程序可以携带大量的运行时信息,这些信息用来验证和解析运行时对象。 Java的历史 James Gosling 于1991发起Java语言计划,当时是为了开发他的机顶盒工程。那时Gosling的办公室外面有一棵橡树,所以这种语言被称为Oak(橡树),后来还被称为Green,最终从一些随机单词中抽到了Java,就改名为Java。 Sun最早于1995年发布了Java 1.0,它具有一次编写,到处运行的特点,运行在主流平台上性能很好。 2006年11月13日,Sun公司根据GPL(General Public License)条款发布了很多Java的自由开放软件资源。 2007年5月8日,Sun公司将Java的所有核心代码自由开源,除了少部分Sun公司没有版权的代码。 需要的工具 为了测试本站提供的示例代码,你需要以下软件: Java JDK 文本编辑器(windows自带的notepad或者其他文本编辑器) 该教程将教你如何使用Java编写GUI程序、网络程序和Web应用程序的技术。 下一节要讲的内容: 下一节将告诉你怎样获取Java以及Java文档,并指导你如何搭建Java开发环境。

专栏涵盖的知识点比较全面,共分为九大模块。

作者:ailin888

专栏涵盖的知识点比较全面,共分为九大模块。 1. 为什么学习 Java 并发编程 我们在工作中会遇到各种多线程带来的并发问题,其中多线程涉及到操作系统、CPU、内存等多方面的知识,所以要理解并发编程原理,运用好并发编程,能帮我们在实现并发编程时有更多的解决方案和选择。 2. 并发理论基础 本模块将从操作系统层面讲解线程安全问题是如何产生的,在多线程编程的过程中,支撑我们解决线程安全问题的理论基础是什么。本模块是该专栏的基础,对后续模块的学习有很大帮助,同时也会刷新大家对并发世界的重新认识。 3. Java 的线程状态流转 一个线程在它的生命周期内从创建到销毁都经历了哪几种状态,状态之间是如何流转的,不同状态下有什么表现;线程如何终止和中断;守护线程与普通线程有什么区别;线程间如何进行通信的,wait/signal 机制是什么;上述问题在本模块都会得到解答。 4. Java 的 Atomic 类用在什么场景 Atomic 类在 Java 中是非常常用的类,本模块会讲解这些不同的 Atomic 类,包括 AtomicInteger,AtomicBoolean,AtomicLong,AtomicReference,Atomic*FieldUpdater 分别用在什么场景,以及如何通过 CAS 操作实现无锁化操作。通过本模块的学习,会进一步加深对 CAS 的认识。 5. Java 的锁的运行原理是什么 讲解 Lock 锁与原生 Synchronized 锁的区别,以及锁的底层实现 AQS。AQS 是整个并发包的核心,理解了 AQS 的原理就了解了锁机制的实现,结合常见的锁冲入锁和读写锁,来讲解这两种锁的使用场景和具体实现。 6. Java 中有哪些并发安全容器 讲述线程安全的 List-CopyOnWriteArrayList,线程安全的 Set-CopyOnWriteSet,线程安全的 Map-ConcurrentHashMap,分为 jdk1.7 和 jdk1.8 两个实现版本,并且阐述 HashMap 在多线程中如何出现死循环的。 本模块还会对常见的队列进行讲解,包括阻塞队列 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、LinkedTransferBlockingQueue,以及非阻塞队列 ConcurrentLinkedQueue,优先队列和延迟队列 DelayQueue 及 DelayedWorkQueue。 7. 面试热点–Java 线程池 Java 线程池是面试常考内容,本模块不仅会涵盖线程池常考的知识点,还会讲述整个线程池的底层实现,jdk8 新特性 CompletableFuture,以及 Fork/Join 框架。 8. 巧妙运用 Java 并发工具类解决并发问题 本模板会介绍常见的 Java 并发工具类,并且进行多维度对比,学完本模块,大家能了解对各自工具类的活学活用。 9. 多线程问题诊断与定位 本模块会结合实际案例演示从问题的发现、止损、恢复的全过程,并且通过监控工具实时查看线程运行状态,让大家能够对线程运行状态有一个全局的把握。

面试官:Java如何绑定线程到指定CPU上执行?

作者:微信小助手

<p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;text-align: center;">这是why的第 <strong>113</strong> 篇原创文章</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">你好呀,我是why。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><img data-ratio="0.7557732680195941" src="/upload/670d976f12e5fe34fd39e116db3f674.png" data-type="png" data-w="1429" height="1080" width="1402"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不知道你是啥感觉,但是我第一次看到这个问题的时候,我是懵逼的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">而且它还是一个面试题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我懵逼倒不是因为我不知道答案,而是恰好我之前在非常机缘巧合的情况下知道了答案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;pad

25000 字详解 23 种设计模式(多图 + 代码)

作者:微信小助手

<ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">创建型模式</a> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: circle;" class="list-paddingleft-2"> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">简单工厂模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">工厂模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">抽象工厂模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">单例模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">建造者模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">原型模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">创建型模式总结</a> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">结构型模式</a> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: circle;" class="list-paddingleft-2"> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">代理模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">适配器模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">桥梁模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">装饰模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">门面模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">组合模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">享元模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">结构型模式总结</a> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">行为型模式</a> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: circle;" class="list-paddingleft-2"> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">策略模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">观察者模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">责任链模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">模板方法模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">状态模式</a> </section></li> <li style="list-style-type: circle;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="2">行为型模式总结</a> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <a href="https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&amp;mid=2247487551&amp;idx=1&amp;sn=18f64ba49f3f0f9d8be9d1fdef8857d9&amp;chksm=fa496f8ecd3ee698f4954c00efb80fe955ec9198fff3ef4011e331aa37f55a6a17bc8c0335a8&amp;scene=21&amp;token=899450012&amp;lang=zh_CN#wechat_redirect" style="color: rgb(30, 107, 184);font-weight: bold;border-bottom: 1px solid rgb(30, 107, 184);" data-linktype="1">总结<span class="js_jump_icon h5_image_link" data-positionback="static" style="inset: auto;margin: 0px;"><img data-ratio="0.5316666666666666" src="/upload/24a7c93f2fca0472d769589ee38622f8.jpg" data-type="jpeg" data-w="1200"

超流行的 Java 数据库框架, MyBatis 千万数据表快速分页!

作者:微信小助手

<section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5MTU0OTY0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zc3KLDBfJlmPt0J5PXYOoiaG8wsQPZrLevbxMZSfgQ0YypNYaicnbS0P9UicluuOySLSP4CjTcRUVHCZzYeXQ9WlA/0?wx_fmt=png" data-nickname="Java派" data-alias="javapai" data-signature="专注Java相关技术栈:Spring全家筒、Docker、k8s、Mysql、集群、微服务、中间件等知识。" data-from="0"></mpprofile> </section> <h3 style="max-width: 100%;text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></em></span><br></h3> <h3 style="max-width: 100%;text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">来源:https://segmentfault.com/a/1190000022478915</em></span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></h3> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">基本概念</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">MyBatis 流式查询接口</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">MyBatis 提供了一个叫&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">org.apache.ibatis.cursor.Cursor</code>&nbsp;的接口类用于流式查询,这个接口继承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:</p> <ol class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Cursor 是可关闭的;</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">Cursor 是可遍历的。</span></p></li> </ol> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">除此之外,Cursor 还提供了三个方法:</p> <ul class="list-paddingleft-2" style="padding-left: 32px;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: break-word !important;"> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">isOpen():用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据;</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">isConsumed():用于判断查询结果是否全部取完。</span></p></li> <li style="margin-bottom: 0.5em;max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">getCurrentIndex():返回已经获取了多少条数据</span></p></li> </ul> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">因为 Cursor 实现了迭代器接口,因此在实际使用当中,从 Cursor 取数据非常简单:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;">cursor.<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">forEach</span>(rowObject&nbsp;-&gt;&nbsp;{...});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">但构建 Cursor 的过程不简单</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们举个实际例子。下面是一个 Mapper 类:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Mapper</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">interface</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">FooMapper</span>&nbsp;</span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Select(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"select&nbsp;*&nbsp;from&nbsp;foo&nbsp;limit&nbsp;#{limit}"</span>)</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;Cursor&lt;Foo&gt;&nbsp;scan(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Param(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"limit"</span>)</span>&nbsp;int&nbsp;limit);<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">方法 scan() 是一个非常简单的查询。通过指定 Mapper 方法的返回值为 Cursor 类型,MyBatis 就知道这个查询方法一个流式查询。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">然后我们再写一个 SpringMVC Controller 方法来调用 Mapper(无关的代码已经省略):</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@GetMapping</span>(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"foo/scan/0/{limit}"</span>)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">scanFoo0</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">(@PathVariable(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"limit"</span>)</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;limit)&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;(Cursor&lt;Foo&gt;&nbsp;cursor&nbsp;=&nbsp;fooMapper.scan(limit))&nbsp;{&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;1</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor.forEach(foo&nbsp;-&gt;&nbsp;{});&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;2</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面的代码中,fooMapper 是 @Autowired 进来的。注释 1 处调用 scan 方法,得到 Cursor 对象并保证它能最后关闭;2 处则是从 cursor 中取数据。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面的代码看上去没什么问题,但是执行 scanFoo0() 时会报错:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">java</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">.lang</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">.IllegalStateException</span>:&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">A</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">Cursor</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">is</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">already</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">closed</span>.<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">这是因为我们前面说了在取数据的过程中需要保持数据库连接,而 Mapper 方法通常在执行完后连接就关闭了,因此 Cusor 也一并关闭了。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">所以,解决这个问题的思路不复杂,保持数据库连接打开即可。我们至少有三种方案可选。</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">方案一:SqlSessionFactory</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们可以用 SqlSessionFactory 来手工打开数据库连接,将 Controller 方法修改如下:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@GetMapping</span>(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"foo/scan/1/{limit}"</span>)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">scanFoo1</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">(@PathVariable(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"limit"</span>)</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;limit)&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;(<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SqlSession&nbsp;sqlSession&nbsp;=&nbsp;sqlSessionFactory.openSession();&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;1</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cursor&lt;Foo&gt;&nbsp;cursor&nbsp;=&nbsp;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sqlSession.getMapper(FooMapper.class).scan(limit)&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;2</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor.forEach(foo&nbsp;-&gt;&nbsp;{&nbsp;});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面的代码中,1 处我们开启了一个 SqlSession (实际上也代表了一个数据库连接),并保证它最后能关闭;2 处我们使用 SqlSession 来获得 Mapper 对象。这样才能保证得到的 Cursor 对象是打开状态的。</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">方案二:TransactionTemplate</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">在 Spring 中,我们可以用 TransactionTemplate 来执行一个数据库事务,这个过程中数据库连接同样是打开的。代码如下:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@GetMapping</span>(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"foo/scan/2/{limit}"</span>)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">scanFoo2</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">(@PathVariable(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"limit"</span>)</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;limit)&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;TransactionTemplate&nbsp;transactionTemplate&nbsp;=&nbsp;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">new</span>&nbsp;TransactionTemplate(transactionManager);&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;1</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;transactionTemplate.execute(status&nbsp;-&gt;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">//&nbsp;2</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;(Cursor&lt;Foo&gt;&nbsp;cursor&nbsp;=&nbsp;fooMapper.scan(limit))&nbsp;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor.forEach(foo&nbsp;-&gt;&nbsp;{&nbsp;});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">return</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">null</span>;<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">上面的代码中,1 处我们创建了一个 TransactionTemplate 对象(此处 transactionManager 是怎么来的不用多解释,本文假设读者对 Spring 数据库事务的使用比较熟悉了),2 处执行数据库事务,而数据库事务的内容则是调用 Mapper 对象的流式查询。注意这里的 Mapper 对象无需通过 SqlSession 创建。</p> <h3 style="margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;max-width: 100%;line-height: inherit;color: rgb(0, 172, 193);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">方案三:@Transactional 注解</span></h3> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">这个本质上和方案二一样,代码如下:</p> <pre style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;box-sizing: border-box !important;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@GetMapping</span>(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"foo/scan/3/{limit}"</span>)<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">@Transactional</span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;"><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">public</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">void</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">scanFoo3</span><span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">(@PathVariable(<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">"limit"</span>)</span>&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">int</span>&nbsp;limit)&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">throws</span>&nbsp;Exception&nbsp;</span>{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="max-width: 100%;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: inherit !important;word-break: inherit !important;">try</span>&nbsp;(Cursor&lt;Foo&gt;&nbsp;cursor&nbsp;=&nbsp;fooMapper.scan(limit))&nbsp;{<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cursor.forEach(foo&nbsp;-&gt;&nbsp;{&nbsp;});<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">&nbsp;&nbsp;&nbsp;&nbsp;}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">它仅仅是在原来方法上面加了个&nbsp;<code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: inherit;line-height: inherit;border-radius: 4px;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);box-sizing: border-box !important;overflow-wrap: break-word !important;">@Transactional</code>&nbsp;注解。这个方案看上去最简洁,但请注意 Spring 框架当中注解使用的坑:只在外部调用时生效。在当前类中调用这个方法,依旧会报错。</p> <p style="margin-top: 1.5em;margin-bottom: 1.5em;max-width: 100%;min-height: 1em;font-size: inherit;color: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">以上是三种实现 MyBatis 流式查询的方法。</p> <p style="max-width: 100%;min-height: 1em;white-space: normal;overflow-wrap: break-word !important;box-sizing: border-box !important;"><br></p>

mysql数据库时间类型datetime、bigint、timestamp的查询效率比较

作者:微信小助手

<p data-lake-id="f47942fff38c686ed626a530b6d84219" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;" data-mpa-powered-by="yiban.io"><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">点击上方蓝色“</span><span style="color: rgb(24, 144, 255);font-size: 13px;" data-mce-style="font-size: 10px">后端面试那些事儿</span><span data-mce-style="font-size: 10px" style="font-size: 13px;color: rgb(136, 136, 136);">”,选择“设为星标”</span></p> <p data-lake-id="eca2a1864e13b3e1b84aafe9cb4abdff" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><span style="color: rgb(140, 140, 140);font-size: 13px;" data-mce-style="font-size: 10px">学最好的别人,做最好的自己</span></p> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" style="text-align: right;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><span style="color: rgb(140, 140, 140);font-size: 13px;" data-mce-style="font-size: 10px">来源:juejin.im/post/6844903701094596615</span></p> <blockquote style="margin: 10px 5px;border-top: none;border-right: 0px solid rgb(53, 179, 120);border-bottom: none;border-left-color: rgb(53, 179, 120);font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(97, 97, 97);padding: 10px 10px 10px 20px;quotes: none;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;">数据库中可以用datetime、bigint、timestamp来表示时间,那么选择什么类型来存储时间比较合适呢?</p> </blockquote> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">前期数据准备</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">通过程序往数据库插入50w数据</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 数据表: </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">CREATE</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">TABLE</span>&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`users`</span>&nbsp;(<br>&nbsp;&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`id`</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">int</span>(<span style="color: rgb(209, 154, 102);line-height: 26px;">11</span>)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">NOT</span>&nbsp;<span style="color: rgb(86, 182, 194);line-height: 26px;">NULL</span>&nbsp;AUTO_INCREMENT,<br>&nbsp;&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_date`</span>&nbsp;datetime&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">NOT</span>&nbsp;<span style="color: rgb(86, 182, 194);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_timestamp`</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">timestamp</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">NOT</span>&nbsp;<span style="color: rgb(86, 182, 194);line-height: 26px;">NULL</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">CURRENT_TIMESTAMP</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">ON</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">UPDATE</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">CURRENT_TIMESTAMP</span>,<br>&nbsp;&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_long`</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">bigint</span>(<span style="color: rgb(209, 154, 102);line-height: 26px;">20</span>)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">NOT</span>&nbsp;<span style="color: rgb(86, 182, 194);line-height: 26px;">NULL</span>,<br>&nbsp;&nbsp;PRIMARY&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">KEY</span>&nbsp;(<span style="color: rgb(152, 195, 121);line-height: 26px;">`id`</span>),<br>&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">KEY</span>&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_long`</span>&nbsp;(<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_long`</span>),<br>&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">KEY</span>&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_timestamp`</span>&nbsp;(<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_timestamp`</span>),<br>&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">KEY</span>&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_date`</span>&nbsp;(<span style="color: rgb(152, 195, 121);line-height: 26px;">`time_date`</span>)<br>)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">ENGINE</span>=<span style="color: rgb(198, 120, 221);line-height: 26px;">InnoDB</span>&nbsp;AUTO_INCREMENT=<span style="color: rgb(209, 154, 102);line-height: 26px;">500003</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">DEFAULT</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">CHARSET</span>=latin1<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">其中time_long、time_timestamp、time_date为同一时间的不同存储格式</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 实体类users </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">@author</span>&nbsp;hetiantian<br>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">@date</span>&nbsp;2018/10/21<br>&nbsp;*&nbsp;*/</span><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Builder</span><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Data</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Users</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;自增唯一id<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;Long&nbsp;id;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;date类型的时间<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;Date&nbsp;timeDate;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;timestamp类型的时间<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;Timestamp&nbsp;timeTimestamp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;long类型的时间<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">long</span>&nbsp;timeLong;<br>}<br></code></pre> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> dao层接口 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;">/**<br>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">@author</span>&nbsp;hetiantian<br>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">@date</span>&nbsp;2018/10/21<br>&nbsp;*&nbsp;*/</span><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Mapper</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">interface</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">UsersMapper</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Insert</span>(<span style="color: rgb(152, 195, 121);line-height: 26px;">"insert&nbsp;into&nbsp;users(time_date,&nbsp;time_timestamp,&nbsp;time_long)&nbsp;value(#{timeDate},&nbsp;#{timeTimestamp},&nbsp;#{timeLong})"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Options</span>(useGeneratedKeys&nbsp;=&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">true</span>,keyProperty&nbsp;=&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">"id"</span>,keyColumn&nbsp;=&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">"id"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">int</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">saveUsers</span><span style="line-height: 26px;">(Users&nbsp;users)</span></span>;<br>}<br></code></pre> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 测试类往数据库插入数据 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">UsersMapperTest</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">extends</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">BaseTest</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Resource</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;UsersMapper&nbsp;usersMapper;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Test</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">test</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">for</span>&nbsp;(<span style="color: rgb(198, 120, 221);line-height: 26px;">int</span>&nbsp;i&nbsp;=&nbsp;<span style="color: rgb(209, 154, 102);line-height: 26px;">0</span>;&nbsp;i&nbsp;&lt;&nbsp;<span style="color: rgb(209, 154, 102);line-height: 26px;">500000</span>;&nbsp;i++)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">long</span>&nbsp;time&nbsp;=&nbsp;System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;usersMapper.saveUsers(Users.builder().timeDate(<span style="color: rgb(198, 120, 221);line-height: 26px;">new</span>&nbsp;Date(time)).timeLong(time).timeTimestamp(<span style="color: rgb(198, 120, 221);line-height: 26px;">new</span>&nbsp;Timestamp(time)).build());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">sql查询速率测试</h3> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过datetime类型查询: </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">count</span>(*)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">where</span>&nbsp;time_date&nbsp;&gt;=<span style="color: rgb(152, 195, 121);line-height: 26px;">"2018-10-21&nbsp;23:32:44"</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">and</span>&nbsp;time_date&nbsp;&lt;=<span style="color: rgb(152, 195, 121);line-height: 26px;">"2018-10-21&nbsp;23:41:22"</span><br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.171</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过timestamp类型查询 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">count</span>(*)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">where</span>&nbsp;time_timestamp&nbsp;&gt;=&nbsp;<span style="color: rgb(152, 195, 121);line-height: 26px;">"2018-10-21&nbsp;23:32:44"</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">and</span>&nbsp;time_timestamp&nbsp;&lt;=<span style="color: rgb(152, 195, 121);line-height: 26px;">"2018-10-21&nbsp;23:41:22"</span><br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.351</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过bigint类型查询 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">count</span>(*)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">where</span>&nbsp;time_long&nbsp;&gt;=<span style="color: rgb(209, 154, 102);line-height: 26px;">1540135964091</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">and</span>&nbsp;time_long&nbsp;&lt;=<span style="color: rgb(209, 154, 102);line-height: 26px;">1540136482372</span><br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.130s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 结论 在InnoDB存储引擎下,通过时间范围查找,性能bigint &gt; datetime &gt; timestamp </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"> <mpcpc js_editor_cpcad="" class="js_cpc_area cpc_iframe" src="/cgi-bin/readtemplate?t=tmpl/cpc_tmpl#1625295257735" data-category_id_list="48|32|26|49|1|27|28|45|46|55|39|8|3|47|35|41|5|31|6|7|24|37|22|11|50|54|53|52|42|29|43|16|17|51|36" data-id="1625295257735"></mpcpc></h3> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">sql分组速率测试</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">使用bigint 进行分组会每条数据进行一个分组,如果将bigint做一个转化在去分组就没有比较的意义了,转化也是需要时间的</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过datetime类型分组: </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;time_date,&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">count</span>(*)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">group</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">by</span>&nbsp;time_date<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.176s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过timestamp类型分组: </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;time_timestamp,&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">count</span>(*)&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">group</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">by</span>&nbsp;time_timestamp<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.173s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 结论 在InnoDB存储引擎下,通过时间分组,性能timestamp &gt; datetime,但是相差不大 </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">sql排序速率测试</h3> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过datetime类型排序: </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">order</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">by</span>&nbsp;time_date<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:1.038s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过timestamp类型排序 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">order</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">by</span>&nbsp;time_timestamp<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.933s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 通过bigint类型排序 </section></li> </ul> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">select</span>&nbsp;*&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">from</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">users</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">order</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">by</span>&nbsp;time_long<br></code></pre> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">耗时:0.775s</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> 结论 在InnoDB存储引擎下,通过时间排序,性能bigint &gt; timestamp &gt; datetime </section></li> </ul> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">小结</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如果需要对时间字段进行操作(如通过时间范围查找或者排序等),推荐使用bigint,如果时间字段不需要进行任何操作,推荐使用timestamp,使用4个字节保存比较节省空间,但是只能记录到2038年记录的时间有限</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> END&nbsp; </section></li> </ul> <p data-lake-id="b4f10076adf2228ecaccd921f627ed69" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section mpa-from-tpl="t" style="margin-top: 10px;margin-bottom: 10px;"> <p style="margin-right: auto;margin-left: auto;width: 231.1875px;"><img data-ratio="0.16666666666666666" src="/upload/89aa6c9fe16e0dfcf56dad1a9f9078ff.png" data-type="gif" data-w="300" style="width: auto;"></p> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><br></p> <section data-recommend-type="list-title" data-recommend-tid="6" data-mpa-template="t" style="width: 100%;display: flex;justify-content: center;align-items: center;" data-mid="" data-from="yb-recommend"> <section style="width: 100%;padding: 14px;background: rgb(255, 255, 255);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 235);" data-mid=""> <section style="width: 100%;display: flex;justify-content: center;align-items: center;align-items: flex-end;" data-mid=""> <section data-mid="" style="height: 28px;padding: 4px 22px;font-size: 14px;font-weight: 500;color: rgb(19, 52, 86);line-height: 20px;background-image: url(&quot;https://mmbiz.qpic.cn/mmbiz_png/sUbvrqLicbpzB81mjeBxPuxnYdalGxNnJo30L2Hq3WwGficcq8w5YJkLeXnsNHocN53k55TfN5mBpCdicGRyfDg1g/640?wx_fmt=png&quot;);background-repeat: no-repeat;background-size: 100% 100%;margin-bottom: -14px;z-index: 10;"> <p data-mid="">往期推荐</p> </section> </section> <section style="width: 100%;border-width: 1px;border-style: solid;border-color: rgb(198, 226, 255);padding: 17px 16px 9px;" data-mid=""> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495517_1" data-recommend-article-time="1625288460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZXP4vcvkSIUKCB726EfaFmo292Ja21ypkr2mm8OIQodtBQ4Nr7a6K7grbCRLztpuGPUJ4fTkAqeg/0?wx_fmt=jpeg" data-recommend-article-title="Java必会的工具库,让你的代码量减少90%" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=1&amp;sn=7dd347f5a31aa88a88b779dee669cabd&amp;chksm=97b47145a0c3f8531a3018fdd6db21c841689573ff76b25c4629cf8859695af36cf40ec0b674#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=1&amp;sn=7dd347f5a31aa88a88b779dee669cabd&amp;chksm=97b47145a0c3f8531a3018fdd6db21c841689573ff76b25c4629cf8859695af36cf40ec0b674&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">Java必会的工具库,让你的代码量减少90%</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495517_2" data-recommend-article-time="1625288460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGFgThhSuxwvIrEdWOaWzEsE3RvlicKb3UVcTyKUv5ePLiaX5ndNL9OH4bmH02VQ7rIzdqoLaksV9kw/0?wx_fmt=jpeg" data-recommend-article-title="为什么catch了异常,但事务还是回滚了?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=2&amp;sn=d25a7d3db51aa1a879b7aa48eb5a0535&amp;chksm=97b47145a0c3f85314cc1044b136af0c26d4c0087b995b439b9632be41f3c414fe9d5ee8aabd#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=2&amp;sn=d25a7d3db51aa1a879b7aa48eb5a0535&amp;chksm=97b47145a0c3f85314cc1044b136af0c26d4c0087b995b439b9632be41f3c414fe9d5ee8aabd&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">为什么catch了异常,但事务还是回滚了?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495517_3" data-recommend-article-time="1625288460" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/Rhiaqbb2uvaKF3CUJUdKgbYUQEuxrqu2YwFNBs5Ax1zsgXuUiajs5I6iaLyVj0KEnenQEjP1JIoqXt3lNeO24EF6A/0?wx_fmt=jpeg" data-recommend-article-title="一键弹出健康码攻略!" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=3&amp;sn=74e885a347c134027c10f42f2423425d&amp;chksm=97b47145a0c3f8531c0873ca255c82deabaee0f9bd41b0f00b01214e9283eb7e020b17b4ebcd#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495517&amp;idx=3&amp;sn=74e885a347c134027c10f42f2423425d&amp;chksm=97b47145a0c3f8531c0873ca255c82deabaee0f9bd41b0f00b01214e9283eb7e020b17b4ebcd&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">一键弹出健康码攻略!</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495507_1" data-recommend-article-time="1625202060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/HmHDU48icAtZibq8Ol2DXvSseQB6qB5IUINsB4eQHS2ico92gKaicJ1icDl7S9VDQb2wQBbCTpgT9XokhPWYMiaq3Isg/0?wx_fmt=jpeg" data-recommend-article-title="说说Java 9 - 16 的新特性?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=1&amp;sn=258c8e3d3bcc45e7c3fb1ab749754099&amp;chksm=97b4714ba0c3f85d3158fca60265d97e4ce74450550d7a12b48c996ed5dee39c231148b6503e#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=1&amp;sn=258c8e3d3bcc45e7c3fb1ab749754099&amp;chksm=97b4714ba0c3f85d3158fca60265d97e4ce74450550d7a12b48c996ed5dee39c231148b6503e&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">说说Java 9 - 16 的新特性?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495507_2" data-recommend-article-time="1625202060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/R3InYSAIZkGFFpE8Giaic5Z9sI8YZh4XNhkWlXJ86ic1cRd6EJNJuT4o01PiboyD8Ewviaha3kibASEqCUWL3A9W8Lfg/0?wx_fmt=jpeg" data-recommend-article-title="骚操作!阿里云直接买www.huaweicloud.com的关键词来抢生意?" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=2&amp;sn=ad525c30d15a97efbda2844d776816a1&amp;chksm=97b4714ba0c3f85d91c3f3e4f403bbfc3568940a4243967f8915fb15f19f2a4b1ba3e8bd7daf#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=2&amp;sn=ad525c30d15a97efbda2844d776816a1&amp;chksm=97b4714ba0c3f85d91c3f3e4f403bbfc3568940a4243967f8915fb15f19f2a4b1ba3e8bd7daf&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">骚操作!阿里云直接买www.huaweicloud.com的关键词来抢生意?</p> </section></a> </section> <section data-mpa-template="t" data-recommend-article-type="list-title" data-recomment-template-id="6" data-recommend-article-id="2247495507_3" data-recommend-article-time="1625202060" data-recommend-article-cover="http://mmbiz.qpic.cn/mmbiz_jpg/Rhiaqbb2uvaLaZI7hVQA9QGcffW0b3ia0MPOKngtFX51xykGsiaUfRDZJ48LrHbY8Vsz8e1iceSgmjcqmD6NTEic6dQ/0?wx_fmt=jpeg" data-recommend-article-title="U盘自动复制工具,插入就被复制,到底有多么不知不觉!(附下载地址)" data-recommend-article-content-url="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=3&amp;sn=c6dc0dc243c6623d95ab3da7118e7b2a&amp;chksm=97b4714ba0c3f85deea4817ffd0167ef9e2734690ceee34379f653031f262cb4a890a14ed61a#rd"> <a href="http://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&amp;mid=2247495507&amp;idx=3&amp;sn=c6dc0dc243c6623d95ab3da7118e7b2a&amp;chksm=97b4714ba0c3f85deea4817ffd0167ef9e2734690ceee34379f653031f262cb4a890a14ed61a&amp;scene=21#wechat_redirect" data-linktype="2"> <section data-recommend-title="t" data-recommend-content="t" style="width: 100%;display: flex;justify-content: center;align-items: center;flex-wrap: nowrap;border-bottom: 1px dashed #c6e2ff;padding: 6px;font-size: 13px;font-weight: 400;color: #2c5f95;line-height: 18px;border-bottom:none !important;" data-mid=""> <p style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 100%;" data-mid="">U盘自动复制工具,插入就被复制,到底有多么不知不觉!(附下载地址)</p> </section></a> </section> </section> </section> </section> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><br></p> <p data-lake-id="098b923ca3e65e99528d2c30d6cf4c26" style="text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"><span style="color: rgb(140, 140, 140);"><br></span></p> <section data-mpa-template="t" mpa-from-tpl="t" style="white-space: normal;"> <p style="text-align: center;"><strong><span style="color: rgb(140, 140, 140);letter-spacing: 0.008em;font-size: 14px;">一起进大厂,每日学干货</span></strong></p> </section> <section style="margin-top: 5px;white-space: normal;text-align: center;font-size: 15px;color: rgb(64, 64, 64);line-height: 1.74;letter-spacing: 0.008em;outline-style: none;overflow-wrap: break-word;"> <span style="color: rgb(0, 0, 0);"><strong><span style="font-size: 14px;">关注我回复【</span></strong></span> <span style="color: rgb(255, 76, 65);"><strong><span style="font-size: 14px;">加群</span></strong></span> <span style="color: rgb(0, 0, 0);"><strong><span style="color: rgb(0, 0, 0);font-size: 14px;">】,加入Java技术交流群</span></strong></span> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <p style="text-align: center;"><img data-ratio="0.5982532751091703" src="/upload/4e21037b66f60f7d73d060863de4b4b5.png" data-type="gif" data-w="458" data-width="100%" style="color: rgb(62, 62, 62);font-size: 16px;vertical-align: middle;width: 62.0938px;"></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzIxMzQzNzMwMw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/HmHDU48icAtYvlypOY9VaGVXQ639L63Iq6zHiclgibG0CAhgrJ2JLRibKbeCgVIx7WXcicbMW6AJL1Hos9AoJTqtVfA/0?wx_fmt=png" data-nickname="后端面试那些事" data-alias="" data-signature="专注分享后端干货!面向大厂,一起进步!" data-from="0"></mpprofile> </section> <p style="text-align: center;"><br></p> </section> <p style="text-align: center;"><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-role="paragraph" mpa-from-tpl="t" style="white-space: normal;border-width: 0px;border-style: none;border-color: initial;"> <section style="box-sizing: border-box;font-size: 16px;"> <section powered-by="xiumi.us" style="margin-top: 0.5em;box-sizing: border-box;"> <section style="padding: 0.5em;border-width: 1px;border-style: solid;border-color: rgb(249, 110, 87);box-shadow: rgb(226, 226, 226) 0px 16px 1px -13px;box-sizing: border-box;"> <section powered-by="xiumi.us" style="text-align: left;box-sizing: border-box;"> <section style="text-align: justify;color: rgb(64, 84, 115);box-sizing: border-box;"> <p style="box-sizing: border-box;"><img data-ratio="0.33611111111111114" src="/upload/a53e4e397528931045198e4f89d7ba0.png" data-type="png" data-w="1080"></p> <p style="box-sizing: border-box;">点击“阅读原文”,领取 2021&nbsp;年<strong>最新免费技术资料大全</strong></p> </section> </section> </section> </section> <section powered-by="xiumi.us" style="font-size: 32px;color: rgb(249, 110, 87);box-sizing: border-box;text-align: left;"> ↓↓↓&nbsp; </section> </section> </section> </section>

多线程 +1 的最快操作

作者:微信小助手

<section style="margin: 10px 8px;white-space: normal;font-size: 16px;line-height: 1.75em;text-align: left;" data-mpa-powered-by="yiban.io"> <span style="letter-spacing: 0.5px;text-align: justify;">直奔主题,多个线程,一个共享变量,不断 +1。</span> </section> <p><img data-height="auto" data-ratio="0.5995850622406639" src="/upload/3daedee3081d48daa8325131522e5fe6.png" data-type="png" data-w="482" data-width="482" height="auto" style="max-width: 100%;display: block;margin: 20px auto 30px;width: 284px;height: 170px;" width="482"></p> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">如果代码直接这样写,会产生线程安全问题。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;font-size: 16px;padding: 10px;"> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LongAdder</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;count&nbsp;=&nbsp;<span style="color: #d19a66;line-height: 26px;">0L</span>;<br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">add</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<br>&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">可以加锁去实现,但效率太低。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;font-size: 16px;padding: 10px;"> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LongAdder</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;count&nbsp;=&nbsp;<span style="color: #d19a66;line-height: 26px;">0L</span>;<br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">add</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">synchronized</span>(<span style="color: #c678dd;line-height: 26px;">this</span>){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<br>&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> </section> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">可以用原子类这种乐观锁实现,比加 synchronized 锁效率高很多。</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;font-size: 16px;padding: 10px;"> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LongAdder</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;AtomicLong&nbsp;count&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;AtomicLong(<span style="color: #d19a66;line-height: 26px;">0L</span>);<br>&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">add</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count.incrementAndGet();<br>&nbsp;&nbsp;&nbsp;}<br>}</code></pre> </section> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">当然,更高级的玩法也可以自己调用 UNSAFE 模拟原子类里的 CAS 操作,但实际上就是把原子类的源码给展开了。(v = count 应该放在循环里)</span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: PingFangSC-Light;font-size: 16px;padding: 10px;"> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 15px 16px 16px;display: -webkit-box;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span><span style="color:#abb2bf;">&nbsp;</span><span style="color: rgb(171, 178, 191);line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LongAdder</span>&nbsp;</span><span style="color:#abb2bf;">{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">private</span><span style="color:#abb2bf;">&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">volatile</span><span style="color:#abb2bf;">&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">long</span><span style="color:#abb2bf;">&nbsp;count&nbsp;=&nbsp;</span><span style="color: rgb(209, 154, 102);line-height: 26px;">0L</span><span style="color:#abb2bf;">;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(171, 178, 191);line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">add</span><span style="line-height: 26px;">()</span>&nbsp;</span><span style="color:#abb2bf;">{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">boolean</span><span style="color:#abb2bf;">&nbsp;success&nbsp;=&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">false</span><span style="color:#abb2bf;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">int</span><span style="color:#abb2bf;">&nbsp;v =&nbsp;count;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;">while</span><span style="color:#abb2bf;">(!success)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success&nbsp;=&nbsp;UNSAFE.compareAndSwapLong(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LongAdder</span><span style="line-height: 26px;"><span style="color:#abb2bf;">.</span><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span><span style="color:#abb2bf;">,&nbsp;</span><span style="color: rgb(230, 192, 123);line-height: 26px;">countOffset</span><span style="color:#abb2bf;">,&nbsp;</span><span style="color: rgb(230, 192, 123);line-height: 26px;">v</span><span style="color:#abb2bf;">,&nbsp;</span><span style="color:#e6c07b;">v </span><span style="color:#abb2bf;">+&nbsp;1)</span></span><span style="color:#abb2bf;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;}<br>}</span></code></pre> </section> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">这几段多线程 +1 的代码如果看不明白,可以找些资料把这块的基础补一下哈,本文就不赘述了,我们继续。</span></p> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;">关于这个多线程 +1 操作,有没有效率更高的办法呢?</span></p> <p style="margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 16px;letter-spacing: 0.5px;"><br mpa-from-tpl="t"></span></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-t

6000 字 | 统一缓存帝国 - 实战 Spring Cache

作者:微信小助手

<figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8104166666666667" src="/upload/5ed1051be0c2ddd48452e5edc43c2456.png" data-type="png" data-w="960" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <span style="letter-spacing: 0px;color: rgb(58, 58, 58);"></span> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">缓存系列文章:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954442&amp;idx=1&amp;sn=e5ec784a11fcbad89eb2e4c7a809378d&amp;chksm=8d1c2295ba6bab833b77318661d4aeb4533234f03d4b9e5a298e84b8041258569af4301a21c3&amp;scene=21#wechat_redirect" textvalue="《缓存实战(一)》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(一)》</a></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954663&amp;idx=1&amp;sn=4bd071b6aaede114263f88c790b61371&amp;chksm=8d1c2278ba6bab6eca2ef44f21b2178cc719fffe124289b68128c0dad72429fe5f286854157a&amp;scene=21#wechat_redirect" textvalue="《缓存实战(二)Redis分布式锁》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(二)Redis分布式锁》</a></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955246&amp;idx=1&amp;sn=5db231b88fb9e735e907873d420f26a5&amp;chksm=8d1c27b1ba6baea7d3ef65860276140ae30a4e2bbe45179931c3f476f1fcb30d8365905dd413&amp;scene=21#wechat_redirect" textvalue="《缓存实战(三)Redisson 分布式锁》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(三)Redisson 分布式锁》</a></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">一、揭开 Spring Cache 的面纱</span></h2> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">1.1 现有缓存方案的痛点</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">试想一种场景</strong>:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">1.用户 A 打开 APP,进入到了秒杀商品的详情页,那这个商品数据我们会先去数据库查询,然后返回给客户端。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">2.因为有大量用户短时间内进入到了详情页,所以可以把活动列表缓存起来,直接读缓存就可以了。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">3.那下次再查询商品时,直接去缓存查询就可以了。如果秒杀商品下架了,缓存的数据不会用到了,就把缓存删掉就可以了。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">4.上面几步看起来也没啥问题,但是放缓存,删除缓存这两步是需要我们去手动写代码实现的。有没有一种方式不用写操作缓存的代码?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">5.假如现在用的缓存中间件是 Redis,领导说要换成 Ehcache,操作缓存的代码是不是又得重新撸一遍?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">总结下上面场景的痛点:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 需要手写操作缓存代码,如添加缓存、更新缓存、删除缓存。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 切换缓存组件并不容易,或者说没有对缓存层进行抽象封装,依赖具体的缓存中间件。 </section></li> </ul> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">哪有没有一种方案可以帮助解决上面的两个痛点呢?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这就是今天要介绍的 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">Spring Cache</code>。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">1.2 Spring Cache 介绍</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring Cache 是 Spring 提供的一整套的缓存解决方案。虽然它本身并没有提供缓存的实现,但是它提供了一整套的接口和代码规范、配置、注解等,这样它就可以整合各种缓存方案了,比如 Redis、Ehcache,我们也就不用关心操作缓存的细节。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring 3.1 开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术,并支持使用注解来简化我们开发。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">Cache</code> 接口它包含了缓存的各种操作方式,同时还提供了各种<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">xxxCache</code>缓存的实现,比如 RedisCache 针对Redis,EhCacheCache 针对 EhCache,ConcurrentMapCache 针对 ConCurrentMap,具体有哪几种,后面实战中会介绍。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">1.3 Spring Cache 有什么功效</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">每次调用某方法,而此方法又是带有缓存功能时,Spring 框架就会检查<code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">指定参数</code>的那个方法是否已经被调用过,如果之前调用过,就从缓存中取之前调用的结果;如果没有调用过,则再调用一次这个方法,并缓存结果,然后再返回结果,那下次调用这个方法时,就可以直接从缓存中获取结果了。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">1.4 Spring Cache 的原理是什么?</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring Cache 主要是作用在类上或者方法上,对类中的方法的返回结果进行缓存。那么如何对方法增强,来实现缓存的功能?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">学过 Spring 的同学,肯定能一下子就反应过来,就是用 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">AOP</code>(面向切面编程)。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">面向切面编程可以简单地理解为在类上或者方法前加一些说明,就是我们常说的注解。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring Cache 的注解会帮忙在方法上创建一个切面(aspect),并触发缓存注解的切点(poinitcut),听起来太绕了,简单点说就是:Spring Cache 的注解会帮忙在调用方法之后,去缓存<strong style="color: black;">方法调用的最终结果</strong>,或者在方法调用之前拿缓存中的结果,或者删除缓存中的结果,这些读、写、删缓存的<strong style="color: black;">脏活</strong>都交给 Spring Cache 来做了,是不是很爽,再也不用自己去写缓存操作的逻辑了。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">1.5 缓存注解</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring 提供了四个注解来声明缓存规则。@Cacheable,@CachePut,@CacheEvict,@Caching。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4360655737704918" src="/upload/dcbdb4c575d8d4243647043efba065c.png" data-type="png" data-w="610" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">大家先有个概念,后面我们再来看怎么使用这些缓存注解。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">二、使用缓存</span></h2> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.1 引入 Spring Cache 依赖</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">在 pom 文件中引入 spring cache 依赖,如下所示:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>org.springframework.boot<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-starter-cache<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.2 配置使用哪种缓存</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">Spring Cache 支持很多缓存中间件作为框架中的缓存,总共有 9 种选择:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> caffeine:Caffeine 是一种高性能的缓存库,基于 Google Guava。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> couchbase: <em style="color: black;">CouchBase</em>是一款非关系型JSON文档数据库。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> generic:由泛型机制和 static 组合实现的泛型缓存机制。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> hazelcast:一个高度可扩展的数据分发和集群平台,可用于实现分布式数据存储、数据缓存。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> infinispan:分布式的集群缓存系统。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> jcache:JCache 作为缓存。它是 JSR107 规范中提到的缓存规范。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> none:没有缓存。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> redis:用 Redis 作为缓存 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> simple:用内存作为缓存。 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5453367875647669" src="/upload/5b85734d14255894fbeddace8eb83067.png" data-type="png" data-w="772" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> mark </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">我们还是用最熟悉的 Redis 作为缓存吧。配置 Redis 作为缓存也很简单,在配置文件 application.properties 中设置缓存的类型为 Redis 就可以了, 如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.29427792915531337" src="/upload/d0e35a12eea731250fa1dd7fffe65b78.png" data-type="png" data-w="367" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">当然,别忘了还要在 pom 文件中 引入 Redis 的依赖,不然用不了 Redis。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span>org.springframework.boot<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">groupId</span>&gt;</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;">&lt;<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">artifactId</span>&gt;</span><br><span style="line-height: 26px;">&lt;/<span style="color: #e06c75;line-height: 26px;">dependency</span>&gt;</span><br></code></pre> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.3 测试缓存</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">那基础的配置已经做好了,现在就是看怎么使用 Spring Cache 了。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">(1)启动类上添加 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">@EnableCaching</code>注解。本文案例就是在 启动类 PassjavaQuestionApplication 添加 @EnableCaching注解。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.31607629427792916" src="/upload/ec4ad7f942293f777386d3bec3320fd4.png" data-type="png" data-w="734" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">(2)指定某方法开启缓存功能。在方法上添加 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">@Cacheable</code> 缓存注解就可以了。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">@Cacheable 注解中,可以添加四种参数:value,key,condition,unless。首先我们来看下 value 参数。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">下面的代码出于演示作用,用了最简单的逻辑,test 方法直接返回一个数字,连数据库查询都没有做。不过没关系,我们主要验证 Spring Cache 是否对方法的结果进行了缓存。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@RequestMapping</span>(<span style="color: #98c379;line-height: 26px;">"/test"</span>)<br><span style="color: #61aeee;line-height: 26px;">@Cacheable</span>({<span style="color: #98c379;line-height: 26px;">"hot"</span>})<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">test</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">222</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">大家注意,@Cacheable 注解中小括号里面还含有大括号,大括号里面还有 “hot” 字符串,这个 hot 字符串你可以把它当作一个缓存的名字,然后将 test 方法返回的结果存到 hot 缓存中。我们也可以用 value="hot" 的方式。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">第一次调用 test 方法前,既没有 hot 缓存,更没有 test 的结果缓存。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">调用 test 方法后,Redis 中就创建出了 hot 缓存了,然后缓存了一个 key,如下图所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.30994152046783624" src="/upload/299e2e85afa2a8bf50bdd25b1f3d69ec.png" data-type="png" data-w="855" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">第二次调用 test 方法时,就从缓存 hot 中将 test 方法缓存的结果 222 取出来了,为了验证没有执行 test 中的方法,大家可以在 test 方法中打下 log 或者断点。最后的验证结果肯定是没有走 test 方法的,而是直接从缓存中获取的。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">那我们再来测试一个方法,方法名改为 test2,且请求路径也改为 test2 了。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@RequestMapping</span>(<span style="color: #98c379;line-height: 26px;">"/test2"</span>)<br><span style="color: #61aeee;line-height: 26px;">@Cacheable</span>({<span style="color: #98c379;line-height: 26px;">"hot"</span>})<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">test2</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;<span style="color: #d19a66;line-height: 26px;">456</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">大家觉得这两个方法的结果都会缓存吗?还是只会缓存第一个被调用的方法?</strong></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">经过测试,执行第一个 test 方法后,再执行 test2 方法,缓存结果一直是 222 不会变。因为他们的 key 都是 默认的 SimpleKey[],所以两个方法对应的缓存的 key 都叫这个,所以得到的缓存值是一样的。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">(3)加上数据库查询的测试。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">有的同学可能觉得上面的测试太简单了,test 方法里面啥都没做,还缓存啥呢,完全没必要啊。没关系,大家的顾虑是对的,我们来加上数据库查询,安排~</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">先说下场景:前端需要查询某个题目的详情,正常逻辑是查询数据库后返回结果。假定这个查询操作非常频繁,我们需要将题目详情进行缓存。我们先看看常规 Redis 缓存方案:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">先从 Redis 缓存中查看缓存中是否有该题目,如果缓存中有,则返回缓存中的题目;如果没有,就从数据库中查。查询出题目后,就用 Redis 存起来,然后返回。这里就要写操作 Redis 的代码了:查询 Redis 缓存、更新 Redis 缓存。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;查询缓存,假定该题目详情缓存的&nbsp;key=question1</span><br>redisTemplate.opsForValue().get(<span style="color: #98c379;line-height: 26px;">"question1"</span>);&nbsp;<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;更新缓存</span><br>redisTemplate.opsForValue().set(<span style="color: #98c379;line-height: 26px;">"question1"</span>,&nbsp;questionEntity);<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">那如果用 Spring Cache 注解的话,上面两行代码可以直接干掉了。如下所示,加一个 @Cacheable 注解搞定。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Cacheable</span>({<span style="color: #98c379;line-height: 26px;">"question"</span>,&nbsp;<span style="color: #98c379;line-height: 26px;">"hot"</span>})<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;QuestionEntity&nbsp;<span style="color: #61aeee;line-height: 26px;">info</span><span style="line-height: 26px;">(Long&nbsp;id)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;getById(id);&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;查询数据库操作</span><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">其中 question 和 hot 是缓存的名字,我们可以将结果放到不同的缓存中。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">结论:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果没有指定请求参数,则缓存生成的 key name,是默认自动生成的,叫做 SimpleKey[]。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果指定了请求参数,则缓存的 key &nbsp;name 就是请求参数,比如上面 info 方法,key 等于我传入的 id = 1。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 缓存中 key 对应的 value 默认使用 JDK 序列化后的数据。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> value 的过期时间为 -1,表示永不过期。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.4 自定义配置类</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">上面保存的缓存数据都是默认设置,我们也可以自己定义配置,如下所示,在配置文件 application.properties 添加如下配置:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;使用&nbsp;Redis&nbsp;作为缓存组件</span><br>spring.cache.type=redis<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;缓存过期时间为&nbsp;3600s</span><br>spring.cache.redis.time-to-live=3600000<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;缓存的键的名字前缀</span><br>spring.cache.redis.key-prefix=passjava_<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;是否使用缓存前缀</span><br>spring.cache.redis.use-key-prefix=<span style="color: #56b6c2;line-height: 26px;">true</span><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">#&nbsp;是否缓存控制,防止缓存穿透</span><br>spring.cache.redis.cache-null-values=<span style="color: #56b6c2;line-height: 26px;">true</span><br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">然后需要加一个配置类:MyCacheConfig。可以在我的开源项目 passjava 获取完整源码。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="line-height: 26px;">RedisCacheConfiguration&nbsp;<span style="color: #61aeee;line-height: 26px;">redisCacheConfiguration</span><span style="line-height: 26px;">(CacheProperties&nbsp;cacheProperties)</span>&nbsp;</span>{<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.5 自定义 key</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">然后我们可以指定 key 的值,可以在 @Cacheable 注解里面加上 key 的值 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">#root.method.name</code>。这是一种特有的表达式,称作 <code style="font-size: 14px;border-radius: 4px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">SpEL</code> 表达式,这里代表用方法名作为缓存 key 的名字。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Cacheable</span>(value&nbsp;=&nbsp;{<span style="color: #98c379;line-height: 26px;">"hot"</span>},&nbsp;key&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"#root.method.name"</span>)<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">接下来就是见证奇迹的时刻,调用 test 方法和 test2 方法,发现有两个不同的 key,一个是 passjava_test1,另外一个 passjava_test2,它们的 key 就是前缀 passjava_ + 方法名 组成。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.29608938547486036" src="/upload/2de7d2c92e671e675139fbda2c65f01f.png" data-type="png" data-w="716" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">SpEL 表达式还有很多其它规则,如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.47746478873239434" src="/upload/bb8a8f85a62181b9d2a78abfc5bf4347.png" data-type="png" data-w="710" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">可以根据项目需要选择合适的表达式来自定义 key。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.6 自定义条件</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">除了设置缓存条目的 key,我们还可以自定义条件来决定是否将缓存功能关闭。这里就要用到@Cacheable 另外两个属性:condition 和 unless,它俩的格式还是用 SpEL 表达式。对应的四个属性总结如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.3798319327731092" src="/upload/7a34c9e605b91dadc92efef7ebd47c9d.png" data-type="png" data-w="595" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">代码示例如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@Cacheable</span>(value&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"hot"</span>,&nbsp;unless&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"#result.message.containss('NoCache')"</span>)<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">当放回的结果 message 字段包含有 NoCache 就不会进行缓存。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.7 更新注解</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><span style="color: rgb(255, 104, 39);">@CachePut </span>也是用来更新缓存,和 @Cacheable 非常相似,不同点是 @CachePut 注解的方法始终都会执行,返回值也会也会放到缓存中。通常用在保存的方法上。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">保存成功后,可以将 key 设置保存实例的 id。这个怎么做呢?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">之前我们说过 key 可以通过 SpEL 表达式来指定,这里就可以搭配 #result.id 来实现。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这里还是用个例子来说明用法:创建题目的方法,返回题目实例,其中包含有题目 id。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@RequestMapping</span>(<span style="color: #98c379;line-height: 26px;">"/create"</span>)<br><span style="color: #61aeee;line-height: 26px;">@CachePut</span>(value&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"hot"</span>,&nbsp;key&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"#result.id"</span>)<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;QuestionEntity&nbsp;<span style="color: #61aeee;line-height: 26px;">create</span><span style="line-height: 26px;">(@Valid&nbsp;@RequestBody&nbsp;QuestionEntity&nbsp;question)</span></span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;IQuestionService.createQuestion(question);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">保存的 id 是自增的,值为 123,所以缓存中的 key = passjava_123。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4680589680589681" src="/upload/54898a8a0564d043d502451c5dcbc4f.png" data-type="png" data-w="814" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">2.8 删除缓存注解</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><span style="color: rgb(255, 104, 39);">@CacheEvict </span>注解的方法在调用时不会在缓存中添加任何东西,但是会从从缓存中移除之前的缓存结果。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">示例代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url(&quot;https://mmbiz.qpic.cn/mmbiz_svg/ibKHP1TZZeXLaZ44VRs4bzx9p3FJYmMcn0gD7ScrAPkNib8eUyv7UlT9V2deCHCA3PbTAoUWsDfkKrOiarZ0UqxFroQOfZSoRmS/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">@RequestMapping</span>(<span style="color: #98c379;line-height: 26px;">"/remove/{id}"</span>)<br><span style="color: #61aeee;line-height: 26px;">@CacheEvict</span>(value&nbsp;=&nbsp;<span style="color: #98c379;line-height: 26px;">"hot"</span>)<br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;R&nbsp;<span style="color: #61aeee;line-height: 26px;">remove</span><span style="line-height: 26px;">(@PathVariable(<span style="color: #98c379;line-height: 26px;">"id"</span>)</span>&nbsp;Long&nbsp;id)</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;IQuestionService.removeById(id);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;R.ok();<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">删除条目的 key 与传递进来的 id 相同。我测试的时候传的 id = 123,经过前缀passjava_组装后就是 passjava_123,所以将之前缓存的 passjava_123 删除了。重复执行也不会报错。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">注意:@CacheEvict 和 @Cacheable、@CachePut 不同,它能够应用在返回值为 void 的方法上。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">@CacheEvict 还有些属性可供使用,总结如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5367892976588629" src="/upload/2bdfe29bf23ca4ee1521691d89c0b8a5.png" data-type="png" data-w="598" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">三、 总结</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">本文通过传统使用缓存的方式的痛点引出 Spring 框架中的 Cache 组件。然后详细介绍了 Spring Cache 组件的用法:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 五大注解。@Cacheable、@CachePut、@CacheEvict、@Caching,、@CacheConfig。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如何自定义缓存条目的 key。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如何自定义 Cache 配置。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如何自定义缓存的条件。 </section></li> </ul> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 当然 Spring Cache 并不是万能的,缓存一致性问题依旧存在,下一篇,我们再细聊缓存的一致性问题。 <br> </section> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <br> </section> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;line-height: 1.8em;color: rgb(58, 58, 58);"><strong>缓存系列文章汇总</strong>:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954442&amp;idx=1&amp;sn=e5ec784a11fcbad89eb2e4c7a809378d&amp;chksm=8d1c2295ba6bab833b77318661d4aeb4533234f03d4b9e5a298e84b8041258569af4301a21c3&amp;scene=21#wechat_redirect" textvalue="《缓存实战(一)》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(一)》</a></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451954663&amp;idx=1&amp;sn=4bd071b6aaede114263f88c790b61371&amp;chksm=8d1c2278ba6bab6eca2ef44f21b2178cc719fffe124289b68128c0dad72429fe5f286854157a&amp;scene=21#wechat_redirect" textvalue="《缓存实战(二)Redis分布式锁》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(二)Redis分布式锁》</a></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 16px;text-align: left;white-space: normal;line-height: 1.8em;color: rgb(58, 58, 58);"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451955246&amp;idx=1&amp;sn=5db231b88fb9e735e907873d420f26a5&amp;chksm=8d1c27b1ba6baea7d3ef65860276140ae30a4e2bbe45179931c3f476f1fcb30d8365905dd413&amp;scene=21#wechat_redirect" textvalue="《缓存实战(三)Redisson 分布式锁》" data-itemshowtype="0" tab="innerlink" data-linktype="2">《缓存实战(三)Redisson 分布式锁》</a></p> <section style="line-height: 1.8em;color: rgb(58, 58, 58);margin-bottom: 5px;"> 参考资料: </section> <section style="line-height: 1.8em;color: rgb(58, 58, 58);margin-bottom: 5px;"> www.passjava.cn&nbsp; </section> <section style="line-height: 1.8em;color: rgb(58, 58, 58);margin-bottom: 5px;"> Spring in Action </section>