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…

量化交易入门(二)量化交易有关的数学和统计学知识

量化交易有关的数学和统计学知识包括&#xff1a;高等数学&#xff08;微积分、线性代数等&#xff09;、概率论与数理统计是量化分析的基础&#xff0c;时间序列分析是预测市场动向和金融数据分析的关键工具。 &#xff08;一&#xff09;、在量化分析和量化交易领域&#xf…

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进行分流 五、…

【PyQt错误集 - 1】:PyQt调用多线程导致窗口异常退出的问题分析(进程已结束,退出代码 -1073741819 (0xC0000005))

文章目录 问题分析解决方法 问题分析 运行以下程序&#xff1a; def run_thread_WTD(self):threading.Thread(targetself.WTD).start()def WTD(self):word_path self.word_path.text()# textBrowser为多行文本框QTextEditself.pycorrectorKenlm(word_path, textBrowser)# ke…

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…

FTP服务器的工作原理

1.1、概述 FTP服务器是网络中提供文件存储和访问服务的服务器&#xff0c;无论是个人还是企业&#xff0c;都可以搭建FTP服务器&#xff0c;用来上传数据、下载数据和共享文件。FTP采用C/S&#xff08;客户端/服务器&#xff09;架构&#xff0c;用户只要通过FTP客户端程序连接…

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;…

JAVA构造方法的作用

JAVA构造方法主要有以下作用&#xff1a; 1. 初始化对象的状态&#xff1a;构造方法用于创建对象时&#xff0c;可以初始化对象的实例变量和其他属性&#xff0c;为对象的状态赋初值。 2. 调用父类构造方法&#xff1a;构造方法还可以用来调用父类的构造方法&#xff0c;通过su…

uView Code 验证码输入框

考虑到用户实际发送验证码的场景&#xff0c;可能是一个按钮&#xff0c;也可能是一段文字&#xff0c;提示语各有不同&#xff0c;所以本组件 不提供界面显示&#xff0c;只提供提示语&#xff0c;由用户将提示语嵌入到具体的场景 #平台差异说明 App&#xff08;vue&#xf…

lqb省赛日志[11/37] -[dfs]

一只小蒟蒻备考蓝桥杯的日志 文章目录 笔记刷题心得小结 笔记 最近对二维数组[][]&#xff0c;xy的区分好混乱啊。。。 刷题 P1101 单词方阵P2404 自然数的拆分问题P1596 [USACO10OCT] Lake Counting SP1162 填涂颜色 心得 莫名其妙就爆0了&#xff0c;但是样例对&#x…

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

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

git |常用命令

git 命令 非常常用 主流的仓库管理服务器&#xff0c;svn 和git 接下来&#xff0c;介绍git 操作&#xff08;自用 先讲一个简单的demo 流程 环境&#xff1a;centos、git #先创建一个本地 git 文件夹 mkdir test && cd ./test #写一个README.md #echo “# 张不大 的de…

MySQL调优:explain详解

MySQL的EXPLAIN命令用于获取SQL查询的执行计划&#xff08;Execution Plan&#xff09;&#xff0c;它揭示了MySQL服务器如何执行给定的SELECT语句&#xff0c;包括如何连接表、使用索引以及MySQL优化器选择的查询路径等重要信息。这对于分析查询性能、找出潜在的瓶颈并优化SQL…

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;包括燃气轮机、燃气锅炉、余热…