mybatis实践篇(一)

日志(logImpl)

StdOutImpl
  <setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>

Slf4jImpl
<setting name="logImpl" value="org.apache.ibatis.logging.slf4j.Slf4jImpl"/>
引入maven文件
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.12</version>
</dependency>
编写配置文件
org.slf4j.simpleLogger.defaultLogLevel=debug
org.slf4j.simpleLogger.showDateTime=true
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss
org.slf4j.simpleLogger.levelInBrackets=true
org.slf4j.simpleLogger.logFile=System.out

执行器

默认执行器(SimpleExecutor)
try(SqlSession sqlSession = sqlSessionFactory.openSession()) {// 使用SqlSession获取映射器实例FullCityMapper mapper = sqlSession.getMapper(FullCityMapper.class);// 使用映射器执行操作FullCity fullCity = mapper.selectByName("广东省");System.out.println("城市的名称:"+fullCity.getName());
}
重用执行器(ReuseExecutor)
try(SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE)) {// 使用SqlSession获取映射器实例FullCityMapper mapper = sqlSession.getMapper(FullCityMapper.class);// 使用映射器执行操作FullCity fullCity = mapper.selectByName("广东省");System.out.println("城市的名称:"+fullCity.getName());
}
批量执行器(BatchExecutor)
try(SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {// 使用SqlSession获取映射器实例FullCityMapper mapper = sqlSession.getMapper(FullCityMapper.class);// 使用映射器执行操作FullCity fullCity = mapper.selectByName("广东省");System.out.println("城市的名称:"+fullCity.getName());}

起别名

配置文件
    <typeAliases>
<!--        <typeAlias type="com.wyl.mybatis.entity.FullCity"/>--><package name="com.wyl.mybatis.entity"/></typeAliases>
mapper文件
<select id="selectByName" resultType="FullCity">select * from d_full_city where name = #{name}</select>

插件

注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {/*** Returns method signatures to intercept.** @return method signatures*/Signature[] value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {// Executor.classClass<?> type();// updateString method();// MappedStatement.class, Object.classClass<?>[] args();
}

主要用到了上面两个注解:@Intercepts和@Signature
方法名和参数的定义如下:

时间插件

作用:打印SQL语句执行的时间,分析慢查询原因(一般针对查询query来说)

package com.wyl.mybatis.intercept;import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;/*** @Description 时间插件* @Author WuYiLong* @Date 2024/2/29 9:51*/
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})
public class TimeIntercept implements Interceptor {private final  static Logger log = LoggerFactory.getLogger(TimeIntercept.class);@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement)args[0];MapperMethod.ParamMap pm = ( MapperMethod.ParamMap) args[1];Map<String, Object> paramsMap = new HashMap<>();pm.forEach((k,v)->{String key = String.valueOf(k);if(!key.contains("param")) {paramsMap.put(String.valueOf(k),v);}});BoundSql boundSql = ms.getBoundSql(ms.getParameterMap());// sql执行之前long startTime = System.currentTimeMillis();Object proceed = invocation.proceed();JSONArray jsonArray = JSONUtil.parseArray(proceed);long endTime = System.currentTimeMillis();log.info("----sql执行语句: {}",boundSql.getSql());log.info("----sql输入参数: {}", JSONUtil.toJsonStr(paramsMap));log.info("----sql输出结果数: {}", jsonArray.size());log.info("----sql执行花费时间: {}", (endTime-startTime)/1000);// sql执行之后return proceed;}
}
<plugins><plugin interceptor="com.wyl.mybatis.intercept.TimeIntercept"></plugin></plugins>
分页插件
FullCityMapper mapper = sqlSession.getMapper(FullCityMapper.class);
for (int i = 1; i <= 3 ; i++) {Page<FullCity> page = new Page<>(i, 10);List<FullCity> fullCities = mapper.selectFullCityPage(page);log.info("当前页:{}",page.getCurrentPage());log.info("页数:{}",page.getPageSize());log.info("总数:{}",page.getTotal());log.info("列表:{}", JSONUtil.toJsonStr(fullCities));
}

