做网站要用到数据库吗,做网站的意义大不大,wordpress相册标签分类,手机vi设计公司前言
处理做项目的问题#xff0c;其中不乏奇奇怪怪的问题#xff0c;其中mybatis plus的问题感觉有点隐蔽#xff0c;有些是运行时出现#xff0c;有些是运行到具体的逻辑触发#xff0c;对于应用的状态监控提出了极大的挑战#xff0c;应用的状态由健康检查接口提供其中不乏奇奇怪怪的问题其中mybatis plus的问题感觉有点隐蔽有些是运行时出现有些是运行到具体的逻辑触发对于应用的状态监控提出了极大的挑战应用的状态由健康检查接口提供或者TCP或者HTTP那么健康检查要怎么写呢比如K8S一般使用HTTP GET方式要定时监控POD状态。
准备
准备SpringBoot与mybatis的demo这个参考SpringBoot官网即可数据库使用MySQL docker部署毕竟docker部署方便Basic Steps for MySQL Server Deployment with Docker
docker run --name mysql_8.0 -e MYSQL_ROOT_PASSWORD123456i -d -i -p 3306:3306 container-registry.oracle.com/mysql/community-server:8.0
就可以使用client连接上去然后建库表和demo数据需要修改非本地登录mysql的能力 更新root登录限制开放 确认OK 造数据 mybatis plus的Id相同
依赖如下 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdversion2.3.0.RELEASE/version/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.1.3/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.3.2/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.33/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.6/version/dependency/dependencies
dao与配置、main类
SpringBootApplication
MapperScan(basePackages com.feng.boot.mybatis.demo.dao)
public class MybatisMain {public static void main(String[] args) {SpringApplication.run(MybatisMain.class, args);}
}Mapper
public interface DemoDao {Select(select * from user)ListUser selectUser();Select(select * from user where name #{name})ListUser selectUser(String name);}RestController
public class DemoController {LazyAutowiredprivate DemoDao demoDao;RequestMapping(/user)public ListUser listUser(String name){return demoDao.selectUser(name);}
SpringBoot数据源配置自行处理启动后日志 _ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\ / | 3.3.2
2024-01-09 21:27:34.043 ERROR 3340 --- [ main] c.b.m.core.MybatisConfiguration : mapper[com.feng.boot.mybatis.demo.dao.DemoDao.selectUser] is ignored, because it exists, maybe from xml file
但是 启动不会保错如果是mybatis的starter则启动直接保错
让我们访问http://localhost:8080/user?namedemo
理论上只会有一条结果然而 2条什么原因呢开启trace日志 为啥不是我方法的执行结果SQL都不对这其实是mybatis plus留下的坑 源码分析
启动过程就埋了坑在
com.baomidou.mybatisplus.core.MybatisMapperAnnotationBuilder
通过generateResultMapName生成mybatis的Id时mybatis plus做了定制 private String generateResultMapName(Method method) {Results results method.getAnnotation(Results.class);if (results ! null !results.id().isEmpty()) {return type.getName() . results.id();}StringBuilder suffix new StringBuilder();//参数拼接for (Class? c : method.getParameterTypes()) {suffix.append(-);suffix.append(c.getSimpleName());}//如果没有参数使用-voidif (suffix.length() 1) {suffix.append(-void);}//类名方法名参数类型拼接return type.getName() . method.getName() suffix;}
所以对于mybatis plus对于方法重载不存在id冲突的可能性在
com.baomidou.mybatisplus.core.MybatisConfiguration 所以出现启动时的error日志然后直接return了所以下面的第2条是没有载入mappedstatement 所以SQL永远是第1条无论我们怎么调用
mybatis-starter
原生的mybatis-starter的org.apache.ibatis.builder.annotation.MapperAnnotationBuilder
实际上id也差不多也是通过-void方式实现无参数id 但是在org.apache.ibatis.builder.MapperBuilderAssistant
会使用不带参数的Id来做校验在org.apache.ibatis.session.Configuration 而不是像mybatis plus那样直接return了。
解决方法
无非是id冲突只要安装方法名唯一的情况即可不使用方法重载 结果OK mybatis的xml配置错误的情况
如果使用xml配置那么也会存在出现错误的情况
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.feng.boot.mybatis.demo.dao.DemoDao!--select idselectUser parameterTypejava.lang.String resultTypecom.feng.boot.mybatis.demo.entity.Userselect * from user where name #{name}/select--select idselectUser parameterTypejava.lang.String resultMapcom.feng.boot.mybatis.demo.entity.Userselect * from user where name #{name}/selectselect idselectUsers resultTypecom.feng.boot.mybatis.demo.entity.Userselect * from user/select/mapper
笔者故意写错selectUser的xml但是笔者在调用 RequestMapping(/users)public ListUser listUser(){return demoDao.selectUsers();}
跟第1个xml毫无关系但是调用报错
java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.feng.boot.mybatis.demo.entity.Userat org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:1031) ~[mybatis-3.5.6.jar:3.5.6] 其实这个都还好关键是启动毫无错误然而执行任意一条正确的SQL却报错了莫非mybatis绝得还可以抢救一下。而且错误信息可以跟正确执行的逻辑毫无相关如果启动后仅仅看启动日志就会埋下极大隐患需要健康检查覆盖mybatis才行。
源码分析
在mybatis的源码中org.apache.ibatis.session.Configuration mybatis的设计是在任意statement执行前执行未完成态的statement执行快速失败既然知道未完成为什么启动不报错也不任何日志提示呢 根源来自org.apache.ibatis.builder.xml.XMLMapperBuilder xml解析失败并不是报错也没有日志直接放在了未完成的statement这里好歹给个日志啊估计mybatis是准备支持抢救一下不对是支持statement在运行态注入一些数据实现完成态。
总结
mybatis plus这个是直接丢弃相同Id的statement安装先后顺序会造成执行过程的误解不过有日志可以查看而且mybatis原生的starter是有校验的直接报错了。mybatis的xml如果写错那么启动居然不报错执行任意statement前需要执行未完成的statement来达到快速失败的情况这种情况对健康检查提出了新挑战否则可能出现启动OK但是mybatis失败的情况。