java - 使用 Quarkus 和 Hibernate 通过 AttributeConverter 将 JSON 更改持久保存到数据库

标签 java json hibernate quarkus

我尝试通过以下方式保留对数据库的更改:

实体

我有一个具有 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&amp;characterEncoding=UTF-8&amp;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/

相关文章:

java - 设置 JButton 的用户定义颜色

java - 使用 Spring Boot 初始化 hibernate、jpa 和 MysqlApp?

java - 如何使用 JPA 持久保存 Map<String, Map<String, String>> ?

json - 使用Gson库动态解析未知数据

json - 如何在 Terraform 模板文件中将字符串转换为数字

javascript - 在 AngularJS ng-repeat 中解析 HTML?

java - maven 缺少依赖项 jta-1.0.1b

java - ClassCastException 的真实示例

java - WildFly 8.2.0 (JBOSS) 独立服务器无法启动

java - libgdx,如何使我的图像可触摸