广告
返回顶部
首页 > 资讯 > 后端开发 > Python >tk.mybatis如何扩展自己的通用mapper
  • 424
分享到

tk.mybatis如何扩展自己的通用mapper

2024-04-02 19:04:59 424人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

tk.mybatis扩展自己的通用mapper 目的:tk.mybatis 提供的通用mapper,虽然使用方便,不过在有些sql还是不能满足我们的需要的,而且我们希望对于delet

tk.mybatis扩展自己的通用mapper

目的:tk.mybatis 提供的通用mapper,虽然使用方便,不过在有些sql还是不能满足我们的需要的,而且我们希望对于deleted语句进行管控(因为通用mapper提供的都是物理删除,有时我们对一些敏感数据只能进行逻辑删除),因此我们将基于原有的通用mapper进行自己的扩展

1 jar引入


     <!-- 非SpringBoot -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.4.0</version>
        </dependency>

springboot项目引这个包


      <!-- springboot -->
             <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>2.0.2</version>
            </dependency>

springboot项目直接引这个包,本次我们将基于springboot进行开发,这里注意jar包版本,过低的版本将会出现问题,下面会介绍

2 编写配置类


package com.example.configuration;
import com.example.common.mapper.commonMapper.CommonMapper;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import java.util.Properties;
@Configuration
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class MyBatisConfiguration {
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.example.dao.mapper");
        Properties properties = new Properties();
        properties.setProperty("mappers", CommonMapper.class.getName());
        properties.setProperty("notEmpty", "false");
        properties.setProperty("identity", "Mysql");
        properties.setProperty("order","BEFORE");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }
}

这里要注意两点:

1>CommonMapper这个是我们自己定义的通用mapper,它放置一个单独的包下面。也就是说这个包下面只有这个一个mapper,否则我们在实用泛型时会出现类型转换的问题。(我在这里纠结了好久)

2>这里我们配置了自定义mapper的扫描路径。注意springboot项目一定要注意jar包版本,版本过低的话,在配置类中的定义是没有用的。还是扫描不到,我之前使用的版本1.2.3就会出现这个问题,更换更高的版本就可以解决了。

3 常规方法接口整合到自己的自定义Mapper接口上

因为我们使用的是mysql数据库,所以在使用通用功能的时候就选择性引入一些经常使用的方法,下面是自己定义的常用mapper类的整合(这里会抛弃一些不常用的类或不是mysql的方法类)。这些基类不要放在 BasePackage的路径下,这个路径下的mapper都是要指定明确的泛型类型的。

1 > 提供查询功能Mapper:


package com.example.common.mapper.basics;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.select.*;
import tk.mybatis.mapper.common.condition.SelectByConditionMapper;
import tk.mybatis.mapper.common.condition.SelectCountByConditionMapper;
import tk.mybatis.mapper.common.example.SelectByExampleMapper;
import tk.mybatis.mapper.common.ids.SelectByIdsMapper;

public interface SelectMapper<T> extends Marker,
        SelectOneMapper<T>,
        tk.mybatis.mapper.common.base.select.SelectMapper<T>,
        SelectAllMapper<T>,
        SelectCountMapper<T>,
        SelectByPrimaryKeyMapper<T>,
        ExistsWithPrimaryKeyMapper<T>,
        SelectByIdsMapper<T>,
        SelectByConditionMapper<T>,
        SelectCountByConditionMapper<T>,
        SelectByExampleMapper<T> {
}

2>提供新增功能mapper


package com.example.common.mapper.basics;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.MySqlMapper;
import tk.mybatis.mapper.common.base.insert.InsertSelectiveMapper;

public interface InsertMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.insert.InsertMapper<T>,
        InsertSelectiveMapper<T>,
        MySqlMapper<T>{
}

3>提供更新功能mapper


package com.example.common.mapper.basics;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeyMapper;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeySelectiveMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionSelectiveMapper;
import tk.mybatis.mapper.common.example.UpdateByExampleSelectiveMapper;

public interface UpdateMapper<T> extends Marker,
        UpdateByPrimaryKeyMapper<T>,
        UpdateByPrimaryKeySelectiveMapper<T>,
        UpdateByConditionMapper<T>,
        UpdateByConditionSelectiveMapper<T>,
        UpdateByExampleSelectiveMapper<T> {
}

4>提供删除功能mapper


