簡體   English   中英

使用 Quarkus 和 Hibernate 通過 AttributeConverter 將 JSON 更改持久保存到數據庫

[英]Persisting JSON change via AttributeConverter to database using Quarkus and Hibernate

我正在嘗試通過以下方式持久化對數據庫的更改:

實體

我有一個具有 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); temp = entity.getData(); entity.setData(null); entity.setData(temp); modify功能結束 - >工作正確的值被持久化到數據庫

我在這里缺少什么嗎?

謝謝

版本

  • 傑瑞8
  • Quarkus 1.0.1.Final
  • 休眠 5.4.9.Final
  • MySQL 8.0.18

在我看來,好像更新在 Hibernate 的緩存中掛起。 如果您在執行entity.setData(temp)后通過EntityManager或持久化和刷新 ( EntityManager.persistAndFlush() ) 讀取實體,緩存應該被刷新並且您應該在數據庫中看到您的更改。

引自quarkus.io

JPA 對您對實體所做的更改進行批處理,並在事務結束時或查詢之前發送更改(稱為刷新)。 這通常是一件好事,因為它更有效率。 但是如果你想檢查樂觀鎖定失敗,立即進行對象驗證或者通常想獲得即時反饋,你可以通過調用 entity.flush() 強制刷新操作,甚至使用 entity.persistAndFlush() 使其成為一個方法稱呼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM