tk.mybatis通用工具采坑记
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
- 继承此工具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通用工具采坑记的更多相关文章
- 分布式改造剧集之Redis缓存采坑记
Redis缓存采坑记 前言 这个其实应该属于分布式改造剧集中的一集(第一集见前面博客:http://www.cnblogs.com/Kidezyq/p/8748961.html),本来按照顺序 ...
- Spring Cloud Config采坑记
1. Spring Cloud Config采坑记 1.1. 问题 在本地运行没问题,本地客户端服务能连上本地服务端服务,可一旦上线,发现本地连不上线上的服务 服务端添加security登录加密,客户 ...
- k8s采坑记 - 解决二进制安装环境下证书过期问题
前言 上一篇k8s采坑记 - 证书过期之kubeadm重新生成证书阐述了如何使用kubeadm解决k8s证书过期问题. 本篇阐述使用二进制安装的kubernetes环境,如何升级过期证书? k8s配置 ...
- Redis适配采坑记
Redis适配采坑记 相对于其他的适配,Redis可以说是非常简单的其中只发现一个坑 问题一: 问题描述: redis认证失败 问题详解: redis连接配置时,本地需要采用password属性,远程 ...
- 微信小程序后台springboot+mybatis+mysql“采坑”集锦
"采坑"错误集锦 1.service层 错误描述:2019-04-14 22:09:52.027 ERROR 8416 --- [nio-8082-exec-5] o.a.c.c. ...
- dubbo初学采坑记
写在前面的话 dubbo 现在是apache组织旗下的项目,相信国内也有很多人使用.最近一个同事离职,我就接手了他的项目.远程通讯就是用的dubbo框架来实现的.使用Intelij idea 写了一个 ...
- Service worker (@nuxtjs/workbox) 采坑记
PWA(Progressive Web App)是前端的大趋势,它能极大的加快前端页面的加载速度,得到近乎原生 app 的展示效果(其实难说).PWA 其实是多种前端技术的组合,其中最重要的一个技术就 ...
- aidl使用采坑记
什么是AIDL? AIDL是 Android Interface definition language的缩写,它是一种Android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口 A ...
- css选择器:first-child和nth-child 采坑记
今天想用nth-child来给一个类似于树的目录(bootstrap-nav-tree 一个angularjs插件)设置不同的颜色,结构大致类似于 <ul> <li class=& ...
随机推荐
- Windows 10同步时间的方法
今天在安装了Windows 10 1809(October 2018 update)之后发现时间不能同步,以前并没有出现这种情况. 1) 打开控制面板,找到时钟域地区 2) 选择日期和时间 3) 选择 ...
- Linux 网络配置文件解析
Linux 网络配置文件解析 网络配置文件路径/etc/sysconfig/network-scripts/ifcfg-* *代表网卡名 vim /etc/sysconfig/network- ...
- KALI安装与环境配置
2018-2019 201899224<网络攻防实践>第二周作业 虚拟化网络攻防实验环境包括以下部分: 靶机:包含系统和应用程序安全漏洞,并作为攻击目标的主机.(Windows XP和Li ...
- 使用 Composer 安装Laravel扩展包的几种方法
使用 Composer 安装Laravel扩展包的几种方法 以下的三种方法都是需要你在项目的根目录运行 第一种:composer install 如有 composer.lock 文件,直接安装,否则 ...
- load 过高分析办法
1.top -H 找到占用cpu较高的进程2.top -Hp pid 找到该进程下占用cpu较高的线程id3.sudo -u adminjstack -F 进程id > ~/stack.txt ...
- Java的三种代理模式(Spring动态代理对象)
Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...
- cmp指令
cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果.cmp指令执行后,将对标志寄存器产生影响.其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果. cmp指令格式: cmp 操作对象 ...
- centos查看系统版本
显示系统版本 cat /etc/redhat-release cat /proc/version uname -a 查看位数 file /bin/ls
- Linux Curl命令
一.简介 linux curl是一个利用URL规则在命令行下工作的文件传输工具.它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称url为下载工具. 二.安装 wget http://c ...
- 网络编程初识和socket套接字
网络的产生 不同机器上的程序要通信,才产生了网络:凡是涉及到倆个程序之间通讯的都需要用到网络 软件开发架构 软件开发架构的类型:应用类.web类 应用类:qq.微信.网盘.优酷这一类是属于需要安装的桌 ...