2 插件编写(80-81)

单个插件编写

2.1实现interceptor接口(ibatis)

invocation.proceed()方法执行必须要有,否则不会无法实现拦截作用

2.2 使用@intercepts注解完成插件签名

2.3 将插件注册到全局配置文件中<plugins>标签

全局配置文件注册plugin时报错:

The content of element type "configuration" must match

"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".

原因:configuration 中的元素不仅有类型限制,还有顺序限制

https://blog.csdn.net/u011199063/article/details/78971527

按照提示的顺序即可

多个插件

插件动态代理时,按插件配置顺序配置层层代理对象,执行目标方法时,按逆向顺序执行

配置的插件顺序

<!-- 自定义插件 -->

<plugins>

<plugin interceptor="com.mybatis.bean.MyPlugin">

<!-- 配置插件属性,在插件setProperties方法中使用 -->

<property name="username1" value="root1"/>

<property name="password1" value="1"/>

</plugin>

<plugin interceptor="com.mybatis.bean.MySecondPlugin">

<property name="username2" value="root2"/>

<property name="password2" value="2"/>

</plugin>

</plugins>

执行打印日志:

22:29:05,207  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.SimpleExecutor@24b1d79b

22:29:05,208  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.SimpleExecutor@24b1d79b

22:29:05,239  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@70beb599

22:29:05,239  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.scripting.defaults.DefaultParameterHandler@70beb599

22:29:05,242  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@365c30cc

22:29:05,242  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.resultset.DefaultResultSetHandler@365c30cc

22:29:05,243  INFO Class:50 - myfirstplugin  plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@4148db48

22:29:05,243  INFO Class:50 - mysecondplugin  plugin:org.apache.ibatis.executor.statement.RoutingStatementHandler@4148db48

显示包装顺序按配置顺序

再看执行intercept方法执行顺序:

22:29:05,272  INFO Class:40 - myfirstplugin intercept:null

22:29:05,272  INFO Class:40 - mysecondplugin intercept:null

也是按顺序执行,并不是如图所示的包装按正序,执行按逆序

3 插件开发(82)

只有再插件类中intercept方法中调用invocation.proceed()方法才能执行拦截的目标方法

简单开发:修改sql参数

//获取拦截的对象

Object target=invocation.getTarget();

log.info(target);

//获取target的元数据

MetaObject metaObject=SystemMetaObject.forObject(target);

Object value=metaObject.getValue("parameterHandler.parameterObject");

System.out.println("sql语句的参数:"+value);

//修改sql语句参数

metaObject.setValue("parameterHandler.parameterObject", 3);

//执行目标方法

Object proceed = invocation.proceed();

log.info("myfirstplugin intercept:"+proceed);

执行后打印信息:

sql语句的参数:2

22:00:27,942 DEBUG getMyDeptById:145 - ==> Parameters: 3(Integer)

可见,sql参数从2修改为3了

4 pagehelper分页插件(83)

引入:

1pom配置

<!-- pagehelper分页插件 -->

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper</artifactId>

<version>4.1.4</version>

</dependency>

2全局配置文件中配置

mybatis-config.xml

<plugins>

<!-- 分页插件 -->

<plugin interceptor="com.github.pagehelper.PageHelper">

<property name="dialect" value="mysql"/>

<property name="offsetAsPageNum" value="false"/>

<property name="rowBoundsWithCount" value="false"/>

<property name="pageSizeZero" value="true"/>

<property name="reasonable" value="false"/>

<property name="supportMethodsArguments" value="false"/>

<property name="returnPageInfo" value="none"/>

</plugin>

</plugins>

3 测试类

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

//获取页码信息方式1 (startPage方式)

Page<Object> startPage = PageHelper.startPage(3, 3);

List<Employee> emps=mapper.selectEmployeeByInnerParameter(null);

// System.out.println("当前页码:"+startPage.getPageNum());

// System.out.println("总记录数:"+startPage.getTotal());

// System.out.println("每页记录数:"+startPage.getPageSize());

// System.out.println("总页码:"+startPage.getPages());

// System.out.println("分页后当前页码数据条数:"+emps.size());

//获取页码信息方式2  (pageInfo信息更丰富)

// PageInfo<Employee> pageInfo = new PageInfo<>(emps);

//2个参数,后面参数表示分页导航,连续显示多少页码(即每次显示5页,如2,3,4,5,6)

PageInfo<Employee> pageInfo = new PageInfo<>(emps,2);

System.out.println("当前页码:"+pageInfo.getPageNum());

System.out.println("总记录数:"+pageInfo.getTotal());

System.out.println("每页记录数:"+pageInfo.getPageSize());

