Data Access 之 MyBatis(八)- MyBatis 通用 Mapper(Part C)

简介: Data Access 之 MyBatis(八)- MyBatis 通用 Mapper(Part C)

六、自定义Mapper

业务Mapper接口PorscheMappr通过继承Mapper<T>接口从而获取了一系列的方法,这一系列的方法也不是Mapper<T>接口本身就有的,而是通过继承其他Mapper如BaseMapper<T>、ExampleMapper<T>等,而这些BaseMapper<T>又继承简介继承了SelectOneMapper<T>才获得selectOne方法,因此我们根据实际需要对Mapper<T>进行定制。

6.1 实现自定义Mapper

在common-mapper项目中新建一个common包,用来存放自定义的Mapper<T>,新建CustMapper<T>

public interface CustMapper<T> extends SelectOneMapper<T> {
}
复制代码

这里也可以选择继承多个如SelectAllMapper<T>等。

在Spring配置文件application.xml中配置自定义的CustMapper<T>

<bean id="mapperScannerConfigurer" class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--指定接口所在的包-->
    <property name="basePackage" value="com.citi.mapper"></property>
    <!--配置自定义的CustMapper<T>接口-->
    <property name="properties">
        <value>
            mappers=com.citi.common.CustMapper
        </value>
    </property>
</bean>
复制代码

修改TeacherMapper的继承关系,改为继承自定义的CustMapper<T>接口

public interface TeacherMapper extends CustMapper<Teacher> {
}
复制代码

增加TeacherMapper的测试类TeacherMapperTest,对继承来的selectOne方法进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application.xml")
public class TeacherMapperTest {
    @Resource
    private TeacherMapper teacherMapper;
    @Test
    public void selectOne(){
        // 构造查询条件
        Teacher record = new Teacher();
        record.setGrade("三年二班");
        record.setName("stark");
        Teacher teacher = teacherMapper.selectOne(record);
        System.out.println("查询到的内容为:" + teacher);
    }
}
复制代码

执行测试

image.png

成功输出根据查询条件查到的数据

plus:自定义的Mapper和普通的XxxMapper接口不能放在同一个包下,会导致Spring容器创建自定义Mapper的Bean失败

七、通用Mapper扩展

扩展指的是增加通用Mapper没有的功能,通用Mapper提供了一些列基本的增删改查以及条件查询主键查询等方法,但是没有提供批量操作的方法,官网中给出了扩展通用Mapper的例子即扩展批量插入的功能。

7.1 扩展实现批量更新

自定义的Mapper扩展可以参考官方已有的代码。

image.png

仿照官方的UpdateByPrimaryKeyMapper<T>接口来写我们自己的BatchUpdateMapper<T>接口

@RegisterMapper
public interface BatchUpdateMapper<T> {
    @UpdateProvider(type = BatchUpdateProvider.class, method = "dynamicSQL")
    void batchUpdate(List<T> tList);
}
复制代码

在common包下新建一个BatchUpdateProvider

image.png

仿照官方的BaseUpdateProvider实现自定义的BatchUpdateProvider,首先声明一个构造器

public class BatchUpdateProvider extends MapperTemplate {
    // 构造器
    public BatchUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }
}
复制代码

批量更新的SQL语句在Mapper XML文件中写入如下格式,将多条UPDATE SQL语句通过“;”连接起来执行

<foreach item="record" collection="list" separator=";">
    UPDATE porsche
    <set>
    por_name = #{porsche.porName},
    por_price = #{porsche.porPrice},
    por_stock = #{porsche.porStock},
    </set>
    por_id = #{porsche.por_id}
</foreach>
复制代码

这就是我们要拼接的SQL语句,BatchUpdateProvider类中增加一个方法batchUpdate,该方法返回一个String即要执行的SQL语句