package com.example.common.mapper.basics;
import com.example.common.mapper.defined.DeleteShamByIdsMapper;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.delete.DeleteByPrimaryKeyMapper;
import tk.mybatis.mapper.common.condition.DeleteByConditionMapper;
import tk.mybatis.mapper.common.ids.DeleteByIdsMapper;

public interface DeleteMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.delete.DeleteMapper<T>,
        DeleteByPrimaryKeyMapper<T>,
        DeleteByConditionMapper<T>,
        DeleteByIdsMapper<T>{
}

5>提供增删改查的基类 CommonMapper


package com.example.common.mapper.commonMapper;
import com.example.common.mapper.basics.DeleteMapper;
import com.example.common.mapper.basics.InsertMapper;
import com.example.common.mapper.basics.SelectMapper;
import com.example.common.mapper.basics.UpdateMapper;

public interface CommonMapper<T> extends
        DeleteMapper<T>,
        InsertMapper<T>,
        SelectMapper<T>,
        UpdateMapper<T> {
}

6>实体对象


package com.example.dao.entity;
import lombok.Data;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Table(name="user")
@Data
public class User implements Serializable {
    @Id
    private Integer id;
    private String trueName;
    private String userName;    
    private Integer isDeleted;
}

7>让自定义mapper继承CommenMapper,就可以使用这些语句了


package com.example.dao.mapper;
import com.example.common.mapper.commonMapper.CommonMapper;
import com.example.dao.entity.User;
public interface UserMapper extends CommonMapper<User> {
}

接下来我们会对 CommonMapper中提供删除方法的DeleteMapper进行增强,来给他添加逻辑删除的语句

1>我们自定义的Provider需要去继承 MapperTemplate并覆写构造方法

这个是源码中的批量删除


//
// Source code recreated from a .class file by IntelliJ idea
// (powered by Fernflower decompiler)
//
package tk.mybatis.mapper.provider;
import java.util.Set;
import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
public class IdsProvider extends MapperTemplate {
    public IdsProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }
    public String deleteByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.deleteFromTable(entityClass, this.tableName(entityClass)));
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 deleteByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }
    public String selectByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        this.setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 selectByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }
}

接下来我们对IdsProvider 进行扩展使他支持批量逻辑删除

1>创建IdsProvider的子类


package com.example.common.mapper.defined;
import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
import tk.mybatis.mapper.provider.IdsProvider;
import java.util.Set;
public class IdsProviderDefined extends IdsProvider {
    public IdsProviderDefined(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }
    public String deleteShamByIds(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
        sql.append("<set> is_deleted='1' </set>");
        Set<EntityColumn> columnList = EntityHelper.getPKColumns(entityClass);
        if (columnList.size() == 1) {
            EntityColumn column = (EntityColumn)columnList.iterator().next();
            sql.append(" where ");
            sql.append(column.getColumn());
            sql.append(" in (${_parameter})");
            return sql.toString();
        } else {
            throw new MapperException("继承 deleteByIds 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段");
        }
    }
}

deleteShamByIds就是我们门批量逻辑删除的方法,这个方法其实就是再拼装sql,tk中提供了很多帮助我们拼装sql,和参数的类(SqlHelper,EntityHelper),我们可以使用

2>创建DeleteShamByIdsMapper接口


package com.example.common.mapper.defined;
import org.apache.ibatis.annotations.DeleteProvider;
public interface DeleteShamByIdsMapper<T> {
    @DeleteProvider(
            type = IdsProviderDefined.class,
            method = "dynamicSQL"
    )
    int deleteShamByIds(String var1);
    //这里的抽象方法的名称必须和IdsProviderDefined 中的方法一致
}

3>在DeleteMapper中继承我们自定义的逻辑删除接口DeleteShamByIdsMapper


package com.example.common.mapper.basics;
import com.example.common.mapper.defined.DeleteShamByIdsMapper;
import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.delete.DeleteByPrimaryKeyMapper;
import tk.mybatis.mapper.common.condition.DeleteByConditionMapper;
import tk.mybatis.mapper.common.ids.DeleteByIdsMapper;

public interface DeleteMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.delete.DeleteMapper<T>,
        DeleteByPrimaryKeyMapper<T>,
        DeleteByConditionMapper<T>,
        DeleteByIdsMapper<T>,
        DeleteShamByIdsMapper<T>{
}

到这里我们自定义的批量逻辑删除就定义好了,我们可以通过这种方式扩展通用mapper。

TK mybatis插件通用mapper与oracle的几个坑

最近公司有几个项目的数据库用的oracle,有段时间没用,然后果断就掉坑里面了,记录几个比较有代表性的。