作用:mysql数据库物理分页,简化分页流程

package com.wyl.mybatis.page;import java.util.List;/*** @Description* @Author WuYiLong* @Date 2024/3/13 13:48*/
public class Page<T>  {private Integer currentPage = 1;private Integer pageSize = 10;private Integer total;private List<T> records;public Page(Integer currentPage,Integer pageSize) {this.currentPage = currentPage;this.pageSize = pageSize;}public Page(){};public Integer getCurrentPage() {return currentPage;}public void setCurrentPage(Integer currentPage) {this.currentPage = currentPage;}public Integer getPageSize() {return pageSize;}public void setPageSize(Integer pageSize) {this.pageSize = pageSize;}public Integer getTotal() {return total;}public void setTotal(Integer total) {this.total = total;}public List<T> getRecords() {return records;}public void setRecords(List<T> records) {this.records = records;}
}
 /*** 分页* @param page* @return*/@Select("select * from d_full_city")List<FullCity> selectFullCityPage(@Param("page") Page page);
package com.wyl.mybatis.intercept;import cn.hutool.db.sql.SqlBuilder;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.wyl.mybatis.config.SqlSessionFactoryConfig;
import com.wyl.mybatis.page.Page;
import com.wyl.mybatis.util.SqlParamUtil;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;/*** @Description* @Author WuYiLong* @Date 2024/3/13 12:06*/
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}),@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class,CacheKey.class,BoundSql.class})})
public class PageIntercept implements Interceptor {private final static Logger log = LoggerFactory.getLogger(PageIntercept.class);@Overridepublic Object intercept(Invocation invocation) throws Throwable {Executor executor = (Executor) invocation.getTarget();Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];Object params = args[1];RowBounds rowBounds = (RowBounds) args[2];BoundSql boundSql = ms.getBoundSql(params);String sql = boundSql.getSql();ResultHandler resultHandler = (ResultHandler) args[3];Page page = null;Map<String, Object> paramMap = SqlParamUtil.filter(params);for (Map.Entry<String, Object> mapEntry : paramMap.entrySet()) {Object v = mapEntry.getValue();if (v instanceof Page) {page = (Page) v;}}if(page != null) {String countSql = countSql(sql);int count = 0;SqlSessionFactory sqlSessionFactory = SqlSessionFactoryConfig.buildSqlSessionFactory();try (SqlSession sqlSession = sqlSessionFactory.openSession()) {Connection connection = sqlSession.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(countSql);ResultSet resultSet = preparedStatement.executeQuery();while (resultSet.next()) {count = resultSet.getInt("count");}}page.setTotal(count);rowBounds = new RowBounds(page.getCurrentPage()-1,page.getPageSize());}CacheKey cacheKey;if (args.length == 4) {cacheKey = executor.createCacheKey(ms, params, rowBounds, boundSql);} else {cacheKey = (CacheKey) args[4];boundSql = (BoundSql) args[5];}List<Object> query = executor.query(ms, params, rowBounds, resultHandler, cacheKey, boundSql);return query;}@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {return Plugin.wrap(target, this);}return target;}private String countSql(String sql) {SqlBuilder sqlBuilder = new SqlBuilder();sqlBuilder.select("count(*) count");List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);SQLSelectStatement sqlStatement = (SQLSelectStatement) sqlStatements.get(0);MySqlSelectQueryBlock queryBlock = (MySqlSelectQueryBlock) sqlStatement.getSelect().getQueryBlock();sqlBuilder.from(queryBlock.getFrom().toString());if (queryBlock.getWhere() != null) {sqlBuilder.where(queryBlock.getWhere().toString());}return sqlBuilder.build();}
}
 <plugins><plugin interceptor="com.wyl.mybatis.intercept.PageIntercept"></plugin></plugins>

