从 class 文件 看 synchronize 锁膨胀过程(偏向锁 轻量级锁 自旋锁 重量级锁)

大家好,我是烤鸭:

    前几天看马士兵老师的并发的课,里边讲到了 synchronize 锁的膨胀过程,今天想用代码演示一下。

1.  简单介绍

    关于synchronize jdk 1.5 以后的优化,由重量级锁调整为膨胀过程。分别是 偏向锁 轻量级锁(自旋锁) 重量级锁。

2.  用例编写

pom文件增加 jol的包,用于看对象头的信息。

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.10</version>
</dependency>

下面的注释已经写的挺清楚的了,关于锁几种状态的转换。 

SyncSourceTest.java

package src.source;import org.openjdk.jol.info.ClassLayout;/*** Created by test on 2020/5/10*/
public class SyncSourceTest {static Object noLock;static Object biaseLock;static Object lightLock;static Object heavyLock;public static void main(String[] args) throws InterruptedException {noLock = new Object();// 无锁状态,由于print 方法是synchronize 修饰,其实打印语句就已经是加偏向锁了(如果满足下面的偏向锁条件)System.out.print("线程["+Thread.currentThread().getName()+"]:无锁状态对象布局:"+ClassLayout.parseInstance(noLock).toPrintable());// 偏向锁,由于JVM 默认偏向锁4s后开启,可以线程sleep.5 或者设置VM参数关闭延迟 -XX:BiasedLockingStartupDelay=0Thread.sleep(5000L);biaseLock = new Object();System.out.println("线程["+Thread.currentThread().getName()+"]:偏向锁状态对象布局:"+ClassLayout.parseInstance(biaseLock).toPrintable());// 轻量级锁,由于轻量级锁是偏向锁升级的,需要先给对象一个偏向锁,如果不加偏向锁,只有一个线程加锁变成偏向锁lightLock = new Object();synchronized (lightLock) {System.out.println("线程["+Thread.currentThread().getName()+"]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:"+ClassLayout.parseInstance(lightLock).toPrintable());}synLight();// 重量级锁heavyLock = new Object();synHeavy();}public static void synLight() throws InterruptedException {for (int i = 0; i < 1; i++) {getLightLock();}}public static void getLightLock() {new Thread(() -> {try {synchronized (lightLock){System.out.println("线程["+Thread.currentThread().getName()+"]:轻量级锁状态对象布局:"+ClassLayout.parseInstance(lightLock).toPrintable());}} catch (Exception e) {e.printStackTrace();}}).start();}public static void synHeavy() throws InterruptedException {for (int i = 0; i < 2; i++) {getHeavyLock();}}private static void getHeavyLock() {new Thread(() -> {try {synchronized (heavyLock){System.out.println("线程["+Thread.currentThread().getName()+"]:重量级锁状态对象布局:"+ClassLayout.parseInstance(heavyLock).toPrintable());}} catch (Exception e) {e.printStackTrace();}}).start();}
}

关于对象布局,我们就先不研究了,这里重点说一下 对象头

HotSpot虚拟机的对象头(Object Header)分为两部分,第一 部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄(Generational GC Age) 等。这部分数据的长度在32位和64位的Java虚拟机中分别会占用32个或64个比特,官方称它为Mark Word”。这部分是实现轻量级锁和偏向锁的关键。另外一部分用于存储指向方法区对象类型数据的指 针,如果是数组对象,还会有一个额外的部分用于存储数组长度。
运行之后我们看一下输出信息:
线程[main]:无锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
线程[main]:偏向锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[main]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           05 28 e3 02 (00000101 00101000 11100011 00000010) (48441349)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-2]:重量级锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           ba ee 0d 26 (10111010 11101110 00001101 00100110) (638447290)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-0]:轻量级锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           88 f5 a4 29 (10001000 11110101 10100100 00101001) (698676616)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total线程[Thread-1]:重量级锁状态对象布局:java.lang.Object object internals:OFFSET  SIZE   TYPE DESCRIPTION                               VALUE0     4        (object header)                           ba ee 0d 26 (10111010 11101110 00001101 00100110) (638447290)4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes totalProcess finished with exit code 0

可以看出 无锁状态下各个状态下 mark word 后三位的值:

无锁:001

偏向:101

轻量级锁:000

重量级锁:010

本来想写一下,关于 轻量级锁 当前线程栈帧中 lock record 和 mark word的变化,无奈查了很多资料不知道在哪可以看到 lock record,有的说是显式或者隐式地创建lock record 空间,咱也不清楚了。更多关于轻量级锁的源码看这篇吧。

