我尝试通过以下方式保留对数据库的更改:
实体
我有一个具有 JSON 数据类型的 JPA 实体:
@Entity
public class TestEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@NotNull
@Convert(converter = TestConverter.class)
@Column(name = "data", columnDefinition = "JSON")
private TestData data;
...
}
TestData
实体定义如下:
public class TestData {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestData testData = (TestData) o;
return Objects.equals(value, testData.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
转换器
TestData 的转换器是这样实现的:
@Converter
public class TestConverter implements AttributeConverter<TestData, String> {
private static final Logger logger = LoggerFactory.getLogger(TestConverter.class);
private static final Jsonb jsonb = JsonbBuilder.create();
@Override
public String convertToDatabaseColumn(TestData attribute) {
logger.debug("To JSON: {}", attribute);
return jsonb.toJson(attribute);
}
@Override
public TestData convertToEntityAttribute(String dbData) {
logger.debug("From JSON: {}", dbData);
return jsonb.fromJson(dbData, TestData.class);
}
}
服务
最后我有一个服务正在尝试修改数据库中的现有实体:
@ApplicationScoped
public class Service {
private static final Logger logger = LoggerFactory.getLogger(Service.class);
@Inject
public EntityManager entityManager;
@Transactional
public void modify(Long id) {
TestEntity entity = entityManager.find(TestEntity.class, id);
entity.getData().setValue("new");
logger.debug("Modified: {}", entity);
}
}
配置
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:33003/test?sessionVariables=FOREIGN_KEY_CHECKS=0&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull" />
<property name="javax.persistence.jdbc.user" value="db-user" />
<property name="javax.persistence.jdbc.password" value="db-pass" />
<property name="javax.persistence.schema-generation.database.action" value="update"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.connection.provider_disables_autocommit" value="false"/>
问题
问题是new
值没有保存到数据库中。这是我在日志中看到的内容:
2019-11-30 12:19:40,065 DEBUG [org.acm.TestConverter] From JSON: {"value":"hello"}
2019-11-30 12:19:40,068 DEBUG [org.acm.TestConverter] To JSON: TestData{value='hello'}
2019-11-30 12:19:40,069 DEBUG [org.acm.TestConverter] From JSON: {"value":"hello"}
2019-11-30 12:19:40,071 DEBUG [org.acm.Service] Modified: TestEntity{id=2, data=TestData{value='new'}}
这是打开 hibernate 日志记录的日志文件(太多内容无法在此处粘贴,因此我发布了一个链接):https://pastebin.com/1e3URx8W
我尝试过的
这是我尝试过的一些事情:
- 将
entityManager.persist(entity);
添加到modify
函数末尾 -> 无变化(预期) - 向
TestData.equals
函数添加日志条目 -> 日志中没有条目 - 将
entity.setData(entity.getData());
添加到modify
函数末尾 -> 无变化 - 将 JSON 类型更改为 TEXT -> 无变化
- 手动启动并提交事务 -> 无变化
- 添加
temp =entity.getData();实体.setData(null); entity.setData(temp);
到modify
函数的末尾 -> 将正确的值保存到数据库
我这里有什么遗漏的吗?
谢谢
版本
- JRE 8
- Quarkus 1.0.1.Final
- Hibernate 5.4.9.Final
- MySQL 8.0.18
最佳答案
在我看来,更新似乎正在 Hibernate 的缓存中等待。如果您在执行 entity.setData(temp)
后通过 EntityManager
读取实体或持久化并刷新 (EntityManager.persistAndFlush()
),则缓存应该会被刷新,您应该会在数据库中看到您的更改。
引自quarkus.io :
JPA batches changes you make to your entities and sends changes (it’s called flush) at the end of the transaction or before a query. This is usually a good thing as it’s more efficient. But if you want to check optimistic locking failures, do object validation right away or generally want to get immediate feedback, you can force the flush operation by calling entity.flush() or even use entity.persistAndFlush() to make it a single method call.
关于java - 使用 Quarkus 和 Hibernate 通过 AttributeConverter 将 JSON 更改持久保存到数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59115776/