在java代碼中對(duì)于PageHelper的配置
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage(MODEL_PACKAGE);
// 配置分頁(yè)插件,詳情請(qǐng)查閱官方文檔
CustomPageHelper customPageHelper = new CustomPageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分頁(yè)尺寸為0時(shí)查詢所有紀(jì)錄不再執(zhí)行分頁(yè)
properties.setProperty("reasonable", "true");//頁(yè)碼<=0 查詢第一頁(yè),頁(yè)碼>=總頁(yè)數(shù)查詢最后一頁(yè)
properties.setProperty("supportMethodsArguments", "true");//支持通過(guò) Mapper 接口參數(shù)來(lái)傳遞分頁(yè)參數(shù)
customPageHelper.setProperties(properties);
// 添加插件
factory.setPlugins(new Interceptor[]{customPageHelper});
// 添加X(jué)ML目錄
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return factory.getObject();
}
在xml中配置 Interceptor ==> PageHelper
6 <configuration>
7 <plugins>
8 <plugin interceptor="com.github.pagehelper.PageHelper">
9 <!--指明數(shù)據(jù)庫(kù) 4.0.0以后不需要設(shè)置此屬性-->
10 <property name="dialect" value="mysql"/>
11 <!-- 該參數(shù)默認(rèn)為false -->
12 <!-- 設(shè)置為true時(shí),會(huì)將RowBounds第一個(gè)參數(shù)offset當(dāng)成pageNum頁(yè)碼使用 -->
13 <!-- 和startPage中的pageNum效果一樣-->
14 <property name="offsetAsPageNum" value="true"/>
15 <!-- 該參數(shù)默認(rèn)為false -->
16 <!-- 設(shè)置為true時(shí),使用RowBounds分頁(yè)會(huì)進(jìn)行count查詢 -->
17 <property name="rowBoundsWithCount" value="true"/>
18 <!-- 設(shè)置為true時(shí),如果pageSize=0或者RowBounds.limit = 0就會(huì)查詢出全部的結(jié)果 -->
19 <!-- (相當(dāng)于沒(méi)有執(zhí)行分頁(yè)查詢,但是返回結(jié)果仍然是Page類型)-->
20 <property name="pageSizeZero" value="true"/>
21 <!-- 3.3.0版本可用 - 分頁(yè)參數(shù)合理化,默認(rèn)false禁用 -->
22 <!-- 啟用合理化時(shí),如果pageNum<1會(huì)查詢第一頁(yè),如果pageNum>pages會(huì)查詢最后一頁(yè) -->
23 <!-- 禁用合理化時(shí),如果pageNum<1或pageNum>pages會(huì)返回空數(shù)據(jù) -->
24 <property name="reasonable" value="true"/>
25 <!-- 3.5.0版本可用 - 為了支持startPage(Object params)方法 -->
26 <!-- 增加了一個(gè)`params`參數(shù)來(lái)配置參數(shù)映射,用于從Map或ServletRequest中取值 -->
27 <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默認(rèn)值 -->
28 <!-- 不理解該含義的前提下,不要隨便復(fù)制該配置 -->
29 <property name="params" value="pageNum=start;pageSize=limit;"/>
30 <!-- 支持通過(guò)Mapper接口參數(shù)來(lái)傳遞分頁(yè)參數(shù) -->
31 <property name="supportMethodsArguments" value="true"/>
32 <!-- always總是返回PageInfo類型,check檢查返回類型是否為PageInfo,none返回Page -->
33 <property name="returnPageInfo" value="check"/>
34 </plugin>
35 </plugins>
36 </configuration>
配置SqlSessionFactory,主要是配置mapper映射與pageHelper
1 <!-- SqlSessionFactory -->
2 <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
3 <!--設(shè)置數(shù)據(jù)源-->
4 <property name="dataSource" ref="dataSource"></property>
5 <!--設(shè)置映射文件-->
6 <property name="mapperLocations" value="classpath:mybatis/sqlmap/mapper/*.xml"></property>
7 <!--設(shè)置pageHelper-->
8 <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
9 </bean>
xml配置參考自在流云的博客
正題部分
實(shí)際上,這些配置都是在進(jìn)行Mybatis插件(plugins)的配置。
Mybatis允許你在已映射語(yǔ)句執(zhí)行過(guò)程中的某一點(diǎn)進(jìn)行攔截調(diào)用,默認(rèn)情況下,MyBatis允許使用插件來(lái)攔截的方法包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
這些類中方法的細(xì)節(jié)可以通過(guò)查看每個(gè)方法的簽名來(lái)發(fā)現(xiàn),或者直接查看 MyBatis 的發(fā)行包中的源代碼。 假設(shè)你想做的不僅僅是監(jiān)控方法的調(diào)用,那么你應(yīng)該很好的了解正在重寫的方法的行為。 因?yàn)槿绻谠噲D修改或重寫已有方法的行為的時(shí)候,你很可能在破壞 MyBatis 的核心模塊。 這些都是更低層的類和方法,所以使用插件的時(shí)候要特別當(dāng)心。
通過(guò) MyBatis 提供的強(qiáng)大機(jī)制,使用插件是非常簡(jiǎn)單的,只需實(shí)現(xiàn) Interceptor 接口,并指定了想要攔截的方法簽名即可。
第一個(gè)方法,顧名思義,配置攔截器,攔截器的參數(shù) Invocation 中帶有以下屬性:
- Object target
- Method method
- Object[] args
在PageHelper中,使用了sqlUtil.intercept進(jìn)行了一次轉(zhuǎn)發(fā),將 Invocation 賦值給了SqlUtil的intercept方法
在這個(gè)方法中,調(diào)用了真正的攔截器方法。
第二個(gè)方法,plugin,返回了自身
第三個(gè)方法,用于配置中定義屬性
@SuppressWarnings("rawtypes")
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class CustomPageHelper extends PageHelper{
private final CustomSqlUtil sqlUtil = new CustomSqlUtil();
@Override
public Object intercept(Invocation invocation) throws Throwable {
return sqlUtil.intercept(invocation);
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
sqlUtil.setProperties(properties);
}
}
這個(gè)時(shí)候反過(guò)來(lái)看,
// 配置分頁(yè)插件,詳情請(qǐng)查閱官方文檔
CustomPageHelper customPageHelper = new CustomPageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分頁(yè)尺寸為0時(shí)查詢所有紀(jì)錄不再執(zhí)行分頁(yè)
properties.setProperty("reasonable", "true");//頁(yè)碼<=0 查詢第一頁(yè),頁(yè)碼>=總頁(yè)數(shù)查詢最后一頁(yè)
properties.setProperty("supportMethodsArguments", "true");//支持通過(guò) Mapper 接口參數(shù)來(lái)傳遞分頁(yè)參數(shù)
customPageHelper.setProperties(properties);
這些屬性,在PageHelper中,都是需要通過(guò)SqlUtil去處理的。
public void setProperties(Properties properties) {
super.setProperties(properties);
//多數(shù)據(jù)源時(shí),獲取jdbcurl后是否關(guān)閉數(shù)據(jù)源
String closeConn = properties.getProperty("closeConn");
//解決#97
if(StringUtil.isNotEmpty(closeConn)){
this.closeConn = Boolean.parseBoolean(closeConn);
}
//數(shù)據(jù)庫(kù)方言
String dialect = properties.getProperty("dialect");
String runtimeDialect = properties.getProperty("autoRuntimeDialect");
if (StringUtil.isNotEmpty(runtimeDialect) && runtimeDialect.equalsIgnoreCase("TRUE")) {
this.autoRuntimeDialect = true;
this.autoDialect = false;
this.properties = properties;
} else if (StringUtil.isEmpty(dialect)) {
autoDialect = true;
this.properties = properties;
} else {
autoDialect = false;
this.dialect = initDialect(dialect, properties);
}
try {
//反射獲取 BoundSql 中的 additionalParameters 屬性
additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
additionalParametersField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
另外的,同樣重要的是攔截器上的注解
@Intercepts(
@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
@Intercepts表明當(dāng)前對(duì)象是一個(gè)Interceptor
@Signature則表明要攔截的接口、方法以及對(duì)應(yīng)的參數(shù)類型
上面的注解表明,在查詢時(shí),type = Executor.class(暫時(shí)沒(méi)弄明白),字面意思應(yīng)該是在查詢執(zhí)行的時(shí)候,攔截了MappedStatement,Object,RowBounds,ResultHandler。
MappedStatement:對(duì)應(yīng)mapper配置文件中一個(gè)節(jié)點(diǎn),主要描述的是一條SQL語(yǔ)句。
其中有許多屬性,包括使用了哪個(gè)mapper,使用了dao的哪個(gè)方法之類的。
Object:主要指的是參數(shù)
例如使用了condition進(jìn)行查詢,object將帶有Criteria對(duì)象,entityClass,orderBy之類的屬性。
RowBounds:主要指的偏移量,可以用它來(lái)進(jìn)行分頁(yè)(pageHelper好像并不使用它)
ResultHandler:暫時(shí)不知道是干什么的,百度說(shuō):
有些sql查詢會(huì)返回一些復(fù)雜類型,這些復(fù)雜類型沒(méi)有辦法簡(jiǎn)單的通過(guò)xml或者注解配置來(lái)實(shí)現(xiàn),這種時(shí)候我們需要實(shí)現(xiàn)mybatis 的ResultHandler接口,來(lái)做自定義的對(duì)象屬性映射。