小编给大家分享一下tk.mybatis怎么扩展自己的通用mapper,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!tk.mybatis扩展自己的通用mapper目的:tk.mybatis 提供的通用mapper,虽然使用方
小编给大家分享一下tk.mybatis怎么扩展自己的通用mapper,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
目的:tk.mybatis 提供的通用mapper,虽然使用方便,不过在有些sql还是不能满足我们的需要的,而且我们希望对于deleted语句进行管控(因为通用mapper提供的都是物理删除,有时我们对一些敏感数据只能进行逻辑删除),因此我们将基于原有的通用mapper进行自己的扩展
<!-- 非SpringBoot --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.4.0</version> </dependency>
<!-- springboot --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>2.0.2</version> </dependency>
springboot项目直接引这个包,本次我们将基于springboot进行开发,这里注意jar包版本,过低的版本将会出现问题,下面会介绍
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就会出现这个问题,更换更高的版本就可以解决了。
因为我们使用的是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")@Datapublic 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。
最近公司有几个项目的数据库用的oracle,有段时间没用,然后果断就掉坑里面了,记录几个比较有代表性的。
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起来,自以为是的经验有时候也很坑的。
先复习一下
一般数据库查询某某字段为空或者不为空的时候都是用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
先上内容:mybatis插入null值时需要指定该值的类型(jdbctype),不然会报错。
因为不指定类型的话mybatis会自己去适配匹配的数据库字段类型,null适配不了。搞不定就报错,很稳。不过一般使用xml配置sql的话一般都不会有这个问题,写的时候顺手都会写上。这个也是我使用TK的时候暴露出来的问题,在使用insert方法的时候有null就挂了,不过TK有个insertSelective方法做插入的时候会自动过滤掉空值。
看完了这篇文章,相信你对“tk.mybatis怎么扩展自己的通用mapper”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网精选频道,感谢各位的阅读!
--结束END--
本文标题: tk.mybatis怎么扩展自己的通用mapper
本文链接: https://lsjlt.com/news/280087.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
2024-05-24
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0