System.out.println("总页码:"+pageInfo.getPages());

System.out.println("分页后当前页码数据条数:"+emps.size());

System.out.println("是否第一页:"+pageInfo.isIsFirstPage());

System.out.println("连续显示页码:"+pageInfo.getNavigatePages());

int[] navigatepageNums = pageInfo.getNavigatepageNums();

for ( int i=0;i<navigatepageNums.length;i++) {

System.out.println(navigatepageNums[i]);

}

输出结果:

当前页码:3

总记录数:11

每页记录数:3

总页码:4

分页后当前页码数据条数:3

是否第一页:false

连续显示页码:2

2

3

5 mybatis批量操作(84)

1采用batch方式进行批量插入操作:

//batch类型的session

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);

try {

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

long start=System.currentTimeMillis();

for(int i=0;i<1000;i++) {

mapper.addEmp(new Employee(null,"name_"+i, "email_"+i+"@com.cn", (i%2)+"", (i%2)));

}

session.commit();

long end=System.currentTimeMillis();

System.out.println("执行时间:"+(end-start));

} finally {

session.close();

}

执行效果:

21:49:06,354 DEBUG addEmp:145 - ==> Parameters: name_304(String), email_304@com.cn(String), 0(String), 0(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_305(String), email_305@com.cn(String), 1(String), 1(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_306(String), email_306@com.cn(String), 0(String), 0(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_307(String), email_307@com.cn(String), 1(String), 1(Integer)

21:49:06,356 DEBUG addEmp:145 - ==> Parameters: name_308(String), email_308@com.cn(String), 0(String), 0(Integer)

执行时间:

21:49:07,208 DEBUG JdbcTransaction:69 - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6ebc05a6]

执行时间:1198

2非batch方式批量操作:

//非batch批量操作session

SqlSession session = sqlSessionFactory.openSession();

try {

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

long start=System.currentTimeMillis();

for(int i=0;i<1000;i++) {

mapper.addEmp(new Employee(null,"name_"+i, "email_"+i+"@com.cn", (i%2)+"", (i%2)));

}

session.commit();

long end=System.currentTimeMillis();

System.out.println("执行时间:"+(end-start));

} finally {

session.close();

}

执行情况:

21:52:44,356 DEBUG addEmp:145 - ==> Parameters: name_987(String), email_987@com.cn(String), 1(String), 1(Integer)

21:52:44,356 DEBUG addEmp:145 - <==    Updates: 1

21:52:44,356 DEBUG addEmp:145 - ==>  Preparing: insert into myemployeee(last_name,email,gender,dept_id) values (?,?, ?,?)

21:52:44,356 DEBUG addEmp:145 - ==> Parameters: name_988(String), email_988@com.cn(String), 0(String), 0(Integer)

21:52:44,357 DEBUG addEmp:145 - <==    Updates: 1

执行时间:

执行时间:1376

原因:

批量batch方式:(预编译sql一次==》设置参数==》1000次==)

非批量:(预编译sql==》设置参数==》执行)==》1000次

执行次数

非批量执行时间(ms)

批量执行时间(ms)

1000

1376

1198

10000

11649

3607

50000

37831

10593

100000

62868

20195

性能在3倍左右

spring整合时,如果获取bath的sqlsession

配置带batch的sqlsession并使用

使用时引入:

 6mybatis存储过程(85-86)

可以理解为sql集合,复杂sql情况下

Oracle中分页借助伪列(rowid)

先<=end,再>=start  (注意如果先>=start再<=end会导致数据不确定而错误)

1创建分页类:

/**

* 分页类

* @author admin

*

*/

public class Page {

private int start;

private int end;

private int count;

private List<Employee> emps;

public int getStart() {

return start;

}

分页查询:先查询总记录数,再进行分页查询

2/**创建oracle存储过程*/

create or replace procedure

hello_test(//存储过程名

p_start in int,//p_start-->参数开始行;in-->表示输入;int表示参数类型

p_end in int,//p_end-->参数结束行;in-->表示输入;int表示参数类型

p_count out int,//输出

p_emps out sys_refcursor//输出,游标

) as

begin

select count(*) into p_count from employee;//将查询的总记录数交给p_count

open p_emps for //打开游标

select * from

(select rownum rn,e.* from employee e where rownum<=p_end)

where rn>=p_start;

end hello_test;

3使用存储过程:

3.1Select * from user_source;

查看存储过程

3.2mybatis调用存储过程

 

1)定义查询接口

//调用存储过程分页(参数为定义的page)

void getPageByProcedure(Page page);

2)mapper中定义查询存储过程的sql

<!-- statementType="CALLABLE" 表示调用存储过程 -->

<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">

<!-- 固定用法 { call 存储过程名(参数1,参数2,...) } -->

{call

hello_test(

#{start,mode=IN,jdbcType=INTEGER},

#{end,mode=IN,jdbcType=INTEGER},

#{end,mode=IN,jdbcType=INTEGER},

#{count,mode=OUT,jdbcType=INTEGER},

#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=resultMap}

<!-- 游标处理,使用ResultSet封装结果集 -->

) }

</select>

3)调用测试