https://blog.csdn.net/z69183787/article/details/104502540?utm_source=app

3. 编译class文件

看下面的class文件,顺便说一下jvm的字节码指令。

可以看下 class文件里边对象的变化:

 7: putstatic     #3                  // Field noLock:Ljava/lang/Object; 静态变量 初始化时

39: getstatic     #3                  // Field noLock:Ljava/lang/Object; 获取 静态变量

而到了偏向锁对象初始化之前,线程 睡眠了5秒。

57: ldc2_w        #16                   // long 5000l ,5000入栈
60: invokestatic  #18                 // Method java/lang/Thread.sleep:(J)V , 执行 sleep

135: monitorenter 对应的这行代码 :synchronized (lightLock)

184: monitorexit  加锁结束

190: monitorexit  后面又有一次 加锁结束

原因是 线程内部加锁后,调用 print 方法,又加了一次锁(重入锁),所以需要释放两次。

D:\gitee\rep\leetcode-gradle\src\main\java\src\source> javac -classpath ".;D:\dev\repository\org\openjdk\jol\jol-core\0.10\jol-core-0.10.jar"  -encoding UTF-8 .\SyncSourceTest.javaD:\gitee\rep\leetcode-gradle\src\main\java\src\source> javap -c .\SyncSourceTest.class
Compiled from "SyncSourceTest.java"
public class src.source.SyncSourceTest {static java.lang.Object noLock;static java.lang.Object biaseLock;static java.lang.Object lightLock;static java.lang.Object heavyLock;public src.source.SyncSourceTest();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]) throws java.lang.InterruptedException;Code:0: new           #2                  // class java/lang/Object3: dup4: invokespecial #1                  // Method java/lang/Object."<init>":()V7: putstatic     #3                  // Field noLock:Ljava/lang/Object;10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;13: new           #5                  // class java/lang/StringBuilder16: dup17: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V20: ldc           #7                  // String 线程[22: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;25: invokestatic  #9                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;28: invokevirtual #10                 // Method java/lang/Thread.getName:()Ljava/lang/String;31: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;34: ldc           #11                 // String ]:无锁状态对象布局:36: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;39: getstatic     #3                  // Field noLock:Ljava/lang/Object;42: invokestatic  #12                 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;45: invokevirtual #13                 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;48: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;51: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;54: invokevirtual #15                 // Method java/io/PrintStream.print:(Ljava/lang/String;)V57: ldc2_w        #16                 // long 5000l60: invokestatic  #18                 // Method java/lang/Thread.sleep:(J)V63: new           #2                  // class java/lang/Object66: dup67: invokespecial #1                  // Method java/lang/Object."<init>":()V70: putstatic     #19                 // Field biaseLock:Ljava/lang/Object;73: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;76: new           #5                  // class java/lang/StringBuilder79: dup80: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V83: ldc           #7                  // String 线程[85: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;88: invokestatic  #9                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;91: invokevirtual #10                 // Method java/lang/Thread.getName:()Ljava/lang/String;94: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;97: ldc           #20                 // String ]:偏向锁状态对象布局:99: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;102: getstatic     #19                 // Field biaseLock:Ljava/lang/Object;105: invokestatic  #12                 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;108: invokevirtual #13                 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;111: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;114: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;117: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V120: new           #2                  // class java/lang/Object123: dup124: invokespecial #1                  // Method java/lang/Object."<init>":()V127: putstatic     #22                 // Field lightLock:Ljava/lang/Object;130: getstatic     #22                 // Field lightLock:Ljava/lang/Object;133: dup134: astore_1135: monitorenter136: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;139: new           #5                  // class java/lang/StringBuilder142: dup143: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V146: ldc           #7                  // String 线程[148: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;151: invokestatic  #9                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;154: invokevirtual #10                 // Method java/lang/Thread.getName:()Ljava/lang/String;157: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;160: ldc           #23                 // String ]:[轻量级锁提前加偏向锁]轻量级锁状态对象布局:162: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;165: getstatic     #22                 // Field lightLock:Ljava/lang/Object;168: invokestatic  #12                 // Method org/openjdk/jol/info/ClassLayout.parseInstance:(Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;171: invokevirtual #13                 // Method org/openjdk/jol/info/ClassLayout.toPrintable:()Ljava/lang/String;174: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;177: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;180: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V183: aload_1184: monitorexit185: goto          193188: astore_2189: aload_1190: monitorexit191: aload_2192: athrow193: invokestatic  #24                 // Method synLight:()V196: new           #2                  // class java/lang/Object199: dup200: invokespecial #1                  // Method java/lang/Object."<init>":()V203: putstatic     #25                 // Field heavyLock:Ljava/lang/Object;206: invokestatic  #26                 // Method synHeavy:()V209: returnException table:from    to  target type136   185   188   any188   191   188   anypublic static void synLight() throws java.lang.InterruptedException;Code:0: iconst_01: istore_02: iload_03: iconst_14: if_icmpge     167: invokestatic  #27                 // Method getLightLock:()V10: iinc          0, 113: goto          216: returnpublic static void getLightLock();Code:0: new           #28                 // class java/lang/Thread3: dup4: invokedynamic #29,  0             // InvokeDynamic #0:run:()Ljava/lang/Runnable;9: invokespecial #30                 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V12: invokevirtual #31                 // Method java/lang/Thread.start:()V15: returnpublic static void synHeavy() throws java.lang.InterruptedException;Code:0: iconst_01: istore_02: iload_03: iconst_24: if_icmpge     167: invokestatic  #32                 // Method getHeavyLock:()V10: iinc          0, 113: goto          216: return
}

