You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Data R2DBC中映射PostgreSQL的'infinity'值到LocalDateTime

解决数据库'infinity'值与Java LocalDateTime的映射问题

你的场景是Java实体里定义了private LocalDateTime expireOn;,但数据库会在API没传值或传null时自动存'infinity',导致Java端映射报错,下面是几个直接可用的解决办法:

方案1:用JPA自定义属性转换器(适合Spring Data JPA场景)

写一个转换器类,自动把数据库的'infinity'转成Java的LocalDateTime最大值,反过来也能把null或最大值转成数据库的'infinity':

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.time.LocalDateTime;

@Converter(autoApply = true)
public class LocalDateTimeInfinityConverter implements AttributeConverter<LocalDateTime, String> {

    private static final String DB_INFINITY = "infinity";
    // 用LocalDateTime的最大值代表无限过期时间
    private static final LocalDateTime MAX_EXPIRE_TIME = LocalDateTime.MAX;

    @Override
    public String convertToDatabaseColumn(LocalDateTime entityValue) {
        if (entityValue == null || entityValue.equals(MAX_EXPIRE_TIME)) {
            return DB_INFINITY;
        }
        return entityValue.toString();
    }

    @Override
    public LocalDateTime convertToEntityAttribute(String dbValue) {
        if (dbValue == null || DB_INFINITY.equalsIgnoreCase(dbValue)) {
            return MAX_EXPIRE_TIME;
        }
        return LocalDateTime.parse(dbValue);
    }
}
  • 如果想让这个转换器全局生效,保留autoApply = true;如果只想给expireOn字段用,去掉autoApply,然后在字段上加@Convert(converter = LocalDateTimeInfinityConverter.class)。

方案2:MyBatis自定义类型处理器(适合MyBatis场景)

如果用MyBatis做持久层,写个类型处理器处理转换逻辑:

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;

@MappedTypes(LocalDateTime.class)
public class LocalDateTimeInfinityTypeHandler extends BaseTypeHandler<LocalDateTime> {

    private static final String DB_INFINITY = "infinity";
    private static final LocalDateTime MAX_EXPIRE_TIME = LocalDateTime.MAX;

    @Override
    public void setNonNullParameter(PreparedStatement ps, int index, LocalDateTime param, JdbcType jdbcType) throws SQLException {
        if (param.equals(MAX_EXPIRE_TIME)) {
            ps.setString(index, DB_INFINITY);
        } else {
            ps.setString(index, param.toString());
        }
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return parseDbValue(rs.getString(columnName));
    }

    @Override
    public LocalDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseDbValue(rs.getString(columnIndex));
    }

    @Override
    public LocalDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseDbValue(cs.getString(columnIndex));
    }

    private LocalDateTime parseDbValue(String dbValue) {
        if (dbValue == null || DB_INFINITY.equalsIgnoreCase(dbValue)) {
            return MAX_EXPIRE_TIME;
        }
        return LocalDateTime.parse(dbValue);
    }
}
  • 写完后在MyBatis配置文件里注册这个处理器,或者在ResultMap的字段上指定typeHandler属性即可。

方案3:数据库查询层面临时处理(适合快速调试)

如果不想改代码,可以在查询SQL里用CASE语句把'infinity'转成Java能解析的最大日期字符串:

SELECT 
    CASE WHEN expire_on = 'infinity' THEN '9999-12-31T23:59:59' ELSE expire_on END AS expireOn
FROM your_table;

不过这个方法需要修改所有涉及该字段的查询,灵活性不如代码层面的转换器。

内容的提问来源于stack exchange,提问作者Thirumal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:04:02