相关推荐:MyBatis 入门(四)--链表查询

一、只包含一个对象的情况 先看看数据库的设计 一个用户表,和用户的身份证id记录表 mapper文件 <resultMap id="BaseResultMap"type="com.element

一、Mybatis插件介绍

摘自官方文档:很晦涩,简单阅读一下即可

MyBatis 允许你在某一点拦截已映射语句执行的调用。默认情况下,MyBatis 允许使用插件来拦截方法调用:

Executor

(update, query, flushStatements, commit, rollback,

getTransaction, close,

isClosed)

ParameterHandler

(getParameterObject,

setParameters)

ResultSetHandler

(handleResultSets,

handleOutputParameters)

StatementHandler

(prepare, parameterize, batch,

update, query)

这些类中方法的详情可以通过查看每个方法的签名来发现 ,而且它们的源代码在 MyBatis

的发行包中有。你应该理解你覆盖方法的行为,假设你所做的要比监视调用要多。 如果你尝试修改或覆盖一个给定的方法, 你可能会打破 MyBatis 的核心。 这是低层次的类和方法,要谨慎使用插件。 使用插件是它们提供的非常简单的力量。 简单实现拦截器接口, 要确定你想拦截的指定签名。 上面的插件将会拦截在 Executor 实例中所有的“update”方法调用,它也是负责低层次 映射语句执行的内部对象。 插件的作用就是在执行预计前,后都可以自定义需要处理的程序(通过责任链模式 ) ,也就是说可以定义多个需要执行的程序。 二、 实现一个自己的拦截器

package com.elements.user.plugins;

import java.sql.Connection;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;

import org.apache.ibatis.plugin.Interceptor;

import org.apache.ibatis.plugin.Intercepts;

import org.apache.ibatis.plugin.Invocation;

import org.apache.ibatis.plugin.Signature;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })

public class PageInterceptor implements Interceptor {

public Object intercept(Invocation invocation) throws Throwable {

System.out.println("bbbbbbbbbb");

return null;

}

public Object plugin(Object target) {

System.out.println("target is :"+target.getClass().getName());

return target;

}

public void setProperties(Properties properties) {

System.out.println(properties.toString());

}

}

测试输出结果

{someProperty=100}

target is :org.apache.ibatis.executor.CachingExecutor

target is :org.apache.ibatis.scripting.defaults.DefaultParameterHandler

target is :org.apache.ibatis.executor.resultset.DefaultResultSetHandler

target is :org.apache.ibatis.executor.statement.RoutingStatementHandler

 intercept没有被调用第一步 我们的属性,从配置文件里面获取了,这里是

someProperty 值是 someProperty

第二步 我们的plugin ,被调用了4次,分别是

CachingExecutor, DefaultParameterHandler ,DefaultResultSetHandler,RoutingStatementHandler

 CachingExecutor :二级缓存执行器 实现 ExecutorDefaultParameterHandler :参数处理 实现ParameterHandler DefaultResultSetHandler :实现

ResultSetHandler ResultSetHandler只负责两件事:

1.处理Statement执行后产生的结果集,生成结果列表

2.处理存储过程执行后的输出参数

 RoutingStatementHandler:实现了StatementHandler 三、分页实现 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<properties resource="jdbc.properties" />

<!-- 自定义分页拦截器 -->

<plugins>

<plugin interceptor="com.elements.user.plugins.PageInterceptor">

<property name="someProperty" value="100" />

</plugin>

</plugins>

<environments default="dev">

<environment id="dev">

<transactionManager type="JDBC" />

<dataSource type="POOLED">

<property name="driver" value="${driver}" />

<property name="url" value="${url}" />

<property name="username" value="${username}" />

<property name="password" value="${password}" />

</dataSource>

</environment>

</environments>

<mappers>

<mapper class="com.elements.user.dao.UserMapper" />

</mappers>

</configuration>

page

package com.elements.user.plugins;

public class Page {

// 定义分页的默认大小

private int OnePageSize = 5;

// 当前页数

private int nowPage = 1;

public int getOnePageSize() {

return OnePageSize;

}

public void setOnePageSize(int onePageSize) {

OnePageSize = onePageSize;

}

public int getStartRow() {

return startRow;

}

public void setStartRow(int startRow) {

this.startRow = startRow;

}

public int getEndRow() {

return endRow;

}

public void setEndRow(int endRow) {

this.endRow = endRow;

}

// 开始的行

private int startRow = 0;

{

startRow = (nowPage - 1) * OnePageSize;

}

// 结束的行

private int endRow = 0;

{

endRow = nowPage * OnePageSize;

}

// 总的页数

private int AllPages = 0;

// 总记录数

private int allRows = 0;

public int getAllRows() {

return allRows;

}

public void setAllRows(int allRows) {

this.allRows = allRows;

this.AllPages = allRows % OnePageSize == 0 ? (int) (allRows / OnePageSize)

: (int) (allRows / OnePageSize) + 1;

}

public int getNowPage() {

return nowPage;

}

public void setNowPage(int nowPage) {

this.nowPage = nowPage;

startRow = (nowPage - 1) * OnePageSize;

endRow = nowPage * OnePageSize;

}

}