1:关于oracle的批量数据插入,我用TK通用mapper的insertList方法自动拼接出来的sql是这样的


insert  into table(column1,column2)values 
(value1,value2),
(value3,value4)。。。

咋一看没啥问题啊,然后就一直报 sql未正确结束,出于对自己sql的过于自信,导致一直都在思考是否是参数问题,浪费了好几个小时,后来把sql拼好直接丢到数据库跑了跑才发现,这种sql确实是不能在oracle跑的,oracle批量插入的语法应该是:


INSERT ALL 
INTO A(field_1,field_2) VALUES (value_1,value_2) 
INTO A(field_1,field_2) VALUES (value_3,value_4) 
INTO A(field_1,field_2) VALUES (value_5,value_6)

粗略的瞅了下TK的代码,貌似确实没有校验数据库驱动就直接开始拼sql了


public String insertList(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.insertIntoTable(entityClass, this.tableName(entityClass)));
        sql.append(SqlHelper.insertColumns(entityClass, true, false, false));
        sql.append(" VALUES ");
        sql.append("<foreach collection=\"list\" item=\"record\" separator=\",\" >");
        sql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
        Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
        Iterator var5 = columnList.iterator();
        while(var5.hasNext()) {
            EntityColumn column = (EntityColumn)var5.next();
            if (!column.isId() && column.isInsertable()) {
                sql.append(column.getColumnHolder("record") + ",");
            }
        }
        sql.append("</trim>");
        sql.append("</foreach>");
        return sql.toString();
    }

不过我觉得这种插件肯定是有兼容方案的,并且使用了这个插件跟使用源生mybatis并不冲突,所以实际对开发并没有影响,算是复习一下oracle的基础并提醒下自己,程序员还是老老实实先run起来,自以为是的经验有时候也很坑的。

2:关于oracle的比较符号(<> =)和null

先复习一下

一般数据库查询某某字段为空或者不为空的时候都是用is null或者is not null

如果查询条件使用=null或者<>null是查不出来数据的

但是赋值却可以用=null如


update BUS_PLATFORM.bus_trans set return_code = null where return_msg= 'tac验证通过';

这个是可以执行成功的,不过这个都是表外的值操作,那么当表内的数据有null时,又有啥坑呢,比如


select * from table1 where name <>'zhansan'

查询表中name字段不为zhangsan的数据,当表中有name为null的数据时,这些数据也是查不出来的.比如表中有100条数据,一条数据的name值为zhangsan ,九条数据的name值为null,那么这条sql只能查出90条数据,所以如果确切的需求要查询name值不为zhangsan的数据且包括name值为null的数据,sql应该为


select * from table1 where name <>'zhansan' or name is null

3:这个是mybatis的一个规范,基本是凑数的,不过也坑过我

先上内容:mybatis插入null值时需要指定该值的类型(jdbctype),不然会报错。

因为不指定类型的话mybatis会自己去适配匹配的数据库字段类型,null适配不了。搞不定就报错,很稳。不过一般使用xml配置sql的话一般都不会有这个问题,写的时候顺手都会写上。这个也是我使用TK的时候暴露出来的问题,在使用insert方法的时候有null就挂了,不过TK有个insertSelective方法做插入的时候会自动过滤掉空值。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: tk.mybatis如何扩展自己的通用mapper

