ORMLite持久化LocalDateTime失败及外键约束问题求助
一、LocalDateTime持久化解析异常问题
问题分析
从异常信息看,解析时拿到的是带毫秒的时间字符串2023-10-15T12:57:46.000,但你的自定义Persister用的是不带毫秒的格式yyyy-MM-dd'T'HH:mm:ss,导致解析失败。另外你说javaToSqlArg断点没触发,说明自定义Persister根本没被ORMLite启用,系统可能在用默认的时间类型处理器读写数据,才会出现带毫秒的字符串。
解决方案
- 强制指定字段使用自定义Persister
在实体类的LocalDateTime字段上,通过注解明确指定使用你的LocalDateTimePersister:
@DatabaseField(persisterClass = LocalDateTimePersister.class) private LocalDateTime createTime;
如果要全局注册,在初始化ORMLite时添加自定义类型:
DatabaseConfigUtil.addCustomType(LocalDateTime.class, LocalDateTimePersister.getSingleton());
- 兼容带毫秒的时间格式
修改自定义Persister的日期格式,让它能处理带/不带毫秒的时间字符串,同时移除无用的SimpleDateFormat(LocalDateTime是Java 8+API,用DateTimeFormatter足够):
public class LocalDateTimePersister extends TimeStampType { private static final LocalDateTimePersister SINGLETON = new LocalDateTimePersister(); // 兼容带毫秒的格式,[]表示可选部分 private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss[.SSS]"; private static final DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); private LocalDateTimePersister() { super(SqlType.STRING, new Class<?>[] { LocalDateTime.class }); } public static LocalDateTimePersister getSingleton() { return SINGLETON; } @Override public Object javaToSqlArg(FieldType fieldType, Object javaObject) { if (javaObject == null) { return null; } LocalDateTime dateTime = (LocalDateTime) javaObject; return dateTime.format(DT_FORMATTER); } @Override public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) { if (sqlArg == null) { return null; } return LocalDateTime.parse((String) sqlArg, DT_FORMATTER); } }
- 清理旧数据(如果需要)
如果数据库中存在之前用默认处理器写入的带毫秒数据,需要先清理或更新这些数据,避免解析失败。
二、外键约束不生效问题
问题分析
SQLite默认关闭外键约束,即使ORMLite生成了外键语句,数据库也不会强制执行。另外如果注解配置不完整,ORMLite可能不会生成外键约束。
解决方案
- 开启SQLite外键约束
在初始化数据库连接后,执行PRAGMA语句开启外键:
// 假设使用JdbcConnectionSource JdbcConnectionSource connectionSource = new JdbcConnectionSource("jdbc:sqlite:your-db.db"); // 开启外键约束 try (Connection conn = connectionSource.getReadOnlyConnection(); Statement stmt = conn.createStatement()) { stmt.execute("PRAGMA foreign_keys = ON;"); } catch (SQLException e) { // 处理异常 }
SQLite会为每个连接保留该设置,所以在初始化ConnectionSource时执行一次即可。
- 正确配置外键注解
在子实体类的父对象字段上,添加完整的外键注解,指定删除行为:
// 子实体类中的父对象字段 @DatabaseField( foreign = true, foreignColumnName = "id", // 父表的主键字段名 onDelete = ForeignCollectionField.ForeignDeleteAction.CASCADE // 删除父对象时自动删除子对象 ) private Parent parent;
如果需要关联查询,还可以添加foreignAutoRefresh = true。
- 重新生成数据表
如果之前的表是在未开启外键时创建的,需要删除旧表,让ORMLite重新生成带外键约束的表结构。
内容的提问来源于stack exchange,提问作者Maxim
相关产品推荐
相关产品推荐