基础类User

package com.elements.user.model;

import com.elements.user.plugins.Page;

public class User extends Page{

/**

* This field was generated by MyBatis Generator.

* This field corresponds to the database column user.userId

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

private Integer userid;

/**

* This field was generated by MyBatis Generator.

* This field corresponds to the database column user.UserName

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

private String username;

/**

* This field was generated by MyBatis Generator.

* This field corresponds to the database column user.UserEmail

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

private String useremail;

/**

* This field was generated by MyBatis Generator.

* This field corresponds to the database column user.createTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

private String createtime;

/**

* This field was generated by MyBatis Generator.

* This field corresponds to the database column user.updateTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

private String updatetime;

/**

* This method was generated by MyBatis Generator.

* This method returns the value of the database column user.userId

*

* @return the value of user.userId

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public Integer getUserid() {

return userid;

}

/**

* This method was generated by MyBatis Generator.

* This method sets the value of the database column user.userId

*

* @param userid the value for user.userId

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public void setUserid(Integer userid) {

this.userid = userid;

}

/**

* This method was generated by MyBatis Generator.

* This method returns the value of the database column user.UserName

*

* @return the value of user.UserName

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public String getUsername() {

return username;

}

/**

* This method was generated by MyBatis Generator.

* This method sets the value of the database column user.UserName

*

* @param username the value for user.UserName

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public void setUsername(String username) {

this.username = username == null ? null : username.trim();

}

/**

* This method was generated by MyBatis Generator.

* This method returns the value of the database column user.UserEmail

*

* @return the value of user.UserEmail

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public String getUseremail() {

return useremail;

}

/**

* This method was generated by MyBatis Generator.

* This method sets the value of the database column user.UserEmail

*

* @param useremail the value for user.UserEmail

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public void setUseremail(String useremail) {

this.useremail = useremail == null ? null : useremail.trim();

}

/**

* This method was generated by MyBatis Generator.

* This method returns the value of the database column user.createTime

*

* @return the value of user.createTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public String getCreatetime() {

return createtime;

}

/**

* This method was generated by MyBatis Generator.

* This method sets the value of the database column user.createTime

*

* @param createtime the value for user.createTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public void setCreatetime(String createtime) {

this.createtime = createtime ;

}

/**

* This method was generated by MyBatis Generator.

* This method returns the value of the database column user.updateTime

*

* @return the value of user.updateTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public String getUpdatetime() {

return updatetime;

}

/**

* This method was generated by MyBatis Generator.

* This method sets the value of the database column user.updateTime

*

* @param updatetime the value for user.updateTime

*

* @mbggenerated Wed Apr 27 15:05:09 CST 2016

*/

public void setUpdatetime(String updatetime) {

this.updatetime = updatetime;

}

@Override

public String toString() {

return "User [userid=" + userid + ", username=" + username

+ ", useremail=" + useremail + ", createtime=" + createtime

+ ", updatetime=" + updatetime + "]\n";

}

}

UserMapper

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.elements.user.dao.UserMapper" >

<resultMap id="BaseResultMap" type="com.elements.user.model.User" >

<id column="userId" property="userid" jdbcType="INTEGER" />

<result column="UserName" property="username" jdbcType="VARCHAR" />

<result column="UserEmail" property="useremail" jdbcType="VARCHAR" />

<result column="createTime" property="createtime" jdbcType="VARCHAR" />

<result column="updateTime" property="updatetime" jdbcType="VARCHAR" />

</resultMap>

<sql id="Base_Column_List" >

userId, UserName, UserEmail, createTime, updateTime

</sql>

<select id="selectUserPage" parameterType="com.elements.user.model.User" resultMap="BaseResultMap">

select

<include refid="Base_Column_List" />

from user

where 1=1

and UserName like '%%'

</select>

</mapper>

最终要的:PageInterceptor

package com.elements.user.plugins;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.List;

import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;

import org.apache.ibatis.executor.statement.RoutingStatementHandler;

import org.apache.ibatis.executor.statement.StatementHandler;

import org.apache.ibatis.mapping.BoundSql;

import org.apache.ibatis.mapping.MappedStatement;

import org.apache.ibatis.mapping.ParameterMapping;

import org.apache.ibatis.plugin.Interceptor;

import org.apache.ibatis.plugin.Intercepts;

import org.apache.ibatis.plugin.Invocation;

import org.apache.ibatis.plugin.Plugin;

import org.apache.ibatis.plugin.Signature;

import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })

