一、工具类UpdateEntity
在 MyBatis-Flex 中,UpdateEntity
是一个用于部分字段更新的核心工具类,尤其适用于需要更新某些字段为 null
或仅修改特定字段的场景。以下是其核心用法和特性总结:
1. UpdateEntity 的作用
- 部分字段更新:通过
UpdateEntity
创建的对象,仅会更新调用了setter
方法的字段,未调用的字段即使实体类中存在值,也不会更新到数据库。 - 支持
null
值更新:若需要将字段更新为null
,直接通过setter
方法设置即可,无需额外配置。
2. 创建 UpdateEntity 实例
通过 UpdateEntity.of
方法创建实例,需指定实体类类型及主键值:
// 方式1:自动设置主键(需实体类主键字段已赋值) Account account = UpdateEntity.of(Account.class); account.setId(100); // 必须设置主键 // 方式2:直接传入主键值 Account account = UpdateEntity.of(Account.class, 100); // 主键自动赋值
3. 更新字段的示例
通过 setter
方法设置需要更新的字段,未调用的字段不会被修改:
Account account = UpdateEntity.of(Account.class, 100); account.setUserName(null); // 更新为 null account.setAge(10); // 更新为 10 accountMapper.update(account); // 生成 SQL:UPDATE tb_account SET user_name=?, age=? WHERE id=100
生成的 SQL 仅包含调用 setter
的字段,性能高效。
4. 注意事项
- 主键必须有效:
UpdateEntity
必须通过主键定位记录,否则会抛出异常。 - 字段覆盖规则:即使实体类其他字段有值,未通过
setter
方法调用的字段不会被更新。 - 性能优化:
UpdateEntity
生成的 SQL 仅包含必要字段,避免全字段更新的性能损耗。
5. 适用场景
- 需要更新少量字段且部分字段为
null
。 - 需要避免覆盖数据库中其他字段的默认值或现有值。
通过合理使用 UpdateEntity
,可以显著简化部分字段更新的代码逻辑,同时提升数据库操作的灵活性和安全性。
二、工具类UpdateWrapper
1. 使用UpdateWrapper 新增数据
在某些场景下,我们希望在新增数据时,新增数据字段内容是数据库的某个 函数
或者 SQL片段
生成的内容,而非我们手动设置的内容。 例如,我们希望执行的 SQL 如下:
INSERT INTO `tb_account`(`user_name`, `birthday`) VALUES (?, now())
以上 SQL 中,
birthday
是由now()
函数生成的内容。
那么,Java 代码如下:
@Test public void testInsertWithRaw() { Account account = new Account(); account.setUserName("michael"); Account newAccount = UpdateWrapper.of(account) // .setRaw("birthday", "now()") // .setRaw(ACCOUNT.BIRTHDAY, "now()") .setRaw(Account::getBirthday, "now()") .toEntity(); accountMapper.insert(newAccount); }
或者复杂一点的:
@Test public void testInsertWithRaw() { Account account = new Account(); account.setUserName("michael"); Account newAccount = UpdateWrapper.of(account) .setRaw(Account::getBirthday, "(select xxx from ...)") .toEntity(); accountMapper.insert(newAccount); }
其生成的 SQL 如下:
INSERT INTO `tb_account`(`user_name`, `birthday`) VALUES (?, (select xxx from ...))
注意,通过
UpdateWrapper.setRaw()
的设置,会覆盖注解@Column.onUpdateValue
配置的内容。
2.使用UpdateWrapper部分字段更新(增强)
在以上的部分字段更新中,只能更新为用户传入的数据,但是有些时候我们想更新为数据库计算的数据,比如 SQL:
update tb_account set user_name = ?, age = age + 1 where id = ?
此时,我们可以直接把 Account
强转为 UpdateWrapper
然后进行更新,例如:
Account account = UpdateEntity.of(Account.class, 100); account.setUserName(null); // 通过 UpdateWrapper 操作 account 数据 UpdateWrapper wrapper = UpdateWrapper.of(account); wrapper.setRaw("age", "age + 1"); accountMapper.update(account);
其执行的 SQL 为:
update tb_account set user_name = null, age = age + 1 where id = 100
更高级的用法
示例1:
Account account = UpdateEntity.of(Account.class, 100); account.setUserName("Michael"); // 通过 UpdateWrapper 操作 account 数据 UpdateWrapper wrapper = UpdateWrapper.of(account); wrapper.set(ACCOUNT.AGE, ACCOUNT.AGE.add(1)); accountMapper.update(account);
其执行的 SQL 为:
update tb_account set user_name = "michael", age = age + 1 where id = 100
示例2:
Account account = UpdateEntity.of(Account.class, 100); account.setUserName("Michael"); // 通过 UpdateWrapper 操作 account 数据 UpdateWrapper wrapper = UpdateWrapper.of(account); wrapper.set(ACCOUNT.AGE, select().from(...)); accountMapper.update(account);
其执行的 SQL 为:
update tb_account set user_name = "michael", age = (select ... from ... ) where id = 100
三、工具类UpdateChain
UpdateChain 是一个对 UpdateEntity
、UpdateWrapper
等进行封装的一个工具类,方便用户用于进行链式操作。
假设我们要更新 Account
的 userName
为 "张三
",更新年龄在之前的基础上加 1,更新代码如下:
@Test public void testUpdateChain() { UpdateChain.of(Account.class) .set(Account::getUserName, "张三") .setRaw(Account::getAge, "age + 1") .where(Account::getId).eq(1) .update(); }
以上方法调用时,MyBatis-Flex 内部执行的 SQL 如下:
UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1 WHERE `id` = 1
更多关于 链式操作,请点击这个 这里。
四、set() 和 setRaw() 的区别
在 Row
、UpdateWrapper
、UpdateChain
中,都提供了 set()
和 setRaw()
两个方法用于设置数据。 那么,他们有什么区别呢?
set()
方法用于设置参数数据。setRaw()
用于设置 SQL 拼接数据。
例如:
UpdateChain.of(Account.class) .set(Account::getUserName, "张三") .where(Account::getId).eq(1) .update();
其执行的 SQL 如下:
UPDATE `tb_account` SET `user_name` = ? WHERE `id` = 1
如果是使用 setRaw()
方法:
UpdateChain.of(Account.class) .setRaw(Account::getUserName, "张三") .where(Account::getId).eq(1) .update();
以上代码执行时,参数 "张三
" 会直接参与 SQL 拼接,可能会造成 SQL 错误,其 SQL 如下:
UPDATE `tb_account` SET `user_name` = 张三 WHERE `id` = 1
因此,需要用户 【特别注意!!!】,setRaw()
传入不恰当的参数时,可能会造成 SQL 注入的危险。 因此,调用 setRaw()
方法时,需要开发者自行对其参数进行 SQL 注入过滤。
setRaw()
经常使用的场景:
- 场景1: 用户充值,更新用户金额:
UpdateChain.of(Account.class) .setRaw(Account::getMoney, "money + 100") .where(Account::getId).eq(1) .update();
其执行的 SQL 如下:
UPDATE `tb_account` SET `money` = money + 100 WHERE `id` = 1
- 场景2:执行某些特殊函数:
UpdateChain.of(Account.class) .setRaw(Account::getUserName, "UPPER(user_name)") .where(Account::getId).eq(1) .update();
其执行的 SQL 如下:
UPDATE tb_account SET user_name = UPPER(user_name) WHERE id = 1
或者
UpdateChain.of(Account.class) .setRaw(Account::getUserName, "utl_raw.cast_to_raw('some magic here')") .where(Account::getId).eq(1) .update();
其执行的 SQL 如下:
UPDATE tb_account SET user_name = utl_raw.cast_to_raw('some magic here') WHERE id = 1