Marshal.load生成的ApplicationRecord调用save!无法写入数据库的原因
Rails跨数据库实例保存问题解析
为什么必须重新创建实例才能写入数据库?
当你用Marshal.dump(MyModel.all)导出数据时,序列化的是原服务器上已经持久化到数据库的ActiveRecord实例。这些实例内部带着ActiveRecord的核心状态标记:
@persisted被设为true,表示该记录已存在于数据库中@new_record被设为false- 同时包含原数据库生成的主键ID
在新服务器用Marshal.load加载这些实例后,ActiveRecord会直接沿用这些状态,认定这些记录已经存在于当前数据库。此时调用save!,ActiveRecord会执行UPDATE语句尝试更新对应ID的记录,但新数据库里根本没有这个ID的记录,所以这条更新语句不会修改任何行数据。
而用MyModel.new(x.attributes)创建新实例时,实例的状态会被完全重置:
@persisted为false,@new_record为true- ActiveRecord会将其识别为“未持久化的新记录”,调用
save!时会执行INSERT语句,把数据插入到新数据库中。
为什么save!返回true但数据库无变化?
save!的返回逻辑很直接:只要没有触发验证错误、回调失败或数据库异常(比如主键冲突、SQL语法错误),就会返回true。
对于加载后的旧实例,执行的是UPDATE操作——即使这条UPDATE语句没有匹配到任何记录(影响行数为0),ActiveRecord默认不会把这种情况视为错误,所以save!仍然返回true,但实际上没有任何数据被写入数据库。只有当操作触发了明确的错误时,save!才会抛出异常,不会返回true。
内容的提问来源于stack exchange,提问作者iftheshoefritz
相关产品推荐
相关产品推荐