public class PageInterceptor implements Interceptor {

public Object plugin(Object target) {

System.out.println("target is :" + target.getClass().getName());

if (target instanceof RoutingStatementHandler) {

return Plugin.wrap(target, this);

}

return target;

}

public void setProperties(Properties properties) {

System.out.println(properties.toString());

}

public Object intercept(Invocation invocation) throws Throwable {

if (invocation.getTarget() instanceof RoutingStatementHandler) {

RoutingStatementHandler statementHandler = (RoutingStatementHandler) invocation

.getTarget();

StatementHandler delegate = (StatementHandler) ReflectHelper

.getFieldValue(statementHandler, "delegate");

BoundSql boundSql = delegate.getBoundSql();

Object obj = boundSql.getParameterObject();

if (obj instanceof Page) {

Page page = (Page) obj;

// 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性

MappedStatement mappedStatement = (MappedStatement) ReflectHelper

.getFieldValue(delegate, "mappedStatement");

// 拦截到的prepare方法参数是一个Connection对象

Connection connection = (Connection) invocation.getArgs()[0];

// 获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句

String sql = boundSql.getSql();

// 给当前的page参数对象设置总记录数

this.setTotalRecord(page, mappedStatement, connection);

// 获取分页Sql语句

String pageSql = this.getPageSql(page, sql);

// 利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句

ReflectHelper.setFieldValue(boundSql, "sql", pageSql);

}

}

return invocation.proceed();

}

private String getPageSql(Page page, String sql) {

StringBuffer sqlBuffer = new StringBuffer(sql);

sqlBuffer.insert(0, "select

*

from (").append(")temp where 1=1 ")

.append(" limit ").append(page.getStartRow()).append(",")

.append(page.getOnePageSize());

return sqlBuffer.toString();

}

private void setTotalRecord(Page page, MappedStatement mappedStatement,

Connection connection) {

// delegate里面的boundSql也是通过mappedStatement.getBoundSql(paramObj)方法获取到的。

BoundSql boundSql = mappedStatement.getBoundSql(page);

// 获取到我们自己写在Mapper映射语句中对应的Sql语句

String sql = boundSql.getSql();

// 通过查询Sql语句获取到对应的计算总记录数的sql语句

String countSql = this.getCountSql(sql);

// 通过BoundSql获取对应的参数映射

List<ParameterMapping> parameterMappings = boundSql

.getParameterMappings();

// 利用Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建立查询记录数对应的BoundSql对象。

BoundSql countBoundSql = new BoundSql(

mappedStatement.getConfiguration(), countSql,

parameterMappings, page);

// 通过mappedStatement、参数对象page和BoundSql对象countBoundSql建立一个用于设定参数的ParameterHandler对象

ParameterHandler parameterHandler = new DefaultParameterHandler(

mappedStatement, page, countBoundSql);

// 通过connection建立一个countSql对应的PreparedStatement对象。

PreparedStatement pstmt = null;

ResultSet rs = null;

try {

pstmt = connection.prepareStatement(countSql);

// 通过parameterHandler给PreparedStatement对象设置参数

parameterHandler.setParameters(pstmt);

// 之后就是执行获取总记录数的Sql语句和获取结果了。

rs = pstmt.executeQuery();

if (rs.next()) {

int totalRecord = rs.getInt(1);

// 给当前的参数page对象设置总记录数

page.setAllRows(totalRecord);

}

} catch (SQLException e) {

e.printStackTrace();

} finally {

try {

if (rs != null)

rs.close();

if (pstmt != null)

pstmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

private String getCountSql(String sql) {

StringBuffer sqlBuffer = new StringBuffer(sql);

sqlBuffer.insert(0, "select

count(*)

from (").append(

")temp where 1=1 ");

return sqlBuffer.toString();

}

}

测试类:

package com.elements.user;

import java.io.IOException;

import java.io.InputStream;

import java.util.List;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Test;

import com.elements.user.dao.UserMapper;

import com.elements.user.model.User;

public class TestUserPage {

@Test

public void TestUserPageSelect() throws IOException {

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()

.build(inputStream);

SqlSession session = sqlSessionFactory.openSession();

try {

UserMapper user = (UserMapper) session

.getMapper(UserMapper.class);

User u=new User();

List<User> list =user.selectUserPage(u);

System.out.print(list);

} finally {

session.close();

}

}

}

四、总结

只要你的查询参数继承Page类,就会自动分页,查询总记录,总页数(在page内

)。方式一要自己一一实现。项目代码地址:

http://pan.baidu.com/s/1sld2aZV

本文章参考了:(1)http://blog.csdn.net/hfmbook/article/details/41985853

相关推荐:MyBatis 入门(五)--分页查询(1)

不使用mybatis的RowBounds方式,网络上说这个功能不怎么好了。 一、根本原理 不管是自己实现还是利用插件方式,其根本就是利用: mysql的 limit beginrow , size(条数) ORACEL的 rownum >= 1and rownu

快照源:http://blog.chinaunix.net/uid-261569-id-5711315.html