Hibernate 7 随 Spring Boot 4 一起上来了。升级之后表结构会变吗?HQL 结果会变吗?哪些写法编译不过?这篇在 MySQL 上用同一份实体对比 Hibernate 6.6 与 7.2。
3.5.16:启动成功
表:['child', 'child_seq', 'item', 'item_seq', 'parent', 'parent_seq']
生成的 DDL 语句数(日志里 create/alter/drop 开头的 Hibernate: 行):14
4.0.8:启动成功
表:['child', 'child_seq', 'item', 'item_seq', 'parent', 'parent_seq']
生成的 DDL 语句数(日志里 create/alter/drop 开头的 Hibernate: 行):14
逐表逐列对比 show create table(只列出两个版本不同的行):
有差异的表 0 个
item 表的列定义(两个版本一样):
`active` bit(1) NOT NULL
`day` date DEFAULT NULL
`dur` decimal(21,0) DEFAULT NULL
`ord` tinyint DEFAULT NULL
`price` decimal(38,2) DEFAULT NULL
`qty` int DEFAULT NULL
`ratio` double DEFAULT NULL
`created` datetime(6) DEFAULT NULL
`id` bigint NOT NULL
`off` datetime(6) DEFAULT NULL
`seen` datetime(6) DEFAULT NULL
`zoned` datetime(6) DEFAULT NULL
`uid` binary(16) DEFAULT NULL
`name` varchar(255) DEFAULT NULL
`data` varbinary(255) DEFAULT NULL
`big` longtext
`label` enum('GREEN','RED') DEFAULT NULL
PRIMARY KEY (`id`)
CONSTRAINT `item_chk_1` CHECK ((`ord` between 0 and 1))两个版本生成的表和 DDL 完全一致。
4.0.8 + validate 对着 3.5.16 建的库:启动成功,没有报错 4.0.8 + update 对着 3.5.16 建的库:启动成功;执行的 DDL 语句 0 条 update 之后各表的 show create table 是否有变化:False(对比的是 update 之前与之后)
3.5.16 建的库,4.0.8 validate 通过、update 不执行 DDL。
3.5.16:join fetch + setMaxResults(2):返回 2 个 Parent,各自 children 数 [2, 2];日志:o.h.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory 4.0.8:join fetch + setMaxResults(2):返回 2 个 Parent,各自 children 数 [2, 2];日志:o.h.orm.query - HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory 3.5.16 + hibernate.query.fail_on_pagination_over_collection_fetch=true:join fetch + setMaxResults(2):异常 HibernateException → HibernateException: setFirstResult() or setMaxResults() specified with collection fetch join (in-memory pagination was about to be applied, but 'hibernate.query.fail_on_pagination_over_collection_fetch' is enabled) 4.0.8 + hibernate.query.fail_on_pagination_over_collection_fetch=true:join fetch + setMaxResults(2):异常 HibernateException → HibernateException: setFirstResult() or setMaxResults() specified with collection fetch join (in-memory pagination was about to be applied, but 'hibernate.query.fail_on_pagination_over_collection_fetch' is enabled)
join fetch 加分页都是内存分页并警告,可以用 fail_on_pagination_over_collection_fetch 变成抛异常。
相同:select count(i) from Item i → 1 行,首行 Long 3
相同:select i.name from Item i where i.id = ?1 [参数 Long 1] → 1 行,首行 String a
相同:select i.name from Item i where i.id = ?1 [参数 Integer 1] → 1 行,首行 String a
相同:select i.name from Item i where i.id = ?1 [参数 String 1] → 1 行,首行 String a
相同:select i.name from Item i where i.price > :p [参数 Integer 1] → 3 行,首行 String a
不同:select i.name from Item i where i.price > :p [参数 String abc]
6.6 → 异常 IllegalArgumentException → NumberFormatException: For input string: "abc"
7.2 → 异常 QueryArgumentException: Argument to query parameter has an incompatible type (java.lang.String is not assignable to java.math.BigDecimal)
相同:select i.name from Item i where i.id in :ids [参数 空 List] → 0 行,首行 null
相同:select i.name from Item i where i.ord = 'RED' → 异常 IllegalArgumentException → SemanticException: Cannot compare left expression of type 'demo.Color' with right expression of type 'java.lang.String'
相同:select i.name from Item i where i.label = 'GREEN' → 3 行,首行 String a
相同:select i.name from Item i order by i.id desc limit 2 → 2 行,首行 String c
相同:select i.name from Item i where i.name = ? → 异常 IllegalArgumentException → ParameterLabelException: Unlabeled ordinal parameter ('?' rather than ?1)
相同:select i.qty / 2 from Item i where i.name = 'a' → 1 行,首行 Integer 2
相同:select i.qty // 2 from Item i where i.name = 'a' → 异常 IllegalArgumentException → SyntaxException: At 1:14 and token '/', no viable alternative at input 'select i.qty /*/ 2 from Item i where i.name = 'a
相同:select max(i.id) + 1.5 from Item i → 1 行,首行 Double 4.5
相同:select sum(i.qty) from Item i → 1 行,首行 Long 21
相同:select avg(i.qty) from Item i → 1 行,首行 Double 7.0
相同:select cast(i.id as String) from Item i where i.name = 'a' → 1 行,首行 String 1
相同:select i.qty * 1.0 from Item i where i.name = 'a' → 1 行,首行 Double 5.0
相同:select i.name from Item i where i.name = null → 0 行,首行 null
相同:select i.name from Item i where i.name like 'a%' escape '!' → 1 行,首行 String a
相同:select i from Item i where i.id = 1 and i.big is null → 1 行,首行 Item Item#1
相同:from Item where qty > 1 → 3 行,首行 Item Item#1
共 22 条,结果不同的 1 条22 条里 21 条一致,仅参数类型不匹配的异常类型不同。
3.5.16 + hibernate.dialect=org.hibernate.dialect.MySQL8Dialect:启动成功
4.0.8 + hibernate.dialect=org.hibernate.dialect.MySQL8Dialect:启动失败 Caused by: java.lang.ClassNotFoundException: Could not load requested class: org.hibernate.dialect.MySQL8Dialect
3.5.16 + hibernate.dialect=org.hibernate.dialect.MySQLDialect:启动成功
4.0.8 + hibernate.dialect=org.hibernate.dialect.MySQLDialect:启动成功
Hibernate 专有写法编译:6.6 通过 20 / 24;7.2 通过 15 / 24
org.hibernate.annotations.Where:6.6→通过;7.2→失败(cannot find symbol)
org.hibernate.annotations.Type(type=…):6.6→失败(cannot find symbol);7.2→失败(cannot find symbol)
org.hibernate.annotations.Proxy:6.6→通过;7.2→失败(cannot find symbol)
org.hibernate.criterion.Restrictions(旧 Criteria):6.6→失败(package org.hibernate.criterion does not);7.2→失败(package org.hibernate.criterion does not)
org.hibernate.Criteria:6.6→失败(cannot find symbol);7.2→失败(cannot find symbol)
Session#save(Object):6.6→通过;7.2→失败(cannot find symbol)
Session#saveOrUpdate(Object):6.6→通过;7.2→失败(cannot find symbol)
org.hibernate.dialect.MySQL8Dialect:6.6→通过;7.2→失败(cannot find symbol)
org.hibernate.dialect.PostgreSQL95Dialect:6.6→失败(cannot find symbol);7.2→失败(cannot find symbol)MySQL8Dialect、@Where、@Proxy、Session.save、saveOrUpdate 在 7.2 里没有了。