JPA - 保存后自动生成的字段为空
Posted
技术标签:
【中文标题】JPA - 保存后自动生成的字段为空【英文标题】:JPA - Auto-generated field null after save 【发布时间】:2018-05-14 02:08:47 【问题描述】:我有一个Account
实体,我正在尝试使用save
函数来持久化它。我的代码:
@Override
public Account createAccount(String pin)
Account account = new Account();
account.setBalance(0L);
account.setPin(pin);
return accountRepository.save(account);
现在我的实体类有一个名为accountNumber
的自动生成字段。我的实体类:
@Entity
@Table(name = "accounts")
@Data
public class Account
@Column(name = "account_number", length = 32, insertable = false)
private String accountNumber;
private Long balance;
现在调用save
后,返回的实体有accountNumber
和null
,但我可以在intellij 数据库视图中看到它实际上不为空。所有其他自动生成的字段(如 id
等)都存在于返回的实体中,只是 accountNumber
为空。 accountNumber 的默认值在 sql 文件中设置:
ALTER TABLE accounts
ALTER COLUMN account_number SET DEFAULT DefaultValueSerializer(TRUE, TRUE, 12);
这里,DefaultValueSerializer
是生成帐号的函数。
我已经尝试过其他可用的解决方案,例如使用 saveAndFlush()
等,但在我的情况下没有任何效果。可能是什么问题?
【问题讨论】:
因为 hibernate 不是这样工作的,所以它对在您的数据库中自动生成列一无所知,并且不会像这样自动更新值。您需要从数据库中重新检索Account
以获取该字段。
@M.Deinum 也试过了。保存后,我使用findOne
函数检索帐户。令人惊讶的是,返回的 accountNumber
仍然是 null
。由于某种原因,findOne
不会导致选择查询,因为我看不到任何由于findOne
函数调用而记录的休眠查询。
因为,正如您所注意到的,它不会从数据库中检索它。使用 ORM 工具,如果具有请求 id 的所需实体已存在于缓存中,则该工具将首先检查一级缓存,并且您可以获得该实例。您首先必须清除缓存 (entitymanager.clear()
) 并重新加载它或 refresh
(entityManager.refresh
) 实体。
你确实是对的。我最终为accountNumber
字段使用了@Generated(value = INSERT)
注释。它让 JPA 知道该值是在插入期间生成的,因此它将在保存后再次从数据库中查询该值以获取更新的值。感谢您为我指明正确的方向。
注解@Generated
似乎是hibernate
特定的所以不是JPA
。
【参考方案1】:
正如评论中提到的,Hibernate 不知道数据库引擎级别发生了什么,因此它看不到生成的值。
将帐号的生成转移到 JPA 级别而不是使用数据库默认值是明智的。
我建议你研究注解@GeneratedValue
和相关的东西,比如@SequenceGenerator
。这样生成帐号的控制在JPA级别,保存后不需要刷新实体之类的东西。
一个起点:Java - JPA - Generators - @SequenceGenerator
对于非 id 字段,可以在使用 @PrePersist
注释的方法中生成值,正如其他答案所建议的那样,但您可以在 Account
s 构造函数中进行初始化。
另请参阅this answer 了解选项。
【讨论】:
这不起作用,因为@GeneratedValue
仅适用于 @Id
字段。
好的,你还有其他的@ID 字段吗?帐号是否不唯一或无法用作 ID?【参考方案2】:
您可以在将其字段设置为其默认值的实体内创建一个带注释的@PrePersist 方法。
这样 jpa 就会知道默认值。
对于不同的实体生命周期事件https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.html,还有其他此类注释可用
附:如果您决定采用这种方式,请记住删除insertable = false
【讨论】:
【参考方案3】:使用
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
为您的 ID。并将您的储蓄留给saveAndFlush
,这样您就可以立即看到更改(如果有)。我还建议将 ID 和帐号分开。它们不应该相同。尝试调试您的程序并查看值停止传递的位置。
【讨论】:
以上是关于JPA - 保存后自动生成的字段为空的主要内容,如果未能解决你的问题,请参考以下文章
jpa如何设置某个字段存到数据库后不能修改,当然整个对象删除除外!
Jpa + Spring - 从数据库读取后自动设置瞬态字段值
从联系人中选择自动填充地址后,iOS UITextField 文本字段为空