4.  总结

有很多文章对 synchronize 分析过,我这里只是想使用代码演示一下各种场景,很多地方并没有深入到源码和原理层面。

简单来说,就是:

无锁:mark word 记录 hashcode和分代年龄。

单线程加锁(偏向锁),mark word 记录线程id。

偏向锁升级到 轻量级锁,mark word 值 替换为 当前线程栈中的lock record 的指针。

轻量级锁到重量级锁:mark word 值 重量级锁 的指针。

其中自旋锁是 轻量级锁到重量级锁 发生的:

CAS操作尝试把对象的Mark Word更新为指向Lock Record的指针,如果成功了,就是轻量级锁,失败了,就变成重量级锁。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php opcache 详解

PHP性能提升之OPcache相关参数详解 工具 memory 发布于December 15, 2016 标签: PHPOPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能&#xff0c; 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。 PHP 5.5.0 及后续版本中已经绑定…

es elasticsearch 几种常见查询场景 二次分组 java读取es的查询json文件

大家好&#xff0c;我是烤鸭&#xff1a; es中几种常见的查询场景,使用java读取es的json文件进行查询。 es 中文使用手册。https://www.elastic.co/guide/cn/elasticsearch/guide/current/foreword_id.html 1. 从最简单的查询开始 GET /_search {"hits" : {&qu…

阿里云服务器邮件发送

一个邮件发送的功能&#xff0c;本机调试无问题&#xff0c;但发布到阿里云服务器后邮件发送功能失败。 网上查了下大概是说阿里云把发送邮件的25端口禁用掉了 那么解决方式一就是向阿里云申请开放25端口&#xff0c;但具体如何申请&#xff0c;并未深入操作。 解决方式二&…

全链路追踪竟然如此简单? bytebuddy搭建全链路追踪的demo 附代码

大家好&#xff0c;我是烤鸭&#xff1a; 最近一直在研究全链路追踪&#xff0c;比如cat、skywalking、zipkin等。 发现 skywalking 是基于bytebuddy 实现的&#xff0c;想自己试着写一下demo。 demo的git地址,感兴趣的可以自己试下。代码在idea中可以跑,至于其他场…

echarts地图的基本使用配置

一、空气质量图 代码和配置如下&#xff1a; <template><div class"box"><div id"map"></div></div> </template><script>import china from echarts/map/js/china.js export default {data(){return {}},mount…

从源码角度分析下 micrometer 自定义 metrics endpoint 和 springboot actuator

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享下 micrometer 的源码&#xff0c;和springboot集成 自定义endpoint 的使用。 1. 文档信息 官方文档&#xff1a; http://micrometer.io/docs github&#xff1a; https://github.com/micrometer-metrics/micrometer s…

云打码

1、云打码平台注册开发者模式用户登录 2、建立项目&#xff0c;下载项目案列代码接口 代码如下&#xff1a; 1 import http.client, mimetypes, urllib, json, time, requests2 3 ######################################################################4 5 class YDMHttp:6 …

Perhaps you are running on a JRE rather than a JDK? 关于 idea maven 缓存的问题 清理 idea maven 缓存

大家好&#xff0c;我是烤鸭&#xff1a; 1. 先检查是否环境变量的问题 参考这篇 https://blog.csdn.net/mingjie1212/article/details/106963143 2. 如果确定环境变量没问题 执行maven install的时候报错&#xff0c;Perhaps you are running on a JRE rather than a JDK …

