出于某些原因,服务器数据库需要迁移至 PostgreSQL
,顺带把Find Somebody Backend也进行技术升级了。
主要技术栈变动如下:
过去 | 现在 |
---|---|
Maven 3 | Gradle 8 |
Java 11 | Java 17 |
Spring Boot 2 | Spring Boot 3 |
Spring MVC | Spring WebFlux |
MySQL 8 | PostgreSQL 16.04 |
JVM | Native Image |
Maven -> Gradle
这还是挺顺利的。
说来令人笑话,玩Android开发快十年纯学会安装 Gradle
了。
Java 11 -> Java 17
常见语法都兼容,也没啥问题。
Spring Boot 2 -> Spring Boot 3
这还真遇到点问题了,需要上网检索。
找不到 @PostConstruct
Spring Boot 3 迁移到 Jakarta EE 9,@PostConstruct
从 javax.annotation
移动到了 jakarta.annotation
。
这在 Hibernate
高版本中也是一样的,其注解早已放在 jakarta
包下。
改名相关:
Spring MVC ->Spring WebFlux
此前对 Spring WebFlux
仅限于 WebClient
的使用,本次有了更多的接触。
弃用 HttpServletRequest
若平时使用 HttpServletRequest
获取请求头信息,而不是 @RequestHeader
。那么区别于 Spring MVC
,现在得这么写:
public static String getClientIpAddress(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
// 先检查 X-Forwarded-For 头
String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
return xForwardedFor.split(",")[0];
}
// 再检查 X-Real-IP 头
String xRealIp = request.getHeaders().getFirst("X-Real-IP");
if (xRealIp != null && !xRealIp.isEmpty()) {
return xRealIp;
}
// 否则直接获取远程地址
return request.getRemoteAddress() != null
? request.getRemoteAddress().getAddress().getHostAddress()
: "Unknown";
}
如果用不到响应信息或者上下文,也可以使用 ServerHttpRequest
。
HTTP接口返回 Mono<T>
WebFlux 是基于 Reactor 库构建的,支持异步和非阻塞的 I/O 操作。如果直接返回 String
,WebFlux 无法知道这个操作是同步还是异步的。返回 Mono<String>
让 WebFlux 知道这是一个异步操作,能够在请求完成时再返回结果。
@GetMapping("/get-token")
public Mono<String> getToken(ServerHttpRequest request) {
return Mono.just("token");
}
WebFlux 的目标是处理高并发请求,传统的阻塞模型无法充分利用 CPU 资源。而返回 Mono<T>
可以让请求处理异步化,避免线程等待 I/O 操作完成,提高性能。在 WebFlux 中,最好遵循响应式编程的模式,返回 Mono<T>
或 Flux<T>
,以便 WebFlux 框架能够管理异步请求和响应。
对于返回 Mono
的函数调用,建议使用 map (没有阻塞任务)/flatMap (有阻塞任务)
进行操作返回值,用法点像Dart中的 then
函数。在响应式链路中,值得一提的是,尽量不要存在 Mono
的阻塞操作,否则可能会引发运行时异常,还是挺头疼的。
MySQL 8 -> PostgreSQL 16.04
数据迁移
建议使用 pgloader ,简单迁移任务比datax好用不少。
一行命令搞定:
pgloader mysql://[user:password]@[host:port]/[db] postgresql://[user:password]@[host:port]/[db]
在迁移中遇到了一些小问题,比较值得记录的是,pgloader不支持MySQL8最新的鉴权模式,需要降级为老的鉴权插件,可以看这里:https://github.com/dimitri/pgloader/issues/782 。
scheme
PGSQL中有这么一个概念—— scheme
。
对比MySQL来说,像是在库和表之间还加了一层空间隔离,名为 scheme
。
在使用中,若没有隔离需求,可以直接把表建在名为 public
的默认 scheme
中。那么在使用上就和MySQL是一样的。若自行创建了新的 scheme
,那么在使用上就需要像这样:
-- 显式指定scheme名称
SELECT * FROM scheme_name.table_name;
官方文档:https://www.postgresql.org/docs/current/ddl-schemas.html
JVM -> Native Image
官方文档写的不错,直接按部就班就好:https://docs.spring.io/spring-boot/how-to/native-image/developing-your-first-application.html
编译本地原生程序可使用Spring推荐的JDK套件:https://bell-sw.com/pages/downloads/native-image-kit/
我遇到的问题是 fastjson2
作妖,折腾好久还是换到了Jackson以解决问题,好在只是使用 toJsonString()
,迁移成本不大。