尝试将Spring Boot的版本从2.6升级到3.0

既然Spring Boot官方宣称3.0是未来10年的基石,那我们也有必要做一些储备和尝试。笔者用当前生产部署的一个项目,建立git分支进行升级测试,这里做一个记录,后续逐渐完善。

具体的版本

Spring Boot 从2.6.13升级到3.0.1

Hibernate 6.0

目前的体会,Hibernate版本升级对这个项目的影响更大一些。
org.hibernate.type.Type 替换为 org.hibernate.type.BasicTypeReference
JpaRepository.getId(ID) Deprecated,已经过时了,用getReferenceById(ID)代替

session.createNativeQuery(sql) Deprecated,已经过时了,建议用session.createNativeQuery(sql, Class):

返回一个字段
1
2
3
4
5
6
7
8
9
10
11
12
String sql = "select code from some_table";
NativeQuery query = session.createNativeQuery(sql, BigInteger.class);
List<BigInteger> list = query.getResultList();
if (!list.isEmpty()) {
BigInteger code = list.get(0);
}

...
// 如果只取一个值则
query.setMaxResults(1);
Optional<BigInteger> optional = query.uniqueResultOptional();
BigInteger code = optional.orElse(BigInteger.valueOf(0));
返回多个字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NativeQuery query = session.createNativeQuery("select sd_code, sd_name from seal_data", Long.class);
query.addScalar("sd_name", StandardBasicTypes.STRING);
query.addScalar("sd_code", Long.class);
query.setMaxResults(1);
List<Object[]> rows = query.getResultList();
if (!rows.isEmpty()) {
Object[] row = rows.get(0);
long code1 = (Long)row[0];
String name = (String)row[1];
long code2 = (Long)row[2];

// createNativeQuery方法里的returnClass是用来转换第一个字段
// addScalar则是后续的字段,并且addScalar的顺序就是返回值的顺序
logger.debug("code1: {}, name: {}, code2: {}", code1, name, code2);
}

Jackson

PropertyNamingStrategy.SNAKE_CASE -> PropertyNamingStrategies.SNAKE_CASE

包名修改:javax -> jakarta

注意不要统一替换,编译发现问题才替换

javax.persistence.* -> jakarta.persistence.*
javax.validation.* -> jakarta.validation.*
javax.servlet.* -> jakarta.servlet.*
javax.annotation.* -> jakarta.annotation.*
javax.transaction* -> jakarta.transaction.*

Spring Security(SecurityFilterChain)

2.7之前是WebSecurityConfigurerAdapter,之后都是SecurityFilterChain

antMatchers -> requestMatchers

application.yml

Excpetion: Unable to resolve name [org.hibernate.dialect.PostgreSQL10Dialect]

如果配置了spring.jpa.database,则 spring.jpa.database-platform 可以删除掉,因为 database-platform 可以自动检测,如果指定了又因为版本原因找不到,就会导致异常
这其实也可以归到Hibernate的升级下

过时的类或者方法

LocalVariableTableParameterNameDiscoverer -> StandardReflectionParameterNameDiscoverer
Base64Utils.encodeToString -> Base64.getEncoder().encodeToString
StringUtils.trimWhitespace -> String.strip,但没有判断null值,故无法简单替代

升级失败

应用启动一段时间之后,报异常org.springframework.transaction.CannotCreateTransactionException:
Could not open JDBC Connection for transaction,暂时无解。
初步分析是一些第三方的库还没跟上Spring Boot 3.0的步伐,后续有时间了逐一排查,才能定位到具体的第三方库。