tk.mybatis通用工具pom

 <!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency> <!--通用mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.5</version>
</dependency>
  • 我使用springboot搭建,所以引用的都是springboot封装的组件

采坑点

批量插入数据,默认主键只支持id

  1. 继承此工具MySqlMapper方法后
/**
* 通用Mapper接口,MySql独有的通用方法
*
* @param <T> 不能为空
* @author liuzh
*/
public interface MySqlMapper<T> extends
InsertListMapper<T>,
InsertUseGeneratedKeysMapper<T> { }
  • 可以看到存在可以批量插入类到数据库的方法
  • 如果项目中途加入了此工具,那么恭喜,估计要踩很多坑~
  • 数据库表主键不为id时,可以继续看源码
public interface InsertListMapper<T> {

    /**
* 批量插入,支持批量插入的数据库可以使用,例如MySQL,H2等,另外该接口限制实体包含`id`属性并且必须为自增列
*
* @param recordList
* @return
*/
@Options(useGeneratedKeys = true, keyProperty = "id")
@InsertProvider(type = SpecialProvider.class, method = "dynamicSQL")
int insertList(List<T> recordList); /**
* ======如果主键不是id怎么用?==========
* 假设主键的属性名是uid,那么新建一个Mapper接口如下
* <pre>
public interface InsertUidListMapper<T> {
@Options(useGeneratedKeys = true, keyProperty = "uid")
@InsertProvider(type = SpecialProvider.class, method = "dynamicSQL")
int insertList(List<T> recordList);
}
* 只要修改keyProperty = "uid"就可以
*
* 然后让你自己的Mapper继承InsertUidListMapper<T>即可
*
* </pre>
*/
}
  • 他留着坑还是很负责的把解决办法留下了~~
  • 我是按网上通用的搭建方式搭建的目录结构,也就是如下结构
/**
* 继承自己的MyMapper
*
*/
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
//FIXME 特别注意,该接口不能被扫描到,否则会出错
//FIXME 最后在启动类中通过MapperScan注解指定扫描的mapper路径:
}
  • 因为InsertUidListMapper这种特殊写的mapper和MyMapper是同一类,如果不同样配置下会报如下错误
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL).  Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider
  • 这时候你要,在application.properties中,把InsertUidListMapper路径配上去
mapper.mappers=com.tzxylao.manager.utils.MyMapper,com.tzxylao.manager.mapper_ext.InsertUidListMapper
  • 还有一点,光这样匹配后还不够,自己写的类DpageConfigMapper,继承InsertUidListMapper这个类后,把DpageConfigMapper类放在Mapper目录下,那么又会很纠结。系统启动会扫描不到DpageConfigMapper这个类。。我竟然找不到默认扫描Mapper包的地方。。但是经验告诉我,继承了MyMapper的类都能被扫描到~~
  • 可是自己的类继承的是InsertUidListMapper,想要它被扫描,启动类就要加上扫描包的地方。。我扫描了整个Mapper包
@EnableTransactionManagement  // 启注解事务管理,等同于xml配置方式的
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAutoConfiguration
@MapperScan("com.tzxylao.manager.mapper")
public class Application extends SpringBootServletInitializer { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
  • 但这样要注意,继承类InsertUidListMapper,不能再这个包里,否则会报该类不能被扫描错误~~
  • 就算把这个类移到了其他包,系统也可以正常运行了。。其实还是有点问题。。启动的时候会出现类似的警告
Skipping MapperFactoryBean with name 'sysMenuMapper' and 'com.telchina.framework.sys.mapper.SysMenuMapper' mapperInterface. Bean already defined with the same name!

虽然不影响使用,但还是看着烦,他的意思就是这个类被扫了两遍我就说哪里MyMapper类继承的类都被莫名其妙扫了一遍。。自己再配置扫一遍就重复了

  • 解决办法就是再建个子包,不继承MyMapper的自定义Mapper都放子包,再单独配置子包扫描
@EnableTransactionManagement  // 启注解事务管理,等同于xml配置方式的
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAutoConfiguration
@MapperScan("com.tzxylao.manager.mapper.ext")
public class Application extends SpringBootServletInitializer { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}

把DpageConfigMapper类放ext子包里就行了。。

  • 上面步骤都解决了,插入还是不成功的,插入语句没有主键,自己生成的主键插不进去?
  • 看源码
 /**
* 批量插入
*
* @param ms
*/
public String insertList(MappedStatement ms) {
final Class<?> entityClass = getEntityClass(ms);
//开始拼sql
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.insertIntoTable(entityClass, 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);
//当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值
for (EntityColumn column : columnList) {
if (!column.isId() && column.isInsertable()) {
sql.append(column.getColumnHolder("record") + ",");
}
}
sql.append("</trim>");
sql.append("</foreach>");
return sql.toString();
}
  • 可以看到,主键插入的地方,他有这样的判断!column.isId() && column.isInsertable(),所以,Bean类主键属性上@Id去掉,就可以自己添加主键值了

总结

