2017.12.25 Mybatis物理分页插件PageHelper的使用(二)
2017-12-25 15:10
501 查看
参考来自:
官方文档的说明:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
上篇博客地址:2017.12.14 Mybatis物理分页插件PageHelper的使用
pageHelper的源码解读:http://blog.csdn.net/u014082617/article/details/71215539
现在的使用场景为:有一个web页面,需要用来测试数据库的连接信息,而数据库的类型是可选的。
页面示例如下:
所以原本的使用方式已经不再试用。因为需要根据不同的数据库来生成对应的分页语句。当然很多数据库对于通用的分页语句是支持的,但是为了考虑以后的拓展,以防有特殊语法的数据库出现(比如自定义的数据库),还是采用根据数据库类型来决定分页语句。
注意:mybatis的pageHelper插件5.x和4.x差别较大,这里使用的是4.x版本。
(2)SqlMapConfig.xml
这里和之前的区别就是不再指明dialect。
(3)pageHelper的源码解析
对pageHelper的源码学习后发现,在配置文件中不指明dialect,它的确会自动识别数据库类型,然后生成对应的分页语句。但是它只会生成一次,即如果第一次是postgresql,第二次是mysql,它会一直沿用postgresql(第一次生成sqlUtil后会放入sqlUtilMap,后面都会从map中取)。
pageHelper的源码参考来自:http://blog.csdn.net/u014082617/article/details/71215539
这和我的需求不一致。我需要为每个可能出现的数据库类型都生成一个sqlUtil,每种类型都只生成一次,并且放入sqlUtilMap中。因此将配置文件中的参数autoRuntimeDialect设为true。
(4)pageHelper的重写
这里有一个奇怪的问题:并没有生效。因此重写pageHelper的代码,在代码中将变量autoRuntimeDialect设置为true,而后生效。
但是运行后出现了另一问题:操作几次页面之后,连接超出最大数,连接失败。
查看pageHelper的源码发现,本来只执行一次的getSqlUtil,因为authRuntimeDialect=true,将会每次都去执行,如果有则从map中取,否则创建一个。
而为了拿到url而获取的连接并没有及时关闭,导致连接被多次创建,直到超过最大连接数。因此重写pageHelper。
原本代码是没有关闭connection的:
至此需求完成。
官方文档的说明:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
上篇博客地址:2017.12.14 Mybatis物理分页插件PageHelper的使用
pageHelper的源码解读:http://blog.csdn.net/u014082617/article/details/71215539
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版本。
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency>
(2)SqlMapConfig.xml
这里和之前的区别就是不再指明dialect。
<?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> <plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <!--<plugin interceptor="com.github.pagehelper.PageHelper">--> <plugin interceptor="com.baosight.ccs.PageHelper.CCSPageHelper"> <property name="autoRuntimeDialect" value="true"/> <!--<property name="dialect" value="postgresql"/>--> <!--设置为true时,使用rowbounds的时候,会将rowbonds的第一个参数offset当做pageNum使用,和startpage中的pageNum效果一样--> <!--<property name="offsetAsPageNum" value="true"/>--> <!--设置为true时,使用rowbounds分页时就会进行count查询--> <property name="rowBoundsWithCount" value="true"/> <!--设置为true时,如果pagesize=0或者rowbounds.limit=0就会查询出所有的结果--> <property name="pageSizeZero" value="true"/> <property name="reasonable" value="true"/> </plugin> </plugins> </configuration>
(3)pageHelper的源码解析
对pageHelper的源码学习后发现,在配置文件中不指明dialect,它的确会自动识别数据库类型,然后生成对应的分页语句。但是它只会生成一次,即如果第一次是postgresql,第二次是mysql,它会一直沿用postgresql(第一次生成sqlUtil后会放入sqlUtilMap,后面都会从map中取)。
pageHelper的源码参考来自:http://blog.csdn.net/u014082617/article/details/71215539
PageHelper SqlUtil PageSqlSource PostgreSQLParser
这和我的需求不一致。我需要为每个可能出现的数据库类型都生成一个sqlUtil,每种类型都只生成一次,并且放入sqlUtilMap中。因此将配置文件中的参数autoRuntimeDialect设为true。
(4)pageHelper的重写
这里有一个奇怪的问题:并没有生效。因此重写pageHelper的代码,在代码中将变量autoRuntimeDialect设置为true,而后生效。
package com.baosight.ccs.PageHelper; import com.baosight.common.utils.StringUtils; import com.github.pagehelper.PageHelper; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 自定义的分页拦截器,支持通用的数据库和自定义的sts数据库 */ @SuppressWarnings("rawtypes") @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})) public class CCSPageHelper extends PageHelper { //sql工具类 private SqlUtil sqlUtil; //属性参数信息 private Properties properties; //配置对象方式 private SqlUtilConfig sqlUtilConfig; //自动获取dialect,如果没有setProperties或setSqlUtilConfig,也可以正常进行 private boolean autoDialect = true; //运行时自动获取dialect private boolean autoRuntimeDialect = true;
但是运行后出现了另一问题:操作几次页面之后,连接超出最大数,连接失败。
Caused by: org.apache.ibatis.exceptions.PersistenceException: ### 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。
package com.baosight.ccs.PageHelper; //import com.github.pagehelper.Dialect; import com.baosight.common.utils.StringUtils; import com.baosight.xinsight.dbs.datasource.MultiDataSource; import com.github.pagehelper.Dialect; import com.github.pagehelper.PageHelper; import com.github.pagehelper.SqlUtil; import com.github.pagehelper.SqlUtilConfig; import com.github.pagehelper.StringUtil; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; import javax.sql.DataSource; /** * 自定义的分页拦截器,支持通用的数据库和自定义的sts数据库 */ @SuppressWarnings("rawtypes") @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})) public class CCSPageHelper extends PageHelper { //sql工具类 private SqlUtil sqlUtil; //属性参数信息 private Properties properties; //配置对象方式 private SqlUtilConfig sqlUtilConfig; //自动获取dialect,如果没有setProperties或setSqlUtilConfig,也可以正常进行 private boolean autoDialect = true; //运行时自动获取dialect private boolean autoRuntimeDialect = true; //缓存 private Map<String, SqlUtil> urlSqlUtilMap = new ConcurrentHashMap<String, SqlUtil>(); private int count = 0; private static final Logger logger = LoggerFactory.getLogger(CCSPageHelper.class); @Override public SqlUtil getSqlUtil(Invocation invocation) { MappedStatement ms = (MappedStatement) invocation.getArgs()[0]; String url = null; Connection cn = null; try { DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource(); cn = dataSource.getConnection(); url = cn.getMetaData().getURL(); } catch (SQLException e) { throw new RuntimeException(e1);130 }finally { 131 try { 132 cn.close(); 133 } catch (SQLException e) { 134 throw new RuntimeException(e); 135 } 136 } //其余和pageHelper一样 } }
原本代码是没有关闭connection的:
String url; DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource(); try { url = dataSource.getConnection().getMetaData().getURL(); } catch (SQLException e) { throw new RuntimeException(e); }
至此需求完成。
相关文章推荐
- 2017.12.25 Mybatis物理分页插件PageHelper的使用(二)
- 2017.12.14 Mybatis物理分页插件PageHelper的使用(一)
- 2017.12.14 Mybatis物理分页插件PageHelper的使用(一)
- 基于ssm框架的mybatis pagehelper分页插件的使用
- mybatis-PageHelper分页插件的原理和使用
- mybatis分页插件pageHelper的使用
- Mybatis分页插件-PageHelper(5.0)的使用
- Mybatis中分页插件PageHelper的使用
- Mybatis分页插件-PageHelper的使用
- mybatis框架---分页插件PageHelper的使用方法
- Mybatis的插件 PageHelper 分页查询使用方法
- Mybatis分页插件PageHelper的使用
- 【TaoTao】Mybatis 系列(3)——Mybatis下使用PageHelper分页插件
- Mybatis分页插件PageHelper简单使用
- Mybatis 数据库物理分页插件 PageHelper
- 【MyBatis】MyBatis分页插件PageHelper的使用
- Mybatis 数据库物理分页 PageHelper的使用教程
- MyBatis分页插件PageHelper的使用
- Mybatis的插件 PageHelper 分页查询使用方法
- Mybatis 的分页插件PageHelper-4.1.1的使用