java实现mysql拦截_在mybatis执⾏SQL语句之前进⾏拦击处
理实例
⽐较适⽤于在分页时候进⾏拦截。对分页的SQL语句通过封装处理,处理成不同的分页sql。
实⽤性⽐较强。
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.utor.parameter.ParameterHandler;
import org.utor.statement.RoutingStatementHandler;
import org.utor.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;
zepto更新
import com.yidao.utils.Page;
import com.yidao.utils.ReflectHelper;
/**
*
* 分页,⽤于拦截需要进⾏分页查询的操作,然后对其进⾏分页处理。
* 利⽤实现Mybatis分页的原理:
* 要利⽤JDBC对数据库进⾏操作就必须要有⼀个对应的Statement对象,Mybatis在执⾏Sql语句前就会产⽣⼀个包含Sql语句的Statement对象,⽽且对应的Sql语句
* 是在Statement之前产⽣的,所以我们就可以在它⽣成Statement之前对⽤来⽣成Statement的Sql语句下⼿。在Mybatis中Statement 语句是通过RoutingStatementHandler对象的
* prepare⽅法⽣成的。所以利⽤实现Mybatis分页的⼀个思路就是拦截StatementHandler接⼝的prepare⽅法,然后在⽅法中把Sql语句改成对应的分页查询Sql语句,之后再调⽤
* StatementHandler对象的prepare⽅法,即调⽤invocation.proceed()。
* 对于分页⽽⾔,在⾥⾯我们还需要做的⼀个操作就是统计满⾜当前条件的记录⼀共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利⽤Mybatis封装好的参数和设
* 置参数的功能把Sql语句中的参数进⾏替换,之后再执⾏查询记录数的Sql语句进⾏总记录数的统计。
*
*/
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageInterceptor implements Interceptor {
private String dialect = ""; //数据库⽅⾔
private String pageSqlId = ""; //l中需要拦截的ID(正则匹配)
public Object intercept(Invocation invocation) throws Throwable {
//对于StatementHandler其实只有两个实现类,⼀个是RoutingStatementHandler,另⼀个是抽象类BaseStatementHandler,
//BaseStatementHandler有三个⼦类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
//SimpleStatementHandler是⽤于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,⽽CallableStatementHandler是
//处理CallableStatement的。Mybatis在进⾏Sql语句处理的时候都是建⽴的RoutingStatementHandler,⽽在RoutingStatementHandler⾥⾯拥有⼀个
//StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建⽴对应的BaseStatementHandler,即SimpleStatementHandler、
//PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler⾥⾯所有StatementHandler接⼝⽅法的实现都是调⽤的delegate对应的⽅法。
//我们在PageInterceptor类上已经⽤@Signature标记了该Interceptor只拦截StatementHandler接⼝的prepare⽅法,⼜因为Mybatis 只有在建⽴RoutingStatementHandler的时候
//是通过Interceptor的plugin⽅法进⾏包裹的,所以我们这⾥拦截到的⽬标对象肯定是RoutingStatementHandler对象。
Target() instanceof RoutingStatementHandler){
RoutingStatementHandler statementHandler = (Target();
StatementHandler delegate = (StatementHandler) FieldValue(statementHandler, "delegate");
BoundSql boundSql = BoundSql();
Object obj = ParameterObject();
if (obj instanceof Page>) {
Page> page = (Page>) obj;
//通过反射获取delegate⽗类BaseStatementHandler的mappedStatement属性
MappedStatement mappedStatement = (FieldValue(delegate, "
mappedStatement");
//拦截到的prepare⽅法参数是⼀个Connection对象
mysql语句转oracleConnection connection = (Args()[0];
//获取当前要执⾏的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
String sql = Sql();
//给当前的page参数对象设置总记录数
this.setTotalRecord(page,
mappedStatement, connection);
//获取分页Sql语句
String pageSql = PageSql(page, sql);
//利⽤反射设置当前BoundSql对应的sql属性为我们建⽴好的分页Sql语句表格样式图片
ReflectHelper.setFieldValue(boundSql, "sql", pageSql);
}
}
return invocation.proceed();
}
/**
* 给当前的参数对象page设置总记录数
*
* @param page Mapper映射语句对应的参数对象
* @param mappedStatement Mapper映射语句
* @param connection 当前的数据库连接
python基础教程二版三版那个好
*/
private void setTotalRecord(Page> page,
MappedStatement mappedStatement, Connection connection) {
//获取对应的BoundSql,这个BoundSql其实跟我们利⽤StatementHandler获取到的BoundSql是同⼀个对象。
//delegate⾥⾯的boundSql也是通过BoundSql(paramObj)⽅法获取到的。
BoundSql boundSql = BoundSql(page);
//获取到我们⾃⼰写在Mapper映射语句中对应的Sql语句
String sql = Sql();
//通过查询Sql语句获取到对应的计算总记录数的sql语句
String countSql = CountSql(sql);
//通过BoundSql获取对应的参数映射
List parameterMappings = ParameterMappings();
//利⽤Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建⽴查询记录数对应的BoundSql对象。
BoundSql countBoundSql = new Configuration(), 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 = uteQuery();
if (rs.next()) {
int totalRecord = rs.getInt(1);
//给当前的参数page对象设置总记录数
page.setTotalRecord(totalRecord);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/
**
* 根据原Sql语句获取对应的查询总记录数的Sql语句
* @param sql
* @return
*/
private String getCountSql(String sql) {
int index = sql.indexOf("from");
return "select count(*) " + sql.substring(index);
}
/**
* 根据page对象获取对应的分页查询Sql语句,这⾥只做了两种数据库类型,Mysql和Oracle * 其它的数据库都 没有进⾏分页
*
* @param page 分页对象
* @param sql 原sql语句
* @return
*/
private String getPageSql(Page> page, String sql) {
StringBuffer sqlBuffer = new StringBuffer(sql);
if ("mysql".equalsIgnoreCase(dialect)) {
return getMysqlPageSql(page, sqlBuffer);
} else if ("oracle".equalsIgnoreCase(dialect)) {
return getOraclePageSql(page, sqlBuffer);
}
String();
}
/**
* 获取Mysql数据库的分页查询语句
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Mysql数据库分页语句
安装了java还要安装jdk吗*/
private String getMysqlPageSql(Page> page, StringBuffer sqlBuffer) {
//计算第⼀条记录的位置,Mysql中记录的位置是从0开始的。
/
/ System.out.println("page:"+Page()+"-------"+Rows());
int offset = (Page() - 1) * Rows();
sqlBuffer.append(" limit ").append(offset).append(",").Rows()); String();
}
/**

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。