平台规划方案怎么写,优化步骤,建设棋牌类网站要多少钱,汕头网站上排名文章目录 MyBatis拦截器可以做什么#xff1f;Mybatis核心对象介绍四大核心对象如何实现#xff1f;接口讲解Interceptor接口intercept方法plugin方法setProperties 完整SQL打印拦截器实战拦截器实现拦截器注册 MyBatis拦截器可以做什么#xff1f;
MyBatis拦截器是MyBatis… 文章目录 MyBatis拦截器可以做什么Mybatis核心对象介绍四大核心对象如何实现接口讲解Interceptor接口intercept方法plugin方法setProperties 完整SQL打印拦截器实战拦截器实现拦截器注册 MyBatis拦截器可以做什么
MyBatis拦截器是MyBatis框架提供的扩展机制它可以在执行SQL语句的过程中拦截和干预用于对SQL语句进行增强或修改。
MyBatis拦截器可以做以下几件事情
拦截SQL语句的执行拦截器可以在SQL语句执行前后进行拦截可以在SQL语句执行之前对参数进行处理也可以在SQL语句执行之后对结果进行处理。修改SQL语句拦截器可以对原始的SQL语句进行修改可以增加、删除或修改SQL语句的部分内容以满足一些特定需求。比如可以在SQL语句前后添加额外的条件或修改排序方式。记录日志拦截器可以用于记录SQL语句的执行日志包括SQL语句的执行时间、执行结果等。这对于系统的性能监控和调优非常有帮助。实现分页功能拦截器可以在执行原始SQL语句之前根据传入的参数进行分页处理将查询结果限制在指定的页数和每页的记录数范围内。实现缓存功能拦截器可以在执行SQL语句之前先检查缓存中是否存在对应的结果如果存在则直接返回缓存结果避免不必要的数据库查询操作。在很多时候对表中的数据都需要记录插入时间修改时间插入人和修改人若每次都在插入或修改代码中去设置这些信息就显得有些冗余。那么此时可以通过Mybatis提供的拦截器加上我们自定义的拦截器实现对在需要记录的操作人信息sql执行前自动补充这些信息也就是所谓的对Mybatis的核心对象进行增强。这里只拦截Executor对象给更新的sql语句动态的增加参数。可参考https://www.cnblogs.com/zys2019/p/16966866.html 具体例子 我们常用的分页插件Pagehelper其实就是一个拦截器实现 Mybatis核心对象介绍
MyBatis的主要的核心部件有以下几个
Configuration初始化基础配置比如MyBatis的别名等一些重要的类型对象如插件映射器ObjectFactory和typeHandler对象MyBatis所有的配置信息都维持在Configuration对象之中。SqlSessionFactorySqlSession工厂。SqlSession作为MyBatis工作的主要顶层API表示和数据库交互的会话完成必要的数据库增删改查功能。ExecutorMyBatis的内部执行器它负责调用StatementHandler操作数据库并把结果集通过ResultSetHandler进行自动映射另外它还处理二级缓存的操作。StatementHandlerMyBatis直接在数据库执行SQL脚本的对象。另外它也实现了MyBatis的一级缓存。ParameterHandler负责将用户传递的参数转换成JDBC Statement所需要的参数。是MyBatis实现SQL入参设置的对象。ResultSetHandler负责将JDBC返回的ResultSet结果集对象转换成List类型的集合。是MyBatis把ResultSet集合映射成POJO的接口对象。TypeHandler负责Java数据类型和JDBC数据类型之间的映射和转换。MappedStatementMappedStatement维护了一条select|update|delete|insert节点的封装。SqlSource 负责根据用户传递的parameterObject动态地生成SQL语句将信息封装到BoundSql对象中并返回。BoundSql表示动态生成的SQL语句以及相应的参数信息。 四大核心对象
在Mybatis中Executor、StatementHandler、ParameterHandler和ResultSetHandler是核心组件它们分别负责不同的任务。
Executor统筹全局 Executor是Mybatis中的执行器它负责处理数据库的操作。它的职责是接收并执行SQL语句管理事务的提交和回滚以及处理缓存。 在Mybatis中有三种类型的ExecutorSimpleExecutor、ReuseExecutor和BatchExecutor它们分别提供了不同的执行策略。StatementHandler执行SQL StatementHandler负责处理SQL语句的操作它是Executor的一个重要组成部分。它的主要职责是创建PreparedStatement对象设置参数并执行SQL语句。 StatementHandler可以根据不同的数据库厂商提供的驱动生成不同的Statement对象如PreparedStatement、CallableStatement等。ParameterHandler参数封装 ParameterHandler负责处理SQL语句中的参数。它的主要职责是将Java对象中的属性值映射到SQL语句中的参数位置。ParameterHandler可以根据参数的类型将Java对象的属性值转换为数据库可以接受的类型并设置到PreparedStatement对象中。ResultSetHandler返回结果映射 ResultSetHandler负责处理SQL语句的结果集。它的主要职责是将查询结果集中的数据映射到Java对象中。ResultSetHandler会根据映射规则将数据库中的每一行数据转换为Java对象并将这些对象放入一个集合中返回给调用者。 这四个组件在Mybatis中协同工作完成了从数据库操作到Java对象映射的整个过程。Executor负责整体的控制和协调StatementHandler负责处理SQL语句的操作ParameterHandler负责处理参数ResultSetHandler负责处理结果集。它们各自分工明确相互配合共同完成数据库操作和对象映射的任务。
如何实现接口讲解
写一个实现org.apache.ibatis.plugin.Interceptor接口的拦截器类并实现其中的方法。添加Intercepts注解写上需要拦截的对象和方法以及方法参数。Spring项目注意添加Component注解即可使其成为Spring管理的一个Bean。
Interceptor接口
Intercepts({Signature(type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),Signature(type StatementHandler.class, method prepare, args {Connection.class, Integer.class}),Signature(type ParameterHandler.class, method setParameters, args {PreparedStatement.class}),Signature(type ResultSetHandler.class, method handleResultSets, args {Statement.class})
})
public class MyInterceptor implements Interceptor {MyBatis拦截器默认可以拦截的类型只有四种即四种接口类型Executor、StatementHandler、ParameterHandler和ResultSetHandler。对于我们的自定义拦截器必须使用MyBatis提供的Intercepts注解来指明我们要拦截的是四种类型中的哪一种接口。
注解描述Intercepts标志该类是一个拦截器Signature指明该拦截器需要拦截哪一个接口的哪一个方法
Signature注解的参数
参数描述type四种类型接口中的某一个接口如Executor.class。method对应接口中的某一个方法名比如Executor的query方法。args对应接口中的某一个方法的参数比如Executor中query方法因为重载原因有多个args就是指明参数类型从而确定是具体哪一个方法。
MyBatis拦截器默认会按顺序拦截以下的四个接口中的所有方法
org.apache.ibatis.executor.Executor //拦截执行器方法
org.apache.ibatis.executor.statement.StatementHandler //拦截SQL语法构建处理
org.apache.ibatis.executor.parameter.ParameterHandler //拦截参数处理
org.apache.ibatis.executor.resultset.ResultSetHandler //拦截结果集处理
具体是拦截这四个接口对应的实现类
org.apache.ibatis.executor.CachingExecutor
org.apache.ibatis.executor.statement.RoutingStatementHandler
org.apache.ibatis.scripting.defaults.DefaultParameterHandler
org.apache.ibatis.executor.resultset.DefaultResultSetHandler intercept方法
进行拦截的时候要执行的方法。该方法参数Invocation类中有三个字段 private final Object target;private final Method method;private final Object[] args;
可通过这三个字段分别获取下面的信息
Object target invocation.getTarget();//被代理对象
Method method invocation.getMethod();//代理方法
Object[] args invocation.getArgs();//方法参数
plugin方法
插件用于封装目标对象的通过该方法我们可以返回目标对象本身也可以返回一个它的代理可以决定是否要进行拦截进而决定要返回一个什么样的目标对象官方提供了示例return Plugin.wrap(target, this);可以在这个方法中提前进行拦截对象类型判断提高性能 Overridepublic Object plugin(Object target) {//只对要拦截的对象生成代理if(target instanceof StatementHandler){//调用插件return Plugin.wrap(target, this);}return target;}
MyBatis拦截器用到责任链模式动态代理反射机制 所有可能被拦截的处理类都会生成一个代理类如果有N个拦截器就会有N个代理层层生成动态代理是比较耗性能的。而且虽然能指定插件拦截的位置但这个是在执行方法时利用反射动态判断的初始化的时候就是简单的把拦截器插入到了所有可以拦截的地方。所以尽量不要编写不必要的拦截器。另外我们可以在调用插件的地方添加判断只要是当前拦截器拦截的对象才进行调用否则直接返回目标对象本身这样可以减少反射判断的次数提高性能。
setProperties
如果我们拦截器需要用到一些变量参数而且这个参数是支持可配置的类似Spring中的Value(${})从application.properties文件获取自定义变量属性这个时候我们就可以使用这个方法。
private String property1;
private int property2;Overridepublic void setProperties(Properties properties) {// 从配置文件中获取属性值this.property1 properties.getProperty(property1);this.property2 Integer.parseInt(properties.getProperty(property2));}在setProperties方法中我们可以通过传入的Properties对象获取配置文件中的属性值并进行相应的处理。
然后在MyBatis的配置文件中注册自定义的拦截器
configuration!-- 其他配置 --pluginsplugin interceptorcom.example.CustomInterceptorproperty nameproperty1 valuevalue1 /property nameproperty2 value2 //plugin/plugins
/configuration完整SQL打印拦截器实战
拦截器实现
Slf4j
Intercepts({Signature(type Executor.class, method update, args {MappedStatement.class, Object.class}),Signature(type Executor.class,method query,args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class,BoundSql.class}
), Signature(type Executor.class,method query,args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)})
public class SqlPrintInterceptor implements Interceptor {Overridepublic Object intercept(Invocation invocation) throws Throwable {try {// 获取xml中的一个select/update/insert/delete节点是一条SQL语句MappedStatement mappedStatement (MappedStatement) invocation.getArgs()[0];Object parameter null;// 获取参数if语句成立表示sql语句有参数参数格式是map形式if (invocation.getArgs().length 1) {parameter invocation.getArgs()[1];log.info(SQL打印拦截器参数 parameter);}// 获取到节点的id, 即sql语句的idString sqlId mappedStatement.getId();//log.info(sqlId sqlId);// BoundSql就是封装myBatis最终产生的sql类BoundSql boundSql mappedStatement.getBoundSql(parameter);// 获取节点的配置Configuration configuration mappedStatement.getConfiguration();// 获取到最终的sql语句String sql getSql(configuration, boundSql, sqlId);log.info(SQL打印拦截器完整SQL sql);} catch (Exception e) {e.printStackTrace();}// 执行完上面的任务后不改变原有的sql执行过程return invocation.proceed();}// 封装了一下sql语句使得结果返回完整xml路径下的sql语句节点id sql语句private static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {String sql showSql(configuration, boundSql);StringBuilder str new StringBuilder(100);str.append(sqlId);str.append(:);str.append(sql);return str.toString();}// 如果参数是String则添加单引号 如果是日期则转换为时间格式器并加单引号 对参数是null和不是null的情况作了处理private static String getParameterValue(Object obj) {String value null;if (obj instanceof String) {value obj.toString() ;} else if (obj instanceof Date) {DateFormat formatter DateFormat.getDateTimeInstance(DateFormat.DEFAULT,DateFormat.DEFAULT, Locale.CHINA);value formatter.format(new Date()) ;} else {if (obj ! null) {value obj.toString();} else {value ;}}return value;}// 进行的替换private static String showSql(Configuration configuration, BoundSql boundSql) {// 获取参数Object parameterObject boundSql.getParameterObject();ListParameterMapping parameterMappings boundSql.getParameterMappings();// sql语句中多个空格都用一个空格代替String sql boundSql.getSql().replaceAll([\\s], );if (CollectionUtils.isNotEmpty(parameterMappings) parameterObject ! null) {// 获取类型处理器注册器类型处理器的功能是进行java类型和数据库类型的转换TypeHandlerRegistry typeHandlerRegistry configuration.getTypeHandlerRegistry();// 如果根据parameterObject.getClass(可以找到对应的类型则替换if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {sql sql.replaceFirst(\\?,Matcher.quoteReplacement(getParameterValue(parameterObject)));} else {// MetaObject主要是封装了originalObject对象提供了get和set的方法用于获取和设置originalObject的属性值,// 主要支持对JavaBean、Collection、Map三种类型对象的操作MetaObject metaObject configuration.newMetaObject(parameterObject);for (ParameterMapping parameterMapping : parameterMappings) {String propertyName parameterMapping.getProperty();if (metaObject.hasGetter(propertyName)) {Object obj metaObject.getValue(propertyName);sql sql.replaceFirst(\\?,Matcher.quoteReplacement(getParameterValue(obj)));} else if (boundSql.hasAdditionalParameter(propertyName)) {// 该分支是动态sqlObject obj boundSql.getAdditionalParameter(propertyName);sql sql.replaceFirst(\\?,Matcher.quoteReplacement(getParameterValue(obj)));} else {// 打印出缺失提醒该参数缺失并防止错位sql sql.replaceFirst(\\?, 缺失);}}}}return sql;}Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}Overridepublic void setProperties(Properties properties) {}
}
拦截器注册
主要是这一句bean.setPlugins(new Interceptor[]{ new SqlPrintInterceptor()});
Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {//设置分页的拦截器PageInterceptor pageInterceptor new PageInterceptor();//创建插件需要的参数集合Properties properties new Properties();//配置数据库方言 为oracleproperties.setProperty(helperDialect, mysql);//配置分页的合理化数据properties.setProperty(reasonable, true);pageInterceptor.setProperties(properties);SqlSessionFactoryBean bean new SqlSessionFactoryBean();bean.setPlugins(new Interceptor[]{ new SqlPrintInterceptor()});bean.setDataSource(dataSource);bean.setMapperLocations(resolveMapperLocations());//重点2 指定包扫描,当前这个数据源对应的mapper.xml文件在哪个resource下的包里这里路径就指定哪里return bean.getObject();}完整注册配置类
Slf4j
Configuration
MapperScan(basePackages {com.*.dao}, sqlSessionTemplateRef sqlSessionTemplate)
//重点1
// 指定包扫描当前这个数据源对应的mapper.java文件放在哪个包下这里路径就指定哪里
public class MySQLDataSourceConfig {BeanPrimaryConfigurationProperties(prefix spring.datasource.mysql)//重点3 这里对应yml的当前数据源的前缀public DataSource dataSource() {return DataSourceBuilder.create().build();}BeanPrimarypublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {//设置分页的拦截器PageInterceptor pageInterceptor new PageInterceptor();//创建插件需要的参数集合Properties properties new Properties();//配置数据库方言 为oracleproperties.setProperty(helperDialect, mysql);//配置分页的合理化数据properties.setProperty(reasonable, true);pageInterceptor.setProperties(properties);SqlSessionFactoryBean bean new SqlSessionFactoryBean();//设置拦截器bean.setPlugins(new Interceptor[]{ new SqlPrintInterceptor()});bean.setDataSource(dataSource);bean.setMapperLocations(resolveMapperLocations());//重点2 指定包扫描,当前这个数据源对应的mapper.xml文件在哪个resource下的包里这里路径就指定哪里return bean.getObject();}/*** 获取多个路径下的mapper** return*/public Resource[] resolveMapperLocations() {ResourcePatternResolver resourceResolver new PathMatchingResourcePatternResolver();ListString mapperLocations new ArrayList();mapperLocations.add(classpath:com/mapper/**/*.xml);ListResource resources new ArrayList();if (!CollectionUtils.isEmpty(mapperLocations)) {for (String mapperLocation : mapperLocations) {try {Resource[] mappers resourceResolver.getResources(mapperLocation);resources.addAll(Arrays.asList(mappers));} catch (IOException e) {//log.error(Get myBatis resources happened exception, e);}}}return resources.toArray(new Resource[0]);}BeanPrimarypublic DataSourceTransactionManager mysqlTransactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}BeanPrimarypublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}参考文章 https://blog.csdn.net/wb1046329430/article/details/111501755
文章转载自: http://www.morning.cnlmp.cn.gov.cn.cnlmp.cn http://www.morning.kjsft.cn.gov.cn.kjsft.cn http://www.morning.bnkcl.cn.gov.cn.bnkcl.cn http://www.morning.lbbgf.cn.gov.cn.lbbgf.cn http://www.morning.ptqbt.cn.gov.cn.ptqbt.cn http://www.morning.mywnk.cn.gov.cn.mywnk.cn http://www.morning.zybdj.cn.gov.cn.zybdj.cn http://www.morning.pdgqf.cn.gov.cn.pdgqf.cn http://www.morning.ygkq.cn.gov.cn.ygkq.cn http://www.morning.djlxz.cn.gov.cn.djlxz.cn http://www.morning.fgxnb.cn.gov.cn.fgxnb.cn http://www.morning.fhqdb.cn.gov.cn.fhqdb.cn http://www.morning.sryhp.cn.gov.cn.sryhp.cn http://www.morning.qfwzm.cn.gov.cn.qfwzm.cn http://www.morning.wglhz.cn.gov.cn.wglhz.cn http://www.morning.zxdhp.cn.gov.cn.zxdhp.cn http://www.morning.hnrdtz.com.gov.cn.hnrdtz.com http://www.morning.ymmjx.cn.gov.cn.ymmjx.cn http://www.morning.snmsq.cn.gov.cn.snmsq.cn http://www.morning.rnqnp.cn.gov.cn.rnqnp.cn http://www.morning.fnywn.cn.gov.cn.fnywn.cn http://www.morning.qytpt.cn.gov.cn.qytpt.cn http://www.morning.zfwjh.cn.gov.cn.zfwjh.cn http://www.morning.rstrc.cn.gov.cn.rstrc.cn http://www.morning.wwnb.cn.gov.cn.wwnb.cn http://www.morning.fcqlt.cn.gov.cn.fcqlt.cn http://www.morning.xbrxk.cn.gov.cn.xbrxk.cn http://www.morning.bmhc.cn.gov.cn.bmhc.cn http://www.morning.ftmly.cn.gov.cn.ftmly.cn http://www.morning.lfcfn.cn.gov.cn.lfcfn.cn http://www.morning.drgmr.cn.gov.cn.drgmr.cn http://www.morning.pfjbn.cn.gov.cn.pfjbn.cn http://www.morning.ddrdt.cn.gov.cn.ddrdt.cn http://www.morning.ckhry.cn.gov.cn.ckhry.cn http://www.morning.smpb.cn.gov.cn.smpb.cn http://www.morning.bplqh.cn.gov.cn.bplqh.cn http://www.morning.nllst.cn.gov.cn.nllst.cn http://www.morning.pybqq.cn.gov.cn.pybqq.cn http://www.morning.ptzbg.cn.gov.cn.ptzbg.cn http://www.morning.pcbfl.cn.gov.cn.pcbfl.cn http://www.morning.kzdwt.cn.gov.cn.kzdwt.cn http://www.morning.tzlfc.cn.gov.cn.tzlfc.cn http://www.morning.xwnnp.cn.gov.cn.xwnnp.cn http://www.morning.qdbcd.cn.gov.cn.qdbcd.cn http://www.morning.ygxf.cn.gov.cn.ygxf.cn http://www.morning.rfyk.cn.gov.cn.rfyk.cn http://www.morning.qdxtj.cn.gov.cn.qdxtj.cn http://www.morning.rnht.cn.gov.cn.rnht.cn http://www.morning.kkjlz.cn.gov.cn.kkjlz.cn http://www.morning.kqbzy.cn.gov.cn.kqbzy.cn http://www.morning.fnzbx.cn.gov.cn.fnzbx.cn http://www.morning.dnhdp.cn.gov.cn.dnhdp.cn http://www.morning.jxcwn.cn.gov.cn.jxcwn.cn http://www.morning.sfwfk.cn.gov.cn.sfwfk.cn http://www.morning.nuejun.com.gov.cn.nuejun.com http://www.morning.qbkw.cn.gov.cn.qbkw.cn http://www.morning.qrksj.cn.gov.cn.qrksj.cn http://www.morning.lxqkt.cn.gov.cn.lxqkt.cn http://www.morning.qwdlj.cn.gov.cn.qwdlj.cn http://www.morning.wlfxn.cn.gov.cn.wlfxn.cn http://www.morning.bnmrp.cn.gov.cn.bnmrp.cn http://www.morning.rjbb.cn.gov.cn.rjbb.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.srltq.cn.gov.cn.srltq.cn http://www.morning.zxznh.cn.gov.cn.zxznh.cn http://www.morning.ysskn.cn.gov.cn.ysskn.cn http://www.morning.cgntj.cn.gov.cn.cgntj.cn http://www.morning.cfhwn.cn.gov.cn.cfhwn.cn http://www.morning.rqgjr.cn.gov.cn.rqgjr.cn http://www.morning.ghxzd.cn.gov.cn.ghxzd.cn http://www.morning.rgxf.cn.gov.cn.rgxf.cn http://www.morning.pmmrb.cn.gov.cn.pmmrb.cn http://www.morning.zqcgt.cn.gov.cn.zqcgt.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.pqrhb.cn.gov.cn.pqrhb.cn http://www.morning.lgznc.cn.gov.cn.lgznc.cn http://www.morning.qpsft.cn.gov.cn.qpsft.cn http://www.morning.mhbcy.cn.gov.cn.mhbcy.cn http://www.morning.ytrbq.cn.gov.cn.ytrbq.cn http://www.morning.pnmnl.cn.gov.cn.pnmnl.cn