//存储过程查询

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

Page page = new Page();

page.setStart(1);

page.setEnd(10);

mapper.getPageByProcedure(page);

System.out.println("总记录数:"+page.getCount());

System.out.println("查出的数据:"+page.getEmps().size());

7 mybatis存自定义类型处理器(87)

自定义typehandler处理枚举类型

设置参数和处理结果时调用typehandler处理参数,将java类型和数据库类型映射。

查看typehandler接口:

public interface TypeHandler<T> {

void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

T getResult(ResultSet rs, String columnName) throws SQLException;

T getResult(ResultSet rs, int columnIndex) throws SQLException;

T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

初步使用枚举

/**

* 枚举工具类

* @author admin

*

*/

public class EnumUtils {

//雇员状态

public enum EmployeeStaus{

LOGIN,//登陆

LONGOUT,//推出

REMOVE//移除

}

//枚举测试

public static void main(String[] args) {

EmployeeStaus status=EmployeeStaus.LOGIN;

System.out.println("枚举的索引:"+status.ordinal());

System.out.println("枚举的名字:"+status.name());

}

}

输出:

枚举的索引:0

枚举的名字:LOGIN

即枚举有索引和名字,接下来测试mybatis默认存放的是什么

1)表myemployeee新增字段status

-- 新增状态字段

alter table myemployeee add column status varchar(11);

2) bean对象添加对应属性

private EmployeeStaus status=EmployeeStaus.LONGOUT;//状态枚举类型,默认退出状态

并提供构造方法:

public Employee(String lastName, String email, String gender, Integer deptId, MyDept myDept,

EmployeeStaus status) {

super();

this.lastName = lastName;

this.email = email;

this.gender = gender;

this.deptId = deptId;

this.myDept = myDept;

this.status = status;

}

3)mapper新增插入字段

<insert id="addEmp" parameterType="com.mybatis.bean.Employee">

insert into myemployeee(last_name,email,gender,dept_id,status)

values (#{lastName,jdbcType=VARCHAR},#{email,jdbcType=VARCHAR},

#{gender,jdbcType=VARCHAR},#{deptId,jdbcType=INTEGER},#{status})

</insert>

4)测试插入:

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

mapper.addEmp(new Employee("test11", "test11@com.cn",

1+"", 1, null, EmployeeStaus.LONGOUT));

5)查看数据库存入数据

select t.* from myemployeee  t order by t.id desc limit 1;

可以看到默认存储的是枚举的名字

 

原因:

默认使用enumTypehandler处理(包含EnumTypeHandler和EnumOrdinalTypeHandler共2种类型)

设置参数时代码如下:

@Override

public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {

if (jdbcType == null) {

ps.setString(i, parameter.name());

} else {

ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589

}

}

可见保存的是枚举的名字。

变更处理器

可以改变使用EnumOrdinalTypeHandler,

在全局配置器中设置:

<!-- 处理指定enum类型,不指定则处理所有enum类型 -->

<typeHandlers>

<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.mybatis.bean.EnumUtils.EmployeeStaus"/>

</typeHandlers>

执行报错:

## The error may exist in SQL Mapper Configuration

### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)

at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)

at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)

at com.mybatis.bean.Mytest_eum_test.getSqlSessionFactory(Mytest_eum_test.java:45)

at com.mybatis.bean.Mytest_eum_test.main(Mytest_eum_test.java:29)

Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:120)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98)

at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78)

... 3 more

Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:118)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.typeHandlerElement(XMLConfigBuilder.java:337)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:117)

... 5 more

Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'com.mybatis.bean.EnumUtils.EmployeeStaus'.  Cause: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:120)

at org.apache.ibatis.builder.BaseBuilder.resolveAlias(BaseBuilder.java:149)

at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:116)

... 7 more

Caused by: java.lang.ClassNotFoundException: Cannot find class: com.mybatis.bean.EnumUtils.EmployeeStaus

at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:200)

at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89)

at org.apache.ibatis.io.Resources.classForName(Resources.java:261)

at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:116)

使用另一种方式(不在全局配置中配置,仅在执行处指定)

