• 基于Mybatis-Plus扩展批量插入或更新InsertOrUpdateBath


    前言: mybatis-plus 是一款很好用的crud基础框架,但是我在api中没有找到插入或者更新,那么我想着基于mybatis-plus 自定义一个方法出来用,因为插入或者更新在字段数量多的时候写xml是非常麻烦的事情。

    传统写法:

    INSERT INTO test(`id`,`name`,`address`)
    VALUES('4','修改10','北京'),
        ( '1', '张三' ,1) 
    ON DUPLICATE KEY UPDATE
    name=VALUES(name),address=VALUES(address);

     

    基于MP的写法,是需要用到MP里面的SQL注入

    MP SQL 注入器文档地址: SQL注入器 | MyBatis-Plus

     1. 新建自定义注解 DuplicateSql

    说明:自定义注解是为了插入更新基于那些字段(自定更新字段使用)

    1. /**
    2. * @author yueF_L
    3. * @version 1.0
    4. * @date 2022-08-30 10:21
    5. * 自定义注解DuplicateSql
    6. */
    7. @Target(ElementType.FIELD)
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface DuplicateSql {
    11. /**
    12. * 列名称,对应数据库字段
    13. *
    14. * @return
    15. */
    16. String columnName() default "";
    17. }

    2. 自定义批量插入更新方法实现

    1. /**
    2. * 批量插入更新方法实现
    3. */
    4. public class MysqlInsertOrUpdateBath extends AbstractMethod {
    5. @Override
    6. public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) {
    7. final String sql = "";
    8. final String tableName = tableInfo.getTableName();
    9. final String filedSql = prepareFieldSql(tableInfo);
    10. final String modelValuesSql = prepareModelValuesSql(tableInfo);
    11. final String modelKeySql = prepareDuplicateKeySql(modelClass);
    12. final String duplicateKeySql = prepareDuplicateKeySql(tableInfo);
    13. final String sqlResult = String.format(sql, tableName, filedSql, modelValuesSql, StringUtils.isBlank(modelKeySql) ? duplicateKeySql : modelKeySql);
    14. SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
    15. return this.addInsertMappedStatement(mapperClass, modelClass, "mysqlInsertOrUpdateBath", sqlSource, new NoKeyGenerator(), null, null);
    16. }
    17. /**
    18. * 根据自定义字段更新
    19. *
    20. * @param modelClass
    21. * @return
    22. */
    23. private String prepareDuplicateKeySql(Class modelClass) {
    24. final StringBuilder duplicateKeySql = new StringBuilder();
    25. // 获取所有的字段信息
    26. Field[] declaredFields = modelClass.getDeclaredFields();
    27. for (Field declaredField : declaredFields) {
    28. DuplicateSql duplicateSql = declaredField.getAnnotation(DuplicateSql.class);
    29. if (ObjectUtil.isNotEmpty(duplicateSql)) {
    30. String columnName = duplicateSql.columnName();
    31. duplicateKeySql.append(columnName).append("=values(").append(columnName).append("),");
    32. }
    33. }
    34. if (StringUtils.isNotBlank(duplicateKeySql)) {
    35. duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
    36. }
    37. return duplicateKeySql.toString();
    38. }
    39. /**
    40. * 准备ON DUPLICATE KEY UPDATE sql
    41. * 根据全字段更新(不推荐使用)
    42. *
    43. * @param tableInfo
    44. * @return
    45. */
    46. private String prepareDuplicateKeySql(TableInfo tableInfo) {
    47. final StringBuilder duplicateKeySql = new StringBuilder();
    48. if (!StringUtils.isEmpty(tableInfo.getKeyColumn())) {
    49. duplicateKeySql.append(tableInfo.getKeyColumn()).append("=values(").append(tableInfo.getKeyColumn()).append("),");
    50. }
    51. tableInfo.getFieldList().forEach(x -> {
    52. duplicateKeySql.append(x.getColumn())
    53. .append("=values(")
    54. .append(x.getColumn())
    55. .append("),");
    56. });
    57. duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
    58. return duplicateKeySql.toString();
    59. }
    60. /**
    61. * 准备属性名
    62. *
    63. * @param tableInfo
    64. * @return
    65. */
    66. private String prepareFieldSql(TableInfo tableInfo) {
    67. StringBuilder fieldSql = new StringBuilder();
    68. fieldSql.append(tableInfo.getKeyColumn()).append(",");
    69. tableInfo.getFieldList().forEach(x -> {
    70. fieldSql.append(x.getColumn()).append(",");
    71. });
    72. fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
    73. fieldSql.insert(0, "(");
    74. fieldSql.append(")");
    75. return fieldSql.toString();
    76. }
    77. private String prepareModelValuesSql(TableInfo tableInfo) {
    78. final StringBuilder valueSql = new StringBuilder();
    79. valueSql.append("");
    80. if (!StringUtils.isEmpty(tableInfo.getKeyProperty())) {
    81. valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
    82. }
    83. tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
    84. valueSql.delete(valueSql.length() - 1, valueSql.length());
    85. valueSql.append("");
    86. return valueSql.toString();
    87. }
    88. }

    3. 注册自定义方法SQL注入器

    1. /**
    2. * @author yueF_L
    3. * @version 1.0
    4. * @date 2022-08-29 17:18
    5. * 注册自定义方法SQL注入器
    6. */
    7. @Component
    8. public class CustomizedSqlInjector extends DefaultSqlInjector {
    9. /**
    10. * 如果只需增加方法,保留mybatis plus自带方法,
    11. * 可以先获取super.getMethodList(),再添加add
    12. */
    13. @Override
    14. public List getMethodList(Class mapperClass, TableInfo tableInfo) {
    15. List methodList = super.getMethodList(mapperClass, tableInfo);
    16. methodList.add(new MysqlInsertOrUpdateBath());
    17. return methodList;
    18. }
    19. }

    4. 自定义Mapper RootMapper

    1. /**
    2. * @author yueF_L
    3. * @version 1.0
    4. * @date 2022-08-29 17:11
    5. * 根Mapper,给表Mapper继承用的,可以自定义通用方法
    6. */
    7. public interface RootMapper extends BaseMapper {
    8. /**
    9. * 自定义批量新增或更新
    10. * 需要配合自定注解 DuplicateSql 使用
    11. *
    12. * @param list
    13. * @return
    14. */
    15. Boolean mysqlInsertOrUpdateBath(@Param("list") List list);
    16. }

  • 相关阅读:
    2023-11-09 mysql-代号m-事务-添加RC隔离级别-需求分析
    ab4d:ViewerSvg - svg to xaml converter
    【2022国赛模拟】相似序列问题——DFA(DP套DP)
    颠覆传统编程:用ChatGPT十倍提升生产力
    为安卓编写Linux内核驱动程序
    linux的su:鉴定故障,或当密码正确
    Nginx配置
    携一站式全品类、全场景智慧出行解决方案,移远通信精彩亮相2023摩博会
    气膜体育馆:低碳环保体育新潮流
    ROS 仿真
  • 原文地址:https://blog.csdn.net/weixin_38982591/article/details/126600572