这里需要注意的是CacheKey缓存key,因为sql的变化直接影响了查询的输出,从上面可以看出分页参数,是不需要用户输入的,通过内置分页插件即可完成分页,所以说sql实质上是没有发生变化的,从而导致重新生成的缓存key都是一样的,如源码所示:

 @Overridepublic CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (closed) {throw new ExecutorException("Executor was closed.");}CacheKey cacheKey = new CacheKey();cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();// mimic DefaultParameterHandler logicfor (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}cacheKey.update(value);}}if (configuration.getEnvironment() != null) {// issue #176cacheKey.update(configuration.getEnvironment().getId());}return cacheKey;}

看到了cacheKey的update方法,所以我们只需要每次请求改变其中之一即可,很明显,我们改变下RowBounds对象的参数就好,这个对象也是控制行数的,从它的名字就可以直接看出来。

项目地址

demo地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/751429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cannot find -xml2: No such file or directory的解决方法

一&#xff0c;问题现象 在编译库的时候出现如下图所示的报错&#xff1a;C:/msys64/mingw32/bin/…/lib/gcc/i686-w64-mingw32/13.2.0/…/…/…/…/i686-w64-mingw32/bin/ld.exe: ca nnot find -lxml2: No such file or directory collect2.exe: error: ld returned 1 exit s…

146 Linux 网络编程2 ,Socket编程,如何创建Linux 服务器 和linux 客户端

IPport 就是一个程序在网络上的身份证号码。 这意味着我们需要如果写一个服务器&#xff0c;至少需要将这台服务器的ip 和 端口号写到程序里面。 实际上更细化的说&#xff1a;应该是将这三都写进程序里面 &#xff1a; IP类型&#xff08;IPV4或者IPV6&#xff09;&#xff…

linux——进程(1)

目录 一、概念 1.1、认识进程 1.2、进程描述符&#xff08;PCB&#xff09; 1.3、进程的结构体&#xff08;task_struct&#xff09; 二、查看进程 三、获取进程的Pid和PPid 3.1、通过系统调用获取进程的PID和PPID 四、创建进程 4.1、fork() 4.2、用if进行分流 五、…

NCV1117ST50T3G线性稳压器芯片中文资料规格书PDF数据手册引脚图图片价格参数

产品概述&#xff1a; NCP1117系列为低压差&#xff08;LDO&#xff09;正向线性电压稳压器&#xff0c;能够提供超过1.0A的输出电流&#xff0c;800mA时温度范围内最大压差为1.2V。这一系列包括八个固定输出电压&#xff1a;1.5V、1.8V、2.0V、2.5V、2.85V、3.3V、5.0V 和 12…

2024/3/15 记录简版抖音部署遇到的问题

1、Centos连不上网 参考这一篇&#xff1a;虚拟机 CentOS 有线连接图标直接消失&#xff0c;网络连接不上&#xff0c;网络连接失败的解决方案&#xff08;亲测有效&#xff09;_centos网络图标不见了-CSDN博客 2、SQLyog连接不到docker中的mysql 原因是对密码有加密过程 &a…

STM32F407_多点电容触摸(GT911)驱动

目录标题 前言1、简单介绍2、触摸芯片与主机的硬件连接3、内部寄存器3.1、控制寄存器&#xff08;0X8040&#xff09;3.2、配置寄存器组&#xff08;0X8047~0X8100&#xff09;3.3、状态寄存器(0x814E)3.4、坐标寄存器(0x8150-0x8177) 4、初始化流程4.1、IIC地址选择4.2、更新G…

html--简历

文章目录 html html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"maximum-scale1.0,minimum-scale1.0,user-scalable0,widthdevice-width,initial-scale1.0&qu…

字母异位词分组【每日一题】

可以通过案例找到规律&#xff0c;每个词排序完后是同一个&#xff0c;所以通过hasmap存储排序过的值做key&#xff0c;值是存储单词集合。 package HasTable;import java.util.*;class Solution {static List<List<String>> groupAnagrams(String[] strs) {Map&l…

jupyter notebook 突然莫名奇妙的白屏

jupyter notebook 突然莫名奇妙的白屏 事件背景&#xff1a; 最近在折腾openai&#xff0c;哎&#xff0c;一言难尽&#xff0c;使用的是conda管理python版本的切换&#xff0c;使用jupyter notebook来运行python程序&#xff0c;其实PyCharm也行&#xff0c;但是&#xff0c;…

