随笔 - 1162  文章 - 0  评论 - 16  阅读 - 59万 

一、通用Mapper接口扩展

1、说明

这里的扩展是指增加通用Mapper提供的功能。

2、举例

通用Mapper官方文档中使用一个批量 insert 作为扩展功能的例子:

tk.mybatis.mapper.additional.insert.InsertListMapper<T>

tk.mybatis.mapper.additional.insert.InsertListProvider

我们来仿照写一个批量 update,假设我们想生成下面这样的 SQL 语句:

update table_emp set emp_name=?, emp_age=?,emp_salary=? where emp_id=?;
update table_emp set emp_name=?, emp_age=?,emp_salary=? where emp_id=?;
update table_emp set emp_name=?, emp_age=?,emp_salary=? where emp_id=?;
......

为了生成上面那样的 SQL 语句,我们需要使用到 MyBatis 的 foreach 标签:

<foreach collection="list" item="record" separator=";">
    UPDATE table_emp
    SET emp_name=#{record.empName},
    emp_age=#{record.empAge},
    emp_salary=#{record.empSalary},
    where emp_id=#{record.empId}
<foreach>

3、需要提供的接口和实现类

二、扩展Mapper接口

1、创建扩展接口与实现类

接口:

public interface MyBatchUpdateMapper<T> {

    @UpdateProvider(type= MyBatchUpdateProvider.class, method = "dynamicSQL")
    public void batchUpdate(List<T> list);
}

实现类:

public class MyBatchUpdateProvider extends MapperTemplate {

    public MyBatchUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }


    public String batchUpdate(MappedStatement ms) {
          return null;
    }
}

2、方法类的实现(拼接SQL)

public class MyBatchUpdateProvider extends MapperTemplate {

    public MyBatchUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    /*
        <foreach collection="list" item="record" separator=";">
            UPDATE tabple_emp
            <set>
                emp_name=#{record.empName},
                emp_age=#{record.empAge},
                emp_salary=#{record.empSalary}
            </set>
            where emp_id=#{record.empId}
        </foreach>

     */
    public String batchUpdate(MappedStatement ms) {

        //1.创建StringBuilder用于拼接SQL语句的各个组成部分
        StringBuilder builder = new StringBuilder();

        //2.拼接foreach标签
        builder.append("<foreach collection=\"list\" item=\"record\" separator=\";\">");

        //3.获取实体类对应的Class对象
        Class<?> entityClass = super.getEntityClass(ms);

        //4.获取实体类在数据库中对应的表名
        String tableName = super.tableName(entityClass);

        //5.生成update子句
        String updateClause = SqlHelper.updateTable(entityClass, tableName);
        builder.append(updateClause);

        builder.append("<set>");

        //6.获取所有字段信息
        Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);

        String idColumn = null;
        String idHolder = null;

        for (EntityColumn entityColumn : columns) {

            boolean isPrimaryKey = entityColumn.isId();

            //7.判断当前字段是否为主键
            if (isPrimaryKey) {
                //8.缓存主键的字段名和字段值
                idColumn = entityColumn.getColumn();

                //※返回格式如:#{record.age,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
                idHolder = entityColumn.getColumnHolder("record");
            } else {

                //9.使用非主键字段拼接SET子句
                String column = entityColumn.getColumn();
                String columnHolder = entityColumn.getColumnHolder("record");

                builder.append(column).append("=").append(columnHolder).append(",");
            }
        }
        builder.append("</set>");

        //10.使用前面缓存的主键名、主键值拼接where子句
        builder.append("where ").append(idColumn).append("=").append(idHolder);

        builder.append("</foreach>");
        //11.将拼接好的字符串返回
        return builder.toString();
    }
}

从获取表的各项属性后,完全就是一个拼SQL的过程,这个过程需要注意的是,这里拼的是XML中的形式。

3、继承扩展的 Mapper 接口

public interface MyMapper<Textends
        SelectAllMapper<T>,
        SelectByPrimaryKeyMapper<T>,
        MyBatchUpdateMapper<T> {
}

4、测试

public class ExtendsMapper {

    private ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
    private EmployeeService employeeService = ioc.getBean(EmployeeService.class);


    @Test
    public void test() {
        List<Employee> empList = new ArrayList<Employee>(){{
            add(new Employee(6"Tom1"1000.0020));
            add(new Employee(7"Tom2"2000.0021));
            add(new Employee(7"Tom3"3000.0022));

        }};

        employeeService.batchUpdateEmp(empList);
        ioc.close();
    }
}

public void batchUpdateEmp(List<Employee> empList) {
    employeeMapper.batchUpdate(empList);
}

SQL语句:

UPDATE tabple_emp SET emp_name=?,emp_salary=?,emp_age=where emp_id=? ; 
UPDATE tabple_emp SET emp_name=?,emp_salary=?,emp_age=where emp_id=? ; 
UPDATE tabple_emp SET emp_name=?,emp_salary=?,emp_age=where emp_id=?

注意:这种执行多条SQL语句的方式,需要进行设置,MySQL数据库默认不支持,开启允许批量执行

allowMultiQueries=true

jdbc.url=jdbc:mysql://localhost:3306/common_mapper?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
posted on   格物致知_Tony  阅读(154)  评论(0编辑  收藏  举报
编辑推荐:
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?
点击右上角即可分享
微信分享提示

目录导航