2017.12.25 Mybatis物理分頁插件PageHelper的使用(二) 2017.12.14 Mybatis物理分頁插件PageHelper的使用 2017.12.14 Mybatis物理分

參考來自:html

 

1.需求說明

在上篇關於mybatis的pageHelper的使用中,講述了基本使用。java

如今的使用場景爲:有一個web頁面,須要用來測試數據庫的鏈接信息,而數據庫的類型是可選的。mysql

頁面示例以下:git

 

因此本來的使用方式已經再也不試用。由於須要根據不一樣的數據庫來生成對應的分頁語句。固然不少數據庫對於通用的分頁語句是支持的,可是爲了考慮之後的拓展,以防有特殊語法的數據庫出現(好比自定義的數據庫),仍是採用根據數據庫類型來決定分頁語句。github

 

2.實際使用

2.1 舊代碼和舊配置

2017.12.14 Mybatis物理分頁插件PageHelper的使用web

 

2.2 新代碼和新配置

(1)pom.xml

注意:mybatis的pageHelper插件5.x和4.x差異較大,這裏使用的是4.x版本。sql

1         <dependency>
2             <groupId>com.github.pagehelper</groupId>
3             <artifactId>pagehelper</artifactId>
4             <version>4.1.0</version>
5         </dependency>

 

(2)SqlMapConfig.xml

這裏和以前的區別就是再也不指明dialect。數據庫

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration
 3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
13     <plugins>
14         <!-- com.github.pagehelper爲PageHelper類所在包名 -->
15         <!--<plugin interceptor="com.github.pagehelper.PageHelper">-->
16         <plugin interceptor="com.baosight.ccs.PageHelper.CCSPageHelper">
17             <property name="autoRuntimeDialect" value="true"/>
18             <!--<property name="dialect" value="postgresql"/>-->
19           
25             <!--設置爲true時,使用rowbounds的時候,會將rowbonds的第一個參數offset當作pageNum使用,和startpage中的pageNum效果同樣-->
26             <!--<property name="offsetAsPageNum" value="true"/>-->
27 <!--設置爲true時,使用rowbounds分頁時就會進行count查詢--> 28 <property name="rowBoundsWithCount" value="true"/>
29 <!--設置爲true時,若是pagesize=0或者rowbounds.limit=0就會查詢出全部的結果--> 30 <property name="pageSizeZero" value="true"/>
31 <property name="reasonable" value="true"/> 32 </plugin> 33 </plugins> 34 </configuration>

 

(3)pageHelper的源碼解析

對pageHelper的源碼學習後發現,在配置文件中不指明dialect,它的確會自動識別數據庫類型,而後生成對應的分頁語句。可是它只會生成一次,即若是第一次是postgresql,第二次是mysql,它會一直沿用postgresql(第一次生成sqlUtil後會放入sqlUtilMap,後面都會從map中取)。apache

pageHelper的源碼參考來自:http://blog.csdn.net/u014082617/article/details/71215539緩存

1 PageHelper
2 SqlUtil
3 PageSqlSource
4 PostgreSQLParser

 

這和個人需求不一致。我須要爲每一個可能出現的數據庫類型都生成一個sqlUtil,每種類型都只生成一次,而且放入sqlUtilMap中。所以將配置文件中的參數autoRuntimeDialect設爲true。

 

(4)pageHelper的重寫

