如何在 Java 中仅更新 @Transactional 方法中更改的字段?

Posted

技术标签:

【中文标题】如何在 Java 中仅更新 @Transactional 方法中更改的字段?【英文标题】:How can I update only changed fields in my @Transactional method in Java? 【发布时间】:2020-09-01 09:57:17 【问题描述】:

亲爱的开发者们好!我需要解决一些与我的方法相关的问题。 我需要创建一个允许我更改对象的编辑/更新方法。

其中一个条件是只有用户更改的字段才能在数据库中更改。不应覆盖所有字段。 示例:旧值名称 -> “Jack”,新值名称 -> “Bob”,应该更改 . 但是,如果旧值是 name -> " Jack ",而新值是 name -> "Jack",则不应覆盖该字段,因为值相等。

我需要我的方法只检查和更改已更改的字段并在数据库中插入更改。

我尝试使用 sql 完成任务,但不幸的是我不知道如何设置值 (如果新值现在与 DB 中的值相同,则不执行任何更新) :


    @Transactional(transactionManager = TransactionManagerConfig.TX_MANAGER_MAIN)
    public void editUserContacts(User user) 

        Connection connection = DataSourceUtils.getConnection(mainDataSource);

        String sql = "UPDATE `" + userSchema + "`.l_user " +
                " SET user_phone_number = @phoneNumber," +
                "firstname = @fullName," +
                "user_country = @userCountry," +
                "house_phone_number = @phoneAlternative," +
                " WHERE l_user_id=? , " +
                "user_phone_number != @phoneNumber OR IS NULL," +
                "firstName != @fullName OR IS NULL," +
                "user_country != @userCountry OR IS NULL," +
                "house_phone_number != @phoneAlternative OR IS NULL,;

        try (
                PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
        ) 
            statement.executeUpdate();
            statement.getUpdateCount();

         catch (SQLException e) 
            throw new DAOException(e);

        
    

也许我需要先执行 SELECT,或者使用 equals 比较每个字段?请告诉我至少一个值的示例,我怎样才能正确地执行我的任务?

P.S 如果新值不等于旧值,我想更新我的值。但是如果新旧值相等,则什么都不会发生

非常感谢您的帮助!

【问题讨论】:

【参考方案1】:

示例:旧值名称 -> “Jack”,新值名称 -> “Bob”,应该更改 .但是,如果旧值是 name -> " Jack ",而新值是 name -> "Jack",则不应覆盖该字段,因为值相等。

别管它。 mysql 足够聪明,只有当列的值真正改变时,它才会更新列。

例子:

看 - 有 2 行,只有一行中的值发生了变化。和 MySQL 报告

1 行受影响

匹配行:2 更改:1

即事实上没有改变值的行没有改变。

【讨论】:

在一种情况下,SQL 确实 关心。如果 all 值未更改,则可能需要避免更新任何行:以节省服务器负载、避免触发触发器或避免自动时间戳更新。 @Akina,很高兴知道这一点。但是正如 cmets 中提到的,如果它说 1 row affected,那么 trigger 是否仍然对两行都执行并且还会发生“自动 tmestamp 更新”(如果有的话)吗?虽然不确定server load 部分。 @Sujitmohanty30 触发器是否仍然对两行都执行并且还会发生“自动 tmestamp 更新”(如果有)? 如果更新查询成功执行,那么自动使用的时间戳值将是更新并为所有匹配的行触发触发器。如果更新失败(由于 CHECK 约束或其他原因),则查询和触发的触发器所做的所有更改(包括自动使用的时间戳更新)都将被回滚。【参考方案2】:

如果我理解正确,您只会在新值不是NULL 时更新表中的值。但是,只有部分列可能会受到影响。为此,请使用COALESCE():

UPDATE " + userSchema + ".l_user 
    SET user_phone_number = COALESCE(@phoneNumber, user_phone_number),
        firstname = COALESCE(@fullName, firstname),
        user_country = COALESCE(@userCountry, user_country),
        house_phone_number = COALESCE(@phoneAlternative, house_phone_number),
    WHERE l_user_id = ? AND
          not (user_phone_number <=> @phoneNumber and
               firstName <=> @fullName and
               user_country <=> @userCountry and
               house_phone_number <=> @phoneAlternative
              );

这将尝试仅更新四个值之一已更改的行。 &lt;=&gt;NULL-safe 比较运算符。

您的查询尝试有多个错误。

WHERE 子句无法识别,。这只是一个语法错误 OR IS NULL 不是有效的 SQL。这是语法错误。 WHERE 子句前还有一个逗号,这是另一个语法错误。

【讨论】:

如果新值不等于旧值,我想更新我的值。但如果新旧值相等,则什么都不会发生

以上是关于如何在 Java 中仅更新 @Transactional 方法中更改的字段?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 swift 中仅为唯一值更新 TableView 行?

如何在 android 应用程序中仅从服务器获取更新的数据?

如何访问以前的状态,并使用它在单个状态设置器调用中仅更新某些对象属性?

如何在 DACPAC 部署中仅部署一组选定的存储过程?

当在 ReactJs React-Redux 中仅创建或更新列表中的一个项目时,如何停止重新渲染整个项目列表?

如何在Java中仅删除字符串的尾随空格并保留前导空格?