【递归搜索回溯专栏】专题二:二叉树中的深搜----二叉树剪枝

本专栏内容为&#xff1a;递归&#xff0c;搜索与回溯算法专栏。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;递归搜索回溯专栏 &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

redis发布订阅与stream类型

发布订阅 redis发布订阅(pub/sub)是一种消息通信模式&#xff1b;发送者(pub)发送消息&#xff0c;订阅者(sub)接收消息。redis客户端可以订阅任意数量的频道。 基础命令&#xff1a; 语法 redis publish命令基本语法如下&#xff1a; redis 127.0.0.1:6379> PUBLISH ch…

Matlab|考虑可再生能源消纳的电热综合能源系统日前经济调度模型

目录 1 主要内容 模型示意图 目标函数 程序亮点 2 部分程序 3 程序结果 4 下载链接 1 主要内容 本程序参考文献《考虑可再生能源消纳的建筑综合能源系统日前经济调度模型》模型&#xff0c;建立了电热综合能源系统优化调度模型&#xff0c;包括燃气轮机、燃气锅炉、余热…

Python基础(七)之数值类型集合

Python基础&#xff08;七&#xff09;之数值类型集合 1、简介 集合&#xff0c;英文set。 集合&#xff08;set&#xff09;是由一个或多个元素组成&#xff0c;是一个无序且不可重复的序列。 集合&#xff08;set&#xff09;只存储不可变的数据类型&#xff0c;如Number、…

修改yolov9的模型打印不出来Gflops的解决办法

正在修改yolov9的模块&#xff0c;发现修改后的模型没有GFlops这个参数 解决办法&#xff1a; 找到utils/torch_utils.py这个文件&#xff0c;有一个model_info函数 然后将其中的stride改为固定的640就可以打印了。 stride max(int(model.stride.max()), 32) if hasattr(mo…

telnet命令使用

window启用telnet telnet命令连接服务端 启动netty服务端后&#xff0c;使用如下cmd命令连接服务端&#xff0c;按enter&#xff0c;将连接到netty服务端 再按CTRL ]&#xff0c;进入命令交互界面 输入 help&#xff0c;查看命令介绍 发送消息&#xff0c;再断开连接&…

Linux:系统初始化,内核优化,性能优化(2)

优化ssh协议 Linux&#xff1a;ssh配置_ssh配置文件-CSDN博客https://blog.csdn.net/w14768855/article/details/131520745?ops_request_misc%257B%2522request%255Fid%2522%253A%2522171068202516800197044705%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fb…

拜占庭将军问题相关问题

1、拜占庭将军问题基本描述 问题 当我们讨论区块链共识时&#xff0c;为什么会讨论拜占庭将军问题&#xff1f; 区块链网络的本质是一个分布式系统&#xff0c;在存在恶意节点的情况下&#xff0c;希望 整个系统当中的善良节点能够对于重要的信息达成一致&#xff0c;这个机…

2024年3月18日 十二生肖 今日运势

小运播报&#xff1a;2024年3月18日&#xff0c;星期一&#xff0c;农历二月初九 &#xff08;甲辰年丁卯月辛巳日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;牛、鸡、猴 需要注意&#xff1a;鼠、虎、猪 喜神方位&#xff1a;西南方 财神方位&#xff1a;…

分数相加减(C语言)

一、流程图&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int fenmu 2;int result 1;int fuhao 1;//执行循环&#xff1b;while (fenmu < 100){//运算&#xff1b;fuhao (-1…

mvnd 安装和配置

mvnd 是 maven 的增强工具&#xff0c;在执行速度方面优于 maven 下载安装&#xff1a; https://github.com/apache/maven-mvnd/releases/ 根据不同的系统下载不同的安装包 配置环境变量 Path 新增 mvnd 安装路径下的 bin 目录 E:\maven-mvnd-1.0-m8-m39-windows-amd64\b…