如何防止 Hibernate 更新 NULL 值

Posted

技术标签:

【中文标题】如何防止 Hibernate 更新 NULL 值【英文标题】:How can I prevent Hibernate from updating NULL values 【发布时间】:2011-11-22 23:18:12 【问题描述】:

在保存休眠对象时,休眠中是否有设置忽略空值属性?

注意 就我而言,我通过 Jackson 将 JSON 反序列化为 Hibernate Pojo。

JSON 只包含 Pojo 的一些字段。如果我保存 Pojo,则不在 JSON 中的字段在 Pojo 中为 null 并休眠更新它们。

我遇到了updateable=false 设置,但这不是 100% 的解决方案。 http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-property

也许有人有别的想法……

注意 2:

根据 Hibernate Docs,dynamicUpdate 注释正是这样做的

dynamicInsert / dynamicUpdate(默认为 false): 指定应在运行时生成 INSERT / UPDATE SQL 并且只包含值不为空的列。

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-class

如果您通过dynamic-update 在 XML 中定义它就够有趣了,文档中没有提到 NULL 值的处理。

dynamic-update(可选 - 默认为 false): 指定 UPDATE SQL 应该 > 在运行时生成,并且只能包含值已更改的列。

由于我同时使用注释 AND xml 配置,hibernate 似乎忽略了我的 dynamicUpdate=true 注释。

【问题讨论】:

您可以使用动态更新来避免 SQL 中出现尚未更新的属性,但通常建议仅在实体具有过多属性时使用此设置(列 > 50)[参考: Java Persistence with Hibernate 2006 edition]。 @hvgotcodes 正确地指出,如果字段永远不会被持久化,您不必映射字段。 【参考方案1】:

您应该首先使用数据库中的主键加载对象,然后在其上复制或反序列化 JSON。

hibernate 无法确定值为 null 的属性是否已显式设置为该值或已被排除。

如果是插入,那么 dynamic-insert=true 应该可以工作。

【讨论】:

引导我走向正确的方向。最好是加载现有对象并相应地更新此对象。杰克逊甚至对 wiki.fasterxml.com/JacksonFeatureUpdateValue 有一个默认行为 我的数据库中没有任何空值。因此,没有人永远不会明确地将任何内容设置为空。我还有其他解决方案吗? @gkamal【参考方案2】:

我在谷歌上搜索了很多关于这个的,但没有适合我的解决方案。所以,我使用了一个不优雅的解决方案来解决它。

  public void setAccount(Account a) throws HibernateException 
    try 
        Account tmp = (Account) session.
                get(Account.class, a.getAccountId());
        tmp.setEmail(getNotNull(a.getEmail(), tmp.getEmail()));            
        ...
        tmp.setVersion(getNotNull(a.getVersion(), tmp.getVersion()));
        session.beginTransaction();
        session.update(tmp);
        session.getTransaction().commit();
     catch (HibernateException e) 
        logger.error(e.toString());
        throw e;
    


public static <T> T getNotNull(T a, T b) 
    return b != null && a != null && !a.equals(b) ? a : b;

我收到一个Object a,其中包含很多字段。那些字段可能是null,但我不想将它们更新到mysql。 我从db得到一个tmp Obejct,通过getNotNull方法改变字段,然后更新Object。

a Chinese description edition

【讨论】:

【参考方案3】:

我遇到了这个问题,我做了一个解决方法来帮助自己解决这个问题。可能有点难看,但也可能对你有用。如果有人觉得有一个很好的调整,可以随意添加。请注意,该解决方法适用于有效的实体类,并且其某些字段包含可为空的属性。这样做的好处是它减少了查询的数量。

public String getUpdateJPQL(Object obj, String column, Object value) throws JsonProcessingException, IOException 

//obj -> your entity class object
//column -> field name in the query clause
//value -> value of the field in the query clause

    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(obj);
    Map<String, Object> map = mapper.readValue(json, Map.class);
    Map format = new HashMap();
    if (value instanceof String) 
        value = "'" + value + "'";
    

    map.keySet()
            .forEach((str) -> 
                Object val = map.get(str);
                if (val != null) 
                    format.put("t.".concat(str), "'" + val + "'");
                
            );
    String formatStr = format.toString();
    formatStr = formatStr.substring(1, formatStr.length() - 1);

    return "update " + obj.getClass()
            .getSimpleName() + " t set " + formatStr + " where " + column + " = " + value + "";


示例:对于实体类型User,字段为:userIduserName & userAgegetUpdateJPQL(user, userId, 2)的结果查询应该是update User t set t.userName = 'value1', t.userAge = 'value2' where t.userId = 2 请注意,您可以在 userId 字段上使用 json 注释(如 @JsonIgnore)在反序列化(即生成的查询)中将其排除。 然后,您可以使用 entityManager 或休眠会话运行查询。

【讨论】:

以上是关于如何防止 Hibernate 更新 NULL 值的主要内容,如果未能解决你的问题,请参考以下文章

SQL 约束,以防止根据其先前值更新列

Hibernate:如何使用 HQL 设置 NULL 查询参数值?

Hibernate:如何使用HQL设置NULL查询参数值?

hibernate在Oracle中插入数据,默认字段被设置为null的问题解决

JPA Hibernate,如何在创建时进行验证,而在更新时忽略验证

hibernate级联更新时,不更新null数据