public String batchUpdate(MappedStatement ms){
    // 1.新建一条SQL语句
    StringBuilder sql = new StringBuilder();
    // 2.拼接 foreach标签开头
    sql.append("<foreach item="record" collection="list" separator=";" >");
    // 获取实体类对象
    Class<?> entityClass = getEntityClass(ms);
    String updateClause = SqlHelper.updateTable(entityClass,tableName(entityClass));
    // 3.拼接 "UPDATE 表名 "
    sql.append(updateClause);
    // 4.拼接set标签开头
    sql.append("<set>");
    // 获取字段名称的集合
    Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);
    // 声明主键字段
    String idColumn = null;
    String idColumnHolder = null;
    // 遍历字段
    for (EntityColumn entityColumn : columns) {
        // 判断是否是主键,是主键要放在WHERE子句后面
        boolean isPrimaryKey = entityColumn.isId();
        System.out.println(isPrimaryKey);
        if (isPrimaryKey){
            idColumn = entityColumn.getColumn();
            System.out.println(idColumn);
            idColumnHolder = entityColumn.getColumnHolder("record");
        } else {
            // 返回类似如下字符串"(实体类.属性,jdbcType=NUMERIC,typeHandler=MyTypeHandler)"
            // 获取字段名和属性名
            String column = entityColumn.getColumn();
            String columnHolder = entityColumn.getColumnHolder("record");
            // 5.拼接por_name = #{porsche.porName},
            sql.append(column).append("=").append(columnHolder).append(",");
        }
    }
    // 6.拼接set标签结尾
    sql.append("</set>");
    // 7.拼接where子句
    sql.append("where ").append(idColumn).append("=").append(idColumnHolder);
    // 8.拼接 foreach标签结尾
    sql.append("</foreach>");
    // 9.返回SQL语句
    return sql.toString();
}
复制代码

代码中拼接批量更新SQL的步骤为:

  1. 新建一条SQL语句
  2. 拼接 foreach标签开头
  3. 拼接 "UPDATE porsche "
  4. 拼接 set标签开头
  5. 拼接 por_name = #{porsche.porName}
  6. 拼接 set标签结尾
  7. 拼接 where子句
  8. 拼接 foreach标签结尾
  9. 返回SQL语句

然后让自定义的CustMapper继承自定义的BatchUpdateMapper

public interface CustMapper<T> extends SelectOneMapper<T>,BatchUpdateMapper<T> {
}
复制代码

因为TeacherMapper接口继承了CustMapper,所有TeacherMapper接口就自动获得了batchUpdate方法,在TeacherMapperTest测试类中增加对batchUpdate的测试

@Test
public void batchUpdate(){
    List<Teacher> teacherList = new ArrayList<>();
    for (int i = 7; i < 10; i++) {
        Teacher teacher = new Teacher();
        teacher.setId(i);
        teacher.setGrade("五年" + i + "班");
        teacher.setName("Ultron " + i);
        teacher.setAddress("New York");
        teacher.setBirthDate(new Date());
        teacherList.add(teacher);
    }
    teacherMapper.batchUpdate(teacherList);
}
复制代码

执行测试前需要注意因为更新语句是将多条SQL语句通过“;”连接起来一次执行,所有需要在db.properties中jdbc_url后面要加上“&allowMultiQueries=true“。

执行测试

image.png

这里出现错误,根据输出的SQL语句判断应该是isId()方法没有判断出id是主键,查看Teacher实体类,发现id属性上没有增加@Id注解,也就是说通用Mapper并不知道id属性对应的字段是主键,也就没有做出正确的判断,导致输出控制台的错误语句。 在id属性上增加@Id注解以及@GeneratedValue注解

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
复制代码

再次执行测试

image.png

数据库被成功修改。

自定义的批量更新扩展生效。


相关文章
|
3月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
62 10
|
5月前
|
SQL Java 数据库连接
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
文章讲述了在使用Mybatis时遇到的资源文件找不到的问题,并提供了通过修改Maven配置来解决资源文件编译到target目录下的方法。
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
|
4月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
75 1
|
5月前
|
XML Java 数据库连接
Mybatis 模块拆份带来的 Mapper 扫描问题
Mybatis 模块拆份带来的 Mapper 扫描问题
55 0
|
6月前
|
SQL
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
|
6月前
|
Java 数据库连接 Maven
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
|
7月前
|
SQL Java 数据库连接
Mybatis如何使用mapper代理开发
Mybatis如何使用mapper代理开发
|
7月前
|
XML 关系型数据库 数据库
使用mybatis-generator插件生成postgresql数据库model、mapper、xml
使用mybatis-generator插件生成postgresql数据库model、mapper、xml
627 0
|
7月前
|
SQL Java 数据库连接
Mybatis中一对多mapper配置
Mybatis中一对多mapper配置
|
7月前
|
Java 数据库连接 mybatis
Mybatis mapper动态代理解决方案
该文介绍了Mybatis中使用Mapper接口的方式代替XML配置执行SQL。Mapper接口规范包括:namespace与接口类路径相同,select ID与接口方法名一致,parameterType和方法参数类型匹配,resultType与返回值类型一致。实现过程中,需配置Mapper.xml,编写Mapper.java接口,并在Mybatis-config.xml中设置。测试类中,通过SqlSession的getMapper方法获取接口的动态代理对象,调用方法执行SQL。
216 0