1. 程式人生 > >mybatis學習系列五--插件及類型處理器

mybatis學習系列五--插件及類型處理器

進行 class 引入 set gis 批量 lte sta sre

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 protected](String), 0(String), 0(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_305(String), [email protected](String), 1(String), 1(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_306(String), [email protected](String), 0(String), 0(Integer)

21:49:06,355 DEBUG addEmp:145 - ==> Parameters: name_307(String), [email protected](String), 1(String), 1(Integer)

21:49:06,356 DEBUG addEmp:145 - ==> Parameters: name_308(String), [email protected](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 protected](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 protected](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整合時,如果獲取bathsqlsession

配置帶batchsqlsession並使用

技術分享圖片

使用時引入:

技術分享圖片

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", "[email protected]",

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

5)查看數據庫存入數據

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

技術分享圖片

技術分享圖片

可以看到默認存儲的是枚舉的名字

原因:

默認使用enumTypehandler處理(包含EnumTypeHandlerEnumOrdinalTypeHandler2種類型)

設置參數時代碼如下:

@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", "[email protected]",

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

session.commit();

查看數據庫:
技術分享圖片

mybatis學習系列五--插件及類型處理器