這裏有一個奇怪的問題:並無生效。所以重寫pageHelper的代碼,在代碼中將變量autoRuntimeDialect設置爲true,然後生效

  1 package com.baosight.ccs.PageHelper;
  2 
  4 import com.baosight.common.utils.StringUtils;  7 import com.github.pagehelper.PageHelper;
 12 import org.apache.ibatis.executor.Executor;
 13 import org.apache.ibatis.mapping.MappedStatement;
 14 import org.apache.ibatis.plugin.Intercepts;
 15 import org.apache.ibatis.plugin.Invocation;
 16 import org.apache.ibatis.plugin.Signature;
 17 import org.apache.ibatis.session.ResultHandler;
 18 import org.apache.ibatis.session.RowBounds;
 19 import org.slf4j.Logger;
 20 import org.slf4j.LoggerFactory; 31 
 32 /**
 33  * 自定義的分頁攔截器,支持通用的數據庫和自定義的sts數據庫
 34  */
 35 @SuppressWarnings("rawtypes")
 36 @Intercepts(@Signature(type = Executor.class, method = "query", 
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})) 37 public class CCSPageHelper extends PageHelper { 38 //sql工具類 39 private SqlUtil sqlUtil; 40 //屬性參數信息 41 private Properties properties; 42 //配置對象方式 43 private SqlUtilConfig sqlUtilConfig; 44 //自動獲取dialect,若是沒有setProperties或setSqlUtilConfig,也能夠正常進行 45 private boolean autoDialect = true; 46 //運行時自動獲取dialect 47 private boolean autoRuntimeDialect = true;

 

可是運行後出現了另外一問題:操做幾回頁面以後,鏈接超出最大數,鏈接失敗。

1 Caused by: org.apache.ibatis.exceptions.PersistenceException: 
2 ### Error querying database.  Cause: java.lang.RuntimeException: com.alibaba.druid.pool.GetConnectionTimeoutException: 
wait millis 10000, active 15, maxActive 15

 

查看pageHelper的源碼發現,原本只執行一次的getSqlUtil,由於authRuntimeDialect=true,將會每次都去執行,若是有則從map中取,不然建立一個。

而爲了拿到url而獲取的鏈接並無及時關閉,致使鏈接被屢次建立,直到超過最大鏈接數。所以重寫pageHelper。

  1 package com.baosight.ccs.PageHelper;
  2 
  3 //import com.github.pagehelper.Dialect;
  4 import com.baosight.common.utils.StringUtils;
  5 import com.baosight.xinsight.dbs.datasource.MultiDataSource;
  6 import com.github.pagehelper.Dialect;
  7 import com.github.pagehelper.PageHelper;
  8 import com.github.pagehelper.SqlUtil;
  9 import com.github.pagehelper.SqlUtilConfig;
 10 import com.github.pagehelper.StringUtil;
 11 
 12 import org.apache.ibatis.executor.Executor;
 13 import org.apache.ibatis.mapping.MappedStatement;
 14 import org.apache.ibatis.plugin.Intercepts;
 15 import org.apache.ibatis.plugin.Invocation;
 16 import org.apache.ibatis.plugin.Signature;
 17 import org.apache.ibatis.session.ResultHandler;
 18 import org.apache.ibatis.session.RowBounds;
 19 import org.slf4j.Logger;
 20 import org.slf4j.LoggerFactory;
 21 
 22 import java.sql.Connection;
 23 import java.sql.DatabaseMetaData;
 24 import java.sql.SQLException;
 25 import java.util.Map;
 26 import java.util.Properties;
 27 import java.util.concurrent.ConcurrentHashMap;
 28 import java.util.concurrent.locks.ReentrantLock;
 29 
 30 import javax.sql.DataSource;
 31 
 32 /**
 33  * 自定義的分頁攔截器,支持通用的數據庫和自定義的sts數據庫
 34  */
 35 @SuppressWarnings("rawtypes")
 36 @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
 37 public class CCSPageHelper extends PageHelper {
 38     //sql工具類
 39     private SqlUtil sqlUtil;
 40     //屬性參數信息
 41     private Properties properties;
 42     //配置對象方式
 43     private SqlUtilConfig sqlUtilConfig;
 44     //自動獲取dialect,若是沒有setProperties或setSqlUtilConfig,也能夠正常進行
 45     private boolean autoDialect = true;
 46     //運行時自動獲取dialect
 47     private boolean autoRuntimeDialect = true;
 48     //緩存
 49     private Map<String, SqlUtil> urlSqlUtilMap = new ConcurrentHashMap<String, SqlUtil>();
 50 
 51     private int count = 0;
 52     private static final Logger logger = LoggerFactory.getLogger(CCSPageHelper.class);
106 
107     @Override
108     public SqlUtil getSqlUtil(Invocation invocation) {
109         MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
110         
111         String url = null;
112         Connection cn = null;
113         try {
114             DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource();
115             cn = dataSource.getConnection();
116             url = cn.getMetaData().getURL();
117         } catch (SQLException e) {
118           throw new RuntimeException(e1);130 }finally { 131 try { 132 cn.close(); 133 } catch (SQLException e) { 134 throw new RuntimeException(e); 135 } 136 } 137 
138         //其他和pageHelper同樣171     }
172 }

 

 本來代碼是沒有關閉connection的:

1         String url;
2         DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource();
3         try {
4             url = dataSource.getConnection().getMetaData().getURL();
5         } catch (SQLException e) {
6             throw new RuntimeException(e);
7         }

 

 至此需求完成。

相關文章
相關標籤/搜索