<insert id="addEmp" parameterType="com.mybatis.bean.Employee">

insert into myemployeee(last_name,email,gender,dept_id,status)

values (#{lastName,jdbcType=VARCHAR},#{email,jdbcType=VARCHAR},

#{gender,jdbcType=VARCHAR},#{deptId,jdbcType=INTEGER},#{status,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler})

</insert>

测试:

EmployeeMapper mapper=session.getMapper(EmployeeMapper.class);

mapper.addEmp(new Employee("test22", "test22@com.cn",

1+"", 1, null, EmployeeStaus.LONGOUT));

session.commit();

查看数据库:

mybatis学习系列五--插件及类型处理器的更多相关文章

  1. MyBatis学习系列二——增删改查

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改, ...

  2. scrapy爬虫学习系列五:图片的抓取和下载

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

  3. MyBatis学习系列三——结合Spring

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...

  4. MyBatis学习系列一之环境搭建

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring 学习一个新的知识,首先做一个简单的例子使用一下,然后再逐步深入.MyBat ...

  5. Mybatis学习系列(五)关联查询

    前面几节的示例基本都是一些单表查询,实际项目中,经常用到关联表的查询,比如一对一,一对多等情况.在Java实体对象中,一对一和一对多可是使用包装对象解决,属性使用List或者Set来实现,在mybat ...

  6. mybatis学习系列一

    1引入dtd约束(6) Mybatis git地址:https://github.com/mybatis/mybatis-3/wiki/Maven 指导手册:http://www.mybatis.or ...

  7. MyBatis学习 之 五、MyBatis配置文件

    在定义sqlSessionFactory时需要指定MyBatis主配置文件: <bean id="sqlSessionFactory" class="org.myb ...

  8. Mybatis学习系列(二)Mapper映射文件

    Mapper映射文件,作用是用来配置SQL映射语句,根据不同的SQL语句性质,使用不同的标签,mapper文件中常用的标签有<iselect>.<insert>.<upd ...

  9. RabbitMQ入门学习系列(五) Exchange的Direct类型

    快速阅读 利用Exchange的Direct类型,实现对队列的过滤,消费者启动以后,输入相应的key值,攻取该key值对应的在队列中的消息 . 从一节知道Exchange有四种类型 Direct,To ...

随机推荐

  1. [源码]K8 Cscan模块 C#获取内网主机IP/机器名/Banner/网页标题源码

    [原创]K8 Cscan 大型内网渗透自定义扫描器 https://www.cnblogs.com/k8gege/p/10519321.html Cscan简介:何为自定义扫描器?其实也是插件化,但C ...

  2. ES6学习总结

    const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了 const foo = {}; // 为 foo 添加一个属性,可以成功 foo.prop = 123; foo ...

  3. Hibernate框架 主配置文件(Hibernate.cfg.xml)基本

    数据库连接参数配置: <?xml version='1.0' encoding='UTF-8'?> <!--表明解析本XML文件的DTD文档位置,DTD是Document Type ...

  4. nginx如何实现高并发

    nginx如何实现高并发 简单来讲,就是异步,非阻塞,使用了epoll和大量的底层代码优化. 稍微详细一点展开的话,就是nginx的特殊进程模型和事件模型的设计. 进程模型 nginx采用一个mast ...

  5. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十四):权限控制(Shiro 注解)

    在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 技术背景 当前,我们基于导航菜单的显示和操作按钮的禁用状态,实现了页面可见性和 ...

  6. 红黑树深入剖析及Java实现

    红黑树是平衡二叉查找树的一种.为了深入理解红黑树,我们需要从二叉查找树开始讲起. BST 二叉查找树(Binary Search Tree,简称BST)是一棵二叉树,它的左子节点的值比父节点的值要小, ...

  7. Java设计模式学习记录-外观模式

    前言 这次要介绍的是外观模式(也称为门面模式),外观模式也属于结构型模式,其实外观模式还是非常好理解的,简单的来讲就是将多个复杂的业务封装成一个方法,在调用此方法时可以不必关系具体执行了哪些业务,而只 ...

  8. FFmpeg流媒体处理-收流与推流

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10623968.html 1. 简介 流媒体是使用了流式传输的多媒体应用技术.如下是维基百 ...

  9. [转]VS Code 扩展 Angular 6 Snippets - TypeScript, Html, Angular Material, ngRx, RxJS & Flex Layout

    本文转自:https://marketplace.visualstudio.com/items?itemName=Mikael.Angular-BeastCode VSCode Angular Typ ...

  10. using的几种用法

    1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间 例如:using System; 一般都会出现在*.cs中.   2.using ...