我正尝试通过以下方式持久保存对数据库的更改:
我有一个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'}}
以下是启用了休眠日志记录的日志文件(此处的内容太多,因此无法发布链接):https://pastebin.com/1e3URx8W
这是我尝试过的一些事情:
entityManager.persist(entity);
函数的末尾添加modify
-> 不变(预期)TestData.equals
功能-> 日志中没有条目 entity.setData(entity.getData());
函数的末尾添加modify
-> 不变 temp = entity.getData(); entity.setData(null); entity.setData(temp);
函数的末尾添加modify
-> 将正确的值保存到数据库中 这里我想念什么吗?
谢谢
答案 0 :(得分:0)
在我看来,好像更新在Hibernate的缓存中待处理。如果您通过EntityManager
读取实体,或者在执行EntityManager.persistAndFlush()
之后坚持并刷新(entity.setData(temp)
),则应该刷新缓存,并且应该在数据库中看到所做的更改。
引用quarkus.io:
JPA批量处理您对实体所做的更改,并在交易结束时或在查询之前发送更改(称为“刷新”)。这通常是一件好事,因为它效率更高。但是,如果您要检查乐观的锁定失败,立即进行对象验证或通常希望获得即时反馈,则可以通过调用entity.flush()甚至使用entity.persistAndFlush()使其成为单个方法来强制执行刷新操作。打电话。