使用Quarkus和Hibernate通过AttributeConverter将JSON更改持久化到数据库

时间:2019-11-30 11:36:22

标签: 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'}}

以下是启用了休眠日志记录的日志文件(此处的内容太多,因此无法发布链接):https://pastebin.com/1e3URx8W

我尝试过的东西

这是我尝试过的一些事情:

  • entityManager.persist(entity);函数的末尾添加modify-> 不变(预期)
  • 将日志条目添加到TestData.equals功能-> 日志中没有条目
  • entity.setData(entity.getData());函数的末尾添加modify-> 不变
  • 将JSON类型更改为TEXT-> 不变
  • 手动启动和提交交易-> 不变
  • temp = entity.getData(); entity.setData(null); entity.setData(temp);函数的末尾添加modify-> 将正确的值保存到数据库中

这里我想念什么吗?

谢谢

版本

  • JRE 8
  • Quarkus 1.0.1.Final
  • 休眠5.4.9.Final
  • MySQL 8.0.18

1 个答案:

答案 0 :(得分:0)

在我看来,好像更新在Hibernate的缓存中待处理。如果您通过EntityManager读取实体,或者在执行EntityManager.persistAndFlush()之后坚持并刷新(entity.setData(temp)),则应该刷新缓存,并且应该在数据库中看到所做的更改。

引用quarkus.io

  

JPA批量处理您对实体所做的更改,并在交易结束时或在查询之前发送更改(称为“刷新”)。这通常是一件好事,因为它效率更高。但是,如果您要检查乐观的锁定失败,立即进行对象验证或通常希望获得即时反馈,则可以通过调用entity.flush()甚至使用entity.persistAndFlush()使其成为单个方法来强制执行刷新操作。打电话。