Spring Boot中如何在@Indexed注解内使用@Value配置Mongo TTL
解决MongoDB TTL索引配置不生效问题
问题根源
你遇到的核心问题是:@Indexed的expireAfter参数要求long类型的毫秒数,但你配置的10d是字符串格式,直接通过SpEL或属性绑定无法自动转换为符合要求的数值;同时Java的Duration解析需要标准ISO格式,而非自定义的10d写法。
可行解决方案
方案1:使用标准ISO Duration格式+SpEL解析
修改配置文件为Java Duration支持的ISO-8601格式:
mongo: data: expire: days: PT10D # PT10D表示10天,P代表周期,T代表时间部分,D代表天
实体类中通过SpEL将Duration转换为毫秒数:
@Document(collection = "Test") public class Test{ @Id private String id; @Indexed(name = "expire_at", expireAfter = "#{T(java.time.Duration).parse('${mongo.data.expire.days}').toMillis()}") private Instant expireAt; }
方案2:自定义配置类解析10d格式
如果你想保留10d的配置写法,创建一个配置类来解析转换:
@Component("mongoTTLConfig") public class MongoTTLConfig { @Value("${mongo.data.expire.days}") private String expireConfig; public long getExpireMillis() { // 解析10d、3h这类简单格式,这里只处理天的情况 long value = Long.parseLong(expireConfig.replaceAll("[^0-9]", "")); String unit = expireConfig.replaceAll("[0-9]", ""); return switch (unit) { case "d" -> value * 24 * 60 * 60 * 1000; case "h" -> value * 60 * 60 * 1000; case "m" -> value * 60 * 1000; default -> value; }; } }
然后实体类中引用配置类的方法:
@Document(collection = "Test") public class Test{ @Id private String id; @Indexed(name = "expire_at", expireAfter = "#{@mongoTTLConfig.getExpireMillis()}") private Instant expireAt; }
方案3:基于字段时间的TTL索引(如果你的需求是按expireAt字段值过期)
如果你的实际需求是当文档的expireAt字段时间到达后自动删除,而非创建后固定天数过期,那么只需将expireAfter设为0,然后在保存文档时给expireAt赋值:
@Document(collection = "Test") public class Test{ @Id private String id; @Indexed(name = "expire_at", expireAfter = 0) private Instant expireAt; }
在服务层保存时注入配置并设置过期时间:
@Service public class TestService { @Value("${mongo.data.expire.days}") private String expireDays; public void saveTest(Test test) { // 解析配置并设置expireAt为当前时间+指定天数 long days = Long.parseLong(expireDays.replace("d", "")); test.setExpireAt(Instant.now().plus(Duration.ofDays(days))); // 执行保存操作 } }
验证索引是否生效
配置完成后,登录MongoDB客户端执行以下命令,检查TTL索引是否正确创建:
db.Test.getIndexes()
查看输出中是否存在expire_at索引,且expireAfterSeconds值符合预期:
- 方案1/2中,10天对应
expireAfterSeconds为864000(102460*60) - 方案3中,
expireAfterSeconds为0
内容的提问来源于stack exchange,提问作者Susmitha
相关产品推荐
相关产品推荐