本文链接: https://www.lsjlt.com/news/128079.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • tk.mybatis如何扩展自己的通用mapper
    tk.mybatis扩展自己的通用mapper 目的:tk.mybatis 提供的通用mapper,虽然使用方便,不过在有些sql还是不能满足我们的需要的,而且我们希望对于delet...
    99+
    2022-11-12
  • tk.mybatis怎么扩展自己的通用mapper
    小编给大家分享一下tk.mybatis怎么扩展自己的通用mapper,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!tk.mybatis扩展自己的通用mapper目的:tk.mybatis 提供的通用mapper,虽然使用方...
    99+
    2023-06-15
  • 扩展tk.mybatis的流式查询功能如何实现
    本篇内容主要讲解“扩展tk.mybatis的流式查询功能如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“扩展tk.mybatis的流式查询功能如何实现”吧!mybatis查询默认是一次获取...
    99+
    2023-06-21
  • spring拓展之如何定义自己的namespace
    目录spring拓展 定义自己的namespace1.查看源码认识spring是怎么加载xml配置的2.定义自己的namespacespring-namespace实现自定义标签类1...
    99+
    2022-11-12
  • 使用cluster 将自己的Node服务器扩展为多线程服务器
    用nodejs的朋友都有了解,node是单线程的,也就是说跑在8核CPU上,只能使用一个核的算力。 单线程一直是node的一个诟病,但随着0.6版本中引入cluster之后,这个情况则得到了改变,开发人员可...
    99+
    2022-06-04
    自己的 服务器 多线程
  • PHP8如何通过Attributes扩展类的功能?
    PHP8如何通过Attributes扩展类的功能?在PHP8中,引入了一个新的功能-Attributes,也被称为是属性。它可以为类、类的属性、方法和函数等实体添加元数据,并且这些元数据可以在运行时被访问和使用。Attributes提供了一...
    99+
    2023-10-25
    PHP Attributes 扩展类
  • win7如何关闭隐藏己知文件类型的扩展名
    这篇文章主要讲解了“win7如何关闭隐藏己知文件类型的扩展名”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“win7如何关闭隐藏己知文件类型的扩展名”吧!方法:在当前目录下,有一个word文件...
    99+
    2023-06-27
  • 如何使用AJAX扩展器自定义控件
    小编给大家分享一下如何使用AJAX扩展器自定义控件,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!掩码编辑功能的必要性在 HTML 中,接受输入数据的唯一方式是使用 <input>...
    99+
    2022-10-19
  • node如何通过express搭建自己的服务器
    这篇文章将为大家详细讲解有关node如何通过express搭建自己的服务器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。安装express框架传送门: express官方...
    99+
    2022-10-19
  • PHP的runkit扩展如何使用
    目录动态修改常量安装查看超全局变量键方法相关操作类方法相关操作总结动态修改常量 define('A', 'TestA'); runkit_constant_redefine('...
    99+
    2022-11-12
  • 如何使用PHP的runkit扩展
    这篇文章主要介绍了如何使用PHP的runkit扩展,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。php的框架有哪些php的框架:1、Laravel,Laravel是一款免费并...
    99+
    2023-06-15
  • 详解如何开发一个MyBatis通用Mapper的轮子
    目录一、前言二、需求三、实现原理四、代码实现1、自定义注解2、几个pojo,用来保存实体对应的信息3、定义开头说的BaseMapper4、SqlProvider5、实体类转Table...
    99+
    2022-12-21
    MyBatis通用Mapper轮子 MyBatis Mapper轮子 MyBatis Mapper
  • python如何打出自己的名字,怎么用python写自己名字
    大家好,给大家分享一下python如何打出自己的名字,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!   可以使用Python编写一个简单的程序来输出姓名、学号、班级等信息,代码如下: print(...
    99+
    2023-10-24
    python
  • RHEL6.7下通用二进制包如何安装MongoDB 3.2.4与mongoDB的php扩展
    RHEL6.7下通用二进制包如何安装MongoDB 3.2.4与mongoDB的php扩展,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 ...
    99+
    2022-10-18
  • python如何引用自己写的模块
    要引用自己写的模块,可以按照以下步骤进行操作:1. 在你的模块所在的文件夹中创建一个空白的`__init__.py`文件。这个文件是...
    99+
    2023-09-25
    python
  • 如何用自己的电脑架设vps
    要在自己的电脑上架设VPS,你需要按照以下步骤进行操作:1. 确定你的电脑操作系统是否支持虚拟化技术,如Intel的VT-x或AMD...
    99+
    2023-09-14
    vps
  • python自己封装的类如何调用
    要调用自己封装的类,需要按照以下步骤进行操作:1. 在代码中导入自己封装的类。例如,如果你的类定义在一个名为`myclass.py`...
    99+
    2023-08-24
    python
  • 如何使用Gitee管理自己的代码
    如今,代码管理已经成为了每个程序员必备的一项技能。而作为一名中国的程序员,使用国内的代码管理工具更是必不可少。Gitee作为国内一款优秀的代码管理工具,在开源社区中广受欢迎。本文将为大家介绍如何使用Gitee管理自己的代码。一、注册Gite...
    99+
    2023-10-22
  • Linux内核如何打造WWAN子系统以发展通用驱动并加强扩展能力
    本篇文章给大家分享的是有关Linux内核如何打造WWAN子系统以发展通用驱动并加强扩展能力,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Linaro继续领导Linux内核的无线...
    99+
    2023-06-15
  • 如何使用SQL Mail收发和自动处理邮件中的扩展存储
    如何使用SQL Mail收发和自动处理邮件中的扩展存储,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、启动SQL Mailxp_star...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作