  • 总觉的我的解决方法很low,限制也太大~有熟悉tk.mybatis的大神讲下别的思路吗?

tk.mybatis通用工具采坑记的更多相关文章

  1. 分布式改造剧集之Redis缓存采坑记

    Redis缓存采坑记 ​ 前言 ​ 这个其实应该属于分布式改造剧集中的一集(第一集见前面博客:http://www.cnblogs.com/Kidezyq/p/8748961.html),本来按照顺序 ...

  2. Spring Cloud Config采坑记

    1. Spring Cloud Config采坑记 1.1. 问题 在本地运行没问题,本地客户端服务能连上本地服务端服务,可一旦上线,发现本地连不上线上的服务 服务端添加security登录加密,客户 ...

  3. k8s采坑记 - 解决二进制安装环境下证书过期问题

    前言 上一篇k8s采坑记 - 证书过期之kubeadm重新生成证书阐述了如何使用kubeadm解决k8s证书过期问题. 本篇阐述使用二进制安装的kubernetes环境,如何升级过期证书? k8s配置 ...

  4. Redis适配采坑记

    Redis适配采坑记 相对于其他的适配,Redis可以说是非常简单的其中只发现一个坑 问题一: 问题描述: redis认证失败 问题详解: redis连接配置时,本地需要采用password属性,远程 ...

  5. 微信小程序后台springboot+mybatis+mysql“采坑”集锦

    "采坑"错误集锦 1.service层 错误描述:2019-04-14 22:09:52.027 ERROR 8416 --- [nio-8082-exec-5] o.a.c.c. ...

  6. dubbo初学采坑记

    写在前面的话 dubbo 现在是apache组织旗下的项目,相信国内也有很多人使用.最近一个同事离职,我就接手了他的项目.远程通讯就是用的dubbo框架来实现的.使用Intelij idea 写了一个 ...

  7. Service worker (@nuxtjs/workbox) 采坑记

    PWA(Progressive Web App)是前端的大趋势,它能极大的加快前端页面的加载速度,得到近乎原生 app 的展示效果(其实难说).PWA 其实是多种前端技术的组合,其中最重要的一个技术就 ...

  8. aidl使用采坑记

    什么是AIDL? AIDL是 Android Interface definition language的缩写,它是一种Android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口 A ...

  9. css选择器:first-child和nth-child 采坑记

    今天想用nth-child来给一个类似于树的目录(bootstrap-nav-tree  一个angularjs插件)设置不同的颜色,结构大致类似于 <ul> <li class=& ...

随机推荐

  1. React页面插入script

    项目中遇到插入广告的需要,而广告的信息只是一个url链接,这个链接返回的时一个js,和以前插入广告有点不同.所有找了很多方式. 先来展示广告链接返回的信息: 假设广告链接为:http://192.16 ...

  2. docker安装portainer

    安装好docker之后,可以使用portainer对容器进到管理 docker安装portainer命令 #这一步可以省略,直接运行可以下一条docker pull portainer #因为dock ...

  3. HALCON示例:BOTTLE.HDEV 光学字符识别(分割OCR)

    * * bottle.hdev: Segment and read numbers on a beer bottle 分割读取啤酒瓶上的数字* * Step 0: Preparations* Spec ...

  4. flash/flex builder在IE中stage.stageWidth始终为0的解决办法

    这应该是IE的bug,解决办法: 原作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com stage.align=StageAlign.TOP_LEFT; stage.scal ...

  5. jQueryEasyUI学习笔记

    data-options 是jQuery Easyui的一个特殊属性.通过这个属性,我们可以对easyui组件的实例化可以完全写入到html中 data-options="region:'w ...

  6. [leetcode]297. Serialize and Deserialize Binary Tree 序列化与反序列化二叉树

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  7. [leetcode]86. Partition List划分链表

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...

  8. Solidity的三种转账方式与比较

    转账的3种方式 123 address.transfer()address.send()address.call.value().gas()() 转账transfer 12345678910 func ...

  9. 每10秒执行定时任务-crontab

    * * * * * /data/crontab.sh * * * * * sleep 10; /data/crontab.sh * * * * * sleep 20; /data/crontab.sh ...

  10. CentOS7 开启网卡,设置开机启用网卡

    默认centos和redhat7都是不启用有线网卡的,要么手动开启,要么安装时直接启用(安装时启用网卡和指定IP最省事)! 一 .临时启用网卡,关机或重启后,网络不会自动开启1.使用命令 ip add ...