swift - 使用系统app导航

import UIKit//1.导入框架 import MapKitclass ViewController: UIViewController {lazy var geoCoder : CLGeocoder {return CLGeocoder()}()override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {geoCoder.geocodeAddressString("广州&…

springcloud gateway 使用nacos 作为配置中心 和 注册中心

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享下 springcloud gateway 使用nacos作为配置中心和注册中心&#xff0c;主要是还是配置中心。 源码下载&#xff1a; https://gitee.com/fireduck_admin/springcloud-gateway-nacos-demo 1. 本地部署nacos 下载 https://g…

springboot 拦截器的坑 WebMvcConfigurationSupport 失效

大家好&#xff0c;我是烤鸭&#xff1a; 今天遇到一个拦截器失效的问题&#xff0c;具体看源码分析下。 环境: springboot 2.x spring 5.x 1. 先说下业务场景 需求是对请求进入时和离开时对和线程id绑定&#xff0c;用的Threadlocal&#xff0c;现在有一个问题&#xff0…

skywalking 源码解析——多线程变量传递 EnhancedInstance

大家好&#xff0c;我是烤鸭&#xff1a; 今天分享下 skywalking源码&#xff0c;正好自己用到相关的内容了。 1. 拦截点 三个主要的拦截器、构造方法、静态方法和示例方法&#xff0c;每个切面里都可以重写这些方法&#xff0c;并且指定进入的拦截器。 2. trace 相关内容 …

2018-2019-1 20165303 实验五 通讯协议设计

任务一 Linux下OpenSSL的安装与使用 前往OpenSSL官网&#xff0c;选择打开OpenSSL源码下载地址&#xff0c;按照下图所示方法下载压缩包“openssl-master.zip Linux下使用unzip openssl-master.zip命令解压 安装的具体命令如下&#xff1a;$ ./config$ make$ make test$ make i…

从字节码看 finally关键字、异常表

大家好&#xff0c;我是烤鸭&#xff1a; 今天说下 finally 这个关键字。 1. 认识finally finally 总是跟 try、catch一起出现&#xff0c;finally是执行方法结束一定要执行的代码&#xff0c;比如流关闭等等。 finally是如何实现在异常捕捉之后保证执行 finally 代码块里的…

Unhandled exception: org.springframework.beans.factory.BeanDefinitionStoreException

大家好&#xff0c;我是烤鸭&#xff1a; ​ 使用 idea 莫名其妙的错误。 无法编译 异常已经 catch 住了&#xff0c;提示明显是有问题的。 再看一下 maven install 的结果 Error:(99, 100) java: 无法访问org.springframework.core.env.EnvironmentCapable 找不到org.spr…

springcloud gateway 源码解析、请求响应流程、第三方响应结果在 gateway 的经过

大家好&#xff0c;我是烤鸭&#xff1a; 1. 官方介绍 官方文档&#xff1a; 看的是 2.2.5.RELEASE 版本的 https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/ 看一下官方这段说明&#xff0c;gateway 使用的是 webflux 和 reactor&#x…

改logback logstash-logback-encoder 框架本身的日志级别

大家好&#xff0c;我是烤鸭&#xff1a; 最近遇到一个问题&#xff0c;想把logback框架本身的日志级别修改&#xff0c;需要 logstash-logback-encoder 6.1 以上的版本才可以。 直接上代码 这里修改的不是业务日志级别&#xff0c;是 logback 框架本身(确切地说是 logstash…

idea首次创建新模块的详细操作

依赖网址:https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/3.1.0 https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api/2.3.1 https://mvnrepository.com/artifact/org.springframework/spring-webmvc 创建文件夹 修改版本号 配…

markdown 常用语法总结 - 个人版

这里并不是要总结所有的 markdown 语法&#xff0c;只是总结笔者自己撰写博客时常用的一些 markdown 语法。 1 图片设置 1.1 设置图片位置 利用markdown在编写文档时插入图片是默认靠左&#xff0c;有些时候将图片设置为居中时可以更加的美观&#xff0c;这时就需要在图片的信息…

PostgreSQL 、springboot 、spring data jpa 集成

项目地址&#xff1a;https://gitee.com/zhxs_code/PostgreSQL_springboot_jpa_demo.git 增删查改都已经实现。 重点部分&#xff1a; 1.定义自己的方言。 1 package com.zxl.postgrespringdemo.config.dialect;2 3 import org.hibernate.dialect.PostgreSQL94Dialect;4 import…