• 2017.12.25 Mybatis物理分页插件PageHelper的使用(二)


    参考来自:

    1.需求说明

    在上篇关于mybatis的pageHelper的使用中,讲述了基本使用。

    现在的使用场景为:有一个web页面,需要用来测试数据库的连接信息,而数据库的类型是可选的。

    页面示例如下:

    所以原本的使用方式已经不再试用。因为需要根据不同的数据库来生成对应的分页语句。当然很多数据库对于通用的分页语句是支持的,但是为了考虑以后的拓展,以防有特殊语法的数据库出现(比如自定义的数据库),还是采用根据数据库类型来决定分页语句。

    2.实际使用

    2.1 旧代码和旧配置

    2017.12.14 Mybatis物理分页插件PageHelper的使用

    2.2 新代码和新配置

    (1)pom.xml

    注意:mybatis的pageHelper插件5.x和4.x差别较大,这里使用的是4.x版本。

    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中取)。

    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         }

     至此需求完成。

  • 相关阅读:
    c# 构架WPF 纸牌游戏(斗地主2)
    超级灰色按钮克星更新v1.3.1112.40
    早期绑定、动态绑定、后期绑定
    反射、反射加壳、反射脱壳、反射注册机(上)
    c# 构架WPF 纸牌游戏(斗地主4)
    Google首页吃豆游戏完整源码下载,以及声音问题的解决
    c# 构架WPF 纸牌游戏(斗地主1)
    c# 构架WPF 纸牌游戏(斗地主3)
    反射、反射加壳、反射脱壳、反射注册机(下)
    未能加载文件或程序集一例
  • 原文地址:https://www.cnblogs.com/lyh421/p/8109510.html
Copyright © 2020-2023  润新知