/** * * * <pre> * 查询总数 * </pre> * * @author jundong.xu_C * @param page * @param parameterObject * @param mappedStatement * @param connection * @throws SQLException */ protected void queryTotalRecord( Page<?> page, Object parameterObject, MappedStatement mappedStatement, Connection connection) throws SQLException { BoundSql boundSql = mappedStatement.getBoundSql(parameterObject); String sql = boundSql.getSql(); String countSql = this.buildCountSql(sql); if (log.isDebugEnabled()) { log.debug("分页时, 生成countSql: " + countSql); } List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); BoundSql countBoundSql = new BoundSql( mappedStatement.getConfiguration(), countSql, parameterMappings, parameterObject); ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBoundSql); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = connection.prepareStatement(countSql); parameterHandler.setParameters(pstmt); rs = pstmt.executeQuery(); if (rs.next()) { long totalRecord = rs.getLong(1); int pageSize = page.getPageSize(); int totalPage = (int) (totalRecord + pageSize - 1) / pageSize; page.setTotalSize(totalRecord); page.setTotalPage(totalPage); } } finally { if (rs != null) try { rs.close(); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("关闭ResultSet时异常.", e); } } if (pstmt != null) try { pstmt.close(); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("关闭PreparedStatement时异常.", e); } } } }
private int getCount( Connection connection, BoundSql boundSql, Configuration configuration, MappedStatement mappedStatement) throws SQLException { String countSql = "select count(0) from ( " + boundSql.getSql() + " )"; // 记录统计 PreparedStatement countStmt = connection.prepareStatement(countSql); BoundSql countBS = new BoundSql( configuration, countSql, boundSql.getParameterMappings(), boundSql.getParameterObject()); setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject()); ResultSet rs = countStmt.executeQuery(); int count = 0; if (rs.next()) { count = rs.getInt(1); } rs.close(); countStmt.close(); return count; }
private void pagination(Invocation invocation, StatementHandler target) throws SQLException { final MetaObject metaStatementHandler = getMetaObject(target); final BoundSql boundSql = target.getBoundSql(); Page<?> page = PAGE_THREAD_LOCAL.get(); if (page == null) { page = findPageParameter(boundSql.getParameterObject()); } // 如果传入的参数中有分页对象且sql语句中有select,才做分页处理 String sql = boundSql.getSql().toLowerCase(); if (sql.startsWith("select") && page != null) { // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); // 设置分页对象里的总记录数和总页数 Connection connection = (Connection) invocation.getArgs()[0]; MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); if (page.isCountTotal()) { int recordsTotal = getTotalCount(sql, connection, mappedStatement, boundSql); page.setTotalNum(recordsTotal); } // 最后重写sql String pageSql = buildPageSql(sql, page); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); } }
@SuppressWarnings("rawtypes") @Override protected BoundSql getPageBoundSql(Object parameterObject) { DynamicContext context; // 由于增加分页参数后会修改parameterObject的值,因此在前面处理时备份该值 // 如果发现参数是Map并且包含该KEY,就使用备份的该值 // 解决bug#25:http://git.oschina.net/free/Mybatis_PageHelper/issues/25 if (parameterObject != null && parameterObject instanceof Map && ((Map) parameterObject).containsKey(ORIGINAL_PARAMETER_OBJECT)) { context = new DynamicContext(configuration, ((Map) parameterObject).get(ORIGINAL_PARAMETER_OBJECT)); } else { context = new DynamicContext(configuration, parameterObject); } rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); sqlSource = new OrderByStaticSqlSource((StaticSqlSource) sqlSource); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); sqlSource = new StaticSqlSource( configuration, parser.getPageSql(boundSql.getSql()), parser.getPageParameterMapping(configuration, boundSql)); boundSql = sqlSource.getBoundSql(parameterObject); // 设置条件参数 for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }
public Object intercept(Invocation invocation) throws Throwable { StatementHandler handler = (StatementHandler) invocation.getTarget(); MetaObject metaObject = MetaObject.forObject(handler); Page page = pageByMetaObject(metaObject); if (page == null || (page.getPageCount() == 0 && page.getPageSize() == 0)) return invocation.proceed(); Configuration configuration = (Configuration) metaObject.getValue("delegate.configuration"); BoundSql orgBoundSql = (BoundSql) metaObject.getValue("delegate.boundSql"); if (page.getCount() == 0) { MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); page.setCount( totalCount( (Connection) invocation.getArgs()[0], orgBoundSql, configuration, mappedStatement)); } metaObject.setValue( "delegate.boundSql.sql", searchDialectByDbTypeEnum(configuration, page) .spellPageSql(orgBoundSql.getSql(), page.getOffset(), page.getLimit())); logger.debug("pagination sql : {}", handler.getBoundSql().getSql()); return invocation.proceed(); }
public Object intercept(Invocation ivk) throws Throwable { // TODO Auto-generated method stub if (ivk.getTarget() instanceof RoutingStatementHandler) { RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget(); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement"); if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQL BoundSql boundSql = delegate.getBoundSql(); Object parameterObject = boundSql .getParameterObject(); // 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空 if (parameterObject == null) { throw new NullPointerException("parameterObject尚未实例化!"); } else { Connection connection = (Connection) ivk.getArgs()[0]; String sql = boundSql.getSql(); String countSql = "select count(0) from (" + sql + ") as tmp_count"; // 记录统计 PreparedStatement countStmt = connection.prepareStatement(countSql); BoundSql countBS = new BoundSql( mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject); setParameters(countStmt, mappedStatement, countBS, parameterObject); ResultSet rs = countStmt.executeQuery(); int count = 0; if (rs.next()) { count = rs.getInt(1); } rs.close(); countStmt.close(); // System.out.println(count); Page page = null; if (parameterObject instanceof Page) { // 参数就是Page实体 page = (Page) parameterObject; page.setEntityOrField(true); // 见com.ttsoft.entity.Page.entityOrField 注释 page.setTotalResult(count); } else { // 参数为某个实体,该实体拥有Page属性 Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "page"); if (pageField != null) { page = (Page) ReflectHelper.getValueByFieldName(parameterObject, "page"); if (page == null) page = new Page(); page.setEntityOrField(false); // 见com.ttsoft.entity.Page.entityOrField 注释 page.setTotalResult(count); ReflectHelper.setValueByFieldName(parameterObject, "page", page); // 通过反射,对实体对象设置分页对象 } else { throw new NoSuchFieldException(parameterObject.getClass().getName() + "不存在 page 属性!"); } } String pageSql = generatePageSql(sql, page); ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql. } } } return ivk.proceed(); }
public CacheKey createCacheKey( MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) throw new ExecutorException("Executor was closed."); CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { cacheKey.update(parameterObject); } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty(); if (metaObject.hasGetter(propertyName)) { cacheKey.update(metaObject.getValue(propertyName)); } else if (boundSql.hasAdditionalParameter(propertyName)) { cacheKey.update(boundSql.getAdditionalParameter(propertyName)); } } } } return cacheKey; }
private SqlSource getSqlSource( MappedStatement ms, SqlSource sqlSource, Object parameterObject, boolean isCount) { if (ms.getSqlSource() instanceof DynamicSqlSource) { MetaObject msObject = MetaObjectUtils.forObject(ms); SqlNode sqlNode = (SqlNode) msObject.getValue("sqlSource.rootSqlNode"); MixedSqlNode mixedSqlNode = null; if (sqlNode instanceof MixedSqlNode) { mixedSqlNode = (MixedSqlNode) sqlNode; } else { List<SqlNode> contents = new ArrayList<SqlNode>(1); contents.add(sqlNode); mixedSqlNode = new MixedSqlNode(contents); } return new CustomerDynamicSqlSource(ms.getConfiguration(), mixedSqlNode, isCount, dialect); } else if (sqlSource instanceof ProviderSqlSource) { return new CustomerProviderSqlSource( ms.getConfiguration(), (ProviderSqlSource) sqlSource, isCount, dialect); } else if (!isCount) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); return new StaticSqlSource( ms.getConfiguration(), dialect.generatePageSQL(boundSql.getSql()), MybatisUtils.plusTwoParameterToMapping(ms.getConfiguration(), boundSql)); } else { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); return new StaticSqlSource( ms.getConfiguration(), dialect.generateCountSQL(boundSql.getSql()), boundSql.getParameterMappings()); } }
/** * 获取总页数 * * @param conn * @param orgBoundSql * @param configuration * @param mappedStatement * @return * @throws SQLException */ private int totalCount( Connection conn, BoundSql orgBoundSql, Configuration configuration, MappedStatement mappedStatement) throws SQLException { String orgSql = orgBoundSql.getSql(); StringBuffer sqlBuffer = new StringBuffer(orgSql.length() + 100); sqlBuffer.append(" SELECT COUNT(0) FROM (").append(orgSql).append(") TEMP "); logger.debug(" this is countsql : {}", sqlBuffer.toString()); PreparedStatement preparedStatement = conn.prepareStatement(sqlBuffer.toString()); Object parameterObject = orgBoundSql.getParameterObject(); BoundSql boundSql = new BoundSql( configuration, sqlBuffer.toString(), orgBoundSql.getParameterMappings(), parameterObject); setParameters(preparedStatement, mappedStatement, boundSql, parameterObject); ResultSet rs = preparedStatement.executeQuery(); if (rs != null) { if (rs.next()) { return rs.getInt(1); } } return 0; }
/** * 对SQL参数(?)设值, 参考org.apache.ibatis.executor.parameter.DefaultParameterHandler。 * * @param ps 表示预编译的 SQL 语句的对象。 * @param mappedStatement MappedStatement * @param boundSql SQL * @param parameterObject 参数对象 * @throws java.sql.SQLException 数据库异常 */ @SuppressWarnings("unchecked") public static void setParameters( PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) throws SQLException { ErrorContext.instance() .activity("setting parameters") .object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { Configuration configuration = mappedStatement.getConfiguration(); TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject); for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); PropertyTokenizer prop = new PropertyTokenizer(propertyName); if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) { value = boundSql.getAdditionalParameter(prop.getName()); if (value != null) { value = configuration .newMetaObject(value) .getValue(propertyName.substring(prop.getName().length())); } } else { value = metaObject == null ? null : metaObject.getValue(propertyName); } @SuppressWarnings("rawtypes") TypeHandler typeHandler = parameterMapping.getTypeHandler(); if (typeHandler == null) { throw new ExecutorException( "There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId()); } typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType()); } } } }
@Override protected BoundSql getDefaultBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); sqlSource = new OrderByStaticSqlSource((StaticSqlSource) sqlSource); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); // 设置条件参数 for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }
/** * @description TODO * @createTime 2016-4-19 上午11:20:47 * @fileName CacheInterceptor.java * @author yaojiamin */ private BoundSql createPageBoundSql(CacheHandlerBean cacheHandlerBean, BoundSql boundSql) { return new BoundSql( cacheHandlerBean.getMappedStatement().getConfiguration(), createCountSql(boundSql), boundSql.getParameterMappings(), cacheHandlerBean.getParameterObject()); }
public Map setParameter( MappedStatement ms, Object parameterObject, PageParam page, Dialect dialect) { BoundSql boundSql = ms.getBoundSql(parameterObject); Map paramMap = null; if (parameterObject == null) { paramMap = new HashMap(); } else if (parameterObject instanceof Map) { paramMap = (Map) parameterObject; } else { paramMap = new HashMap(); boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass()); MetaObject metaObject = MetaObjectUtils.forObject(parameterObject); if (ms.getSqlSource() instanceof CustomerProviderSqlSource) { paramMap.put(Const.PROVIDER_OBJECT, parameterObject); } if (!hasTypeHandler) { for (String name : metaObject.getGetterNames()) { paramMap.put(name, metaObject.getValue(name)); } } if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) { for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { String name = parameterMapping.getProperty(); if (!name.equals(Const.PARAMETER_FIRST) && !name.equals(Const.PARAMETER_SECOND) && paramMap.get(name) == null) { if (hasTypeHandler || parameterMapping.getJavaType().equals(parameterObject.getClass())) { paramMap.put(name, parameterObject); break; } } } } } // 备份原始参数对象 paramMap.put(Const.ORIGINAL_PARAMETER_OBJECT, parameterObject); // 设置分页参数 Map<String, Object> customerPageParams = dialect.getPageParameter(page); if (customerPageParams != null) { for (String key : customerPageParams.keySet()) { paramMap.put(key, customerPageParams.get(key)); } } return paramMap; }
@Override public Object intercept(Invocation invocation) throws Throwable { // 当前环境 MappedStatement,BoundSql,及sql取得 MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; Object parameter = invocation.getArgs()[1]; BoundSql boundSql = mappedStatement.getBoundSql(parameter); String originalSql = boundSql.getSql().trim(); Object parameterObject = boundSql.getParameterObject(); // Page对象获取,“信使”到达拦截器! Page page = searchPageWithXpath(boundSql.getParameterObject(), SystemConstant.PAGE); // 如果分页参数存在,进行分页处理。 if (page != null) { String countSql = getCountSql(originalSql); Connection connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection(); PreparedStatement countStmt = connection.prepareStatement(countSql); BoundSql countBS = copyFromBoundSql(mappedStatement, boundSql, countSql); DefaultParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, countBS); parameterHandler.setParameters(countStmt); ResultSet rs = countStmt.executeQuery(); int totpage = 0; if (rs.next()) { totpage = rs.getInt(1); } rs.close(); countStmt.close(); connection.close(); // 分页计算 page.setTotalRecord(totpage); // 对原始Sql追加limit int offset = (page.getPageNo() - 1) * page.getPageSize(); StringBuffer sb = new StringBuffer(); sb.append(originalSql) .append(" limit ") .append(offset) .append(",") .append(page.getPageSize()); BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, sb.toString()); MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql)); invocation.getArgs()[0] = newMs; } return invocation.proceed(); }
/** * 对SQL参数(?)设值 * * @param ps * @param mappedStatement * @param boundSql * @param parameterObject * @throws SQLException */ private void setParameters( PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql) throws SQLException { ParameterHandler parameterHandler = mappedStatement .getConfiguration() .newParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql); parameterHandler.setParameters(ps); }
private void ensureNoOutParams(MappedStatement ms, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { throw new ExecutorException( "Caching stored procedures with OUT params is not supported. Please configure useCache=false in " + ms.getId() + " statement."); } } } }
public void setParameters(PreparedStatement ps) throws SQLException { ErrorContext.instance() .activity("setting parameters") .object(mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject); for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter( propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { value = metaObject == null ? null : metaObject.getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); if (typeHandler == null) { throw new ExecutorException( "There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId()); } JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull(); typeHandler.setParameter(ps, i + 1, value, jdbcType); } } } }
@Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); ParameterHandler parameterHandler = statementHandler.getParameterHandler(); BoundSql boundSql = statementHandler.getBoundSql(); MetaObject metaStatementHandler = MetaObject.forObject( statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds"); // 没有分页参数 if (rowBounds == null || rowBounds == RowBounds.DEFAULT) { return invocation.proceed(); } Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration"); Dialect dialect = DialectFactory.buildDialect(configuration); String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql"); // 获取总记录数 Page<?> page = (Page<?>) rowBounds; String countSql = dialect.getCountString(originalSql); Connection connection = (Connection) invocation.getArgs()[0]; int total = getTotal(parameterHandler, connection, countSql); page.setTotalCount(total); // 设置物理分页语句 metaStatementHandler.setValue( "delegate.boundSql.sql", dialect.getLimitString(originalSql, page.getOffset(), page.getLimit())); // 屏蔽mybatis原有分页 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); if (logger.isDebugEnabled()) { logger.debug("分页SQL : " + boundSql.getSql()); } return invocation.proceed(); }
/** * 获取总记录数 * * @param sql 原始sql语句 * @param conn * @param ms * @param boundSql * @return * @throws SQLException */ private int getTotalCount(String sql, Connection conn, MappedStatement ms, BoundSql boundSql) throws SQLException { int start = sql.indexOf("from"); if (start == -1) { throw new RuntimeException("statement has no 'from' keyword"); } int stop = sql.indexOf("order by"); if (stop == -1) { stop = sql.length(); } String countSql = "select count(0) " + sql.substring(start, stop); BoundSql countBoundSql = new BoundSql( ms.getConfiguration(), countSql, boundSql.getParameterMappings(), boundSql.getParameterObject()); ParameterHandler parameterHandler = new DefaultParameterHandler(ms, boundSql.getParameterObject(), countBoundSql); PreparedStatement stmt = null; ResultSet rs = null; int count = 0; try { stmt = conn.prepareStatement(countSql); // 通过parameterHandler给PreparedStatement对象设置参数 parameterHandler.setParameters(stmt); rs = stmt.executeQuery(); if (rs.next()) { count = rs.getInt(1); } } finally { CloseableUtil.closeQuietly(rs); CloseableUtil.closeQuietly(stmt); } return count; }
@Override public Object intercept(Invocation invocation) throws Throwable { final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; // //拦截需要分页的SQL //// if (mappedStatement.getId().matches(_SQL_PATTERN)) { // if (StringUtils.indexOfIgnoreCase(mappedStatement.getId(), _SQL_PATTERN) != -1) { Object parameter = invocation.getArgs()[1]; BoundSql boundSql = mappedStatement.getBoundSql(parameter); Object parameterObject = boundSql.getParameterObject(); // 获取分页参数对象 Page<Object> page = null; if (parameterObject != null) { page = convertParameter(parameterObject, page); } // 如果设置了分页对象,则进行分页 if (page != null && page.getPageSize() != -1) { if (StringUtils.isBlank(boundSql.getSql())) { return null; } String originalSql = boundSql.getSql().trim(); // 得到总记录数 page.setCount( SQLHelper.getCount(originalSql, null, mappedStatement, parameterObject, boundSql, log)); // 分页查询 本地化对象 修改数据库注意修改实现 String pageSql = SQLHelper.generatePageSql(originalSql, page, DIALECT); // if (log.isDebugEnabled()) { // log.debug("PAGE SQL:" + StringUtils.replace(pageSql, "\n", "")); // } invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT); BoundSql newBoundSql = new BoundSql( mappedStatement.getConfiguration(), pageSql, boundSql.getParameterMappings(), boundSql.getParameterObject()); // 解决MyBatis 分页foreach 参数失效 start if (Reflections.getFieldValue(boundSql, "metaParameters") != null) { MetaObject mo = (MetaObject) Reflections.getFieldValue(boundSql, "metaParameters"); Reflections.setFieldValue(newBoundSql, "metaParameters", mo); } // 解决MyBatis 分页foreach 参数失效 end MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql)); invocation.getArgs()[0] = newMs; } // } return invocation.proceed(); }
private void handleLocallyCachedOutputParameters( MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { final Object cachedParameter = localOutputParameterCache.getObject(key); if (cachedParameter != null && parameter != null) { final MetaObject metaCachedParameter = MetaObject.forObject(cachedParameter); final MetaObject metaParameter = MetaObject.forObject(parameter); for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { final String parameterName = parameterMapping.getProperty(); final Object cachedValue = metaCachedParameter.getValue(parameterName); metaParameter.setValue(parameterName, cachedValue); } } } } }
/** 复制BoundSql对象 */ private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) { BoundSql newBoundSql = new BoundSql( ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()); for (ParameterMapping mapping : boundSql.getParameterMappings()) { String prop = mapping.getProperty(); if (boundSql.hasAdditionalParameter(prop)) { newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop)); } } return newBoundSql; }
public void handleOutputParameters(CallableStatement cs) throws SQLException { final Object parameterObject = parameterHandler.getParameterObject(); final MetaObject metaParam = configuration.newMetaObject(parameterObject); final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); for (int i = 0; i < parameterMappings.size(); i++) { final ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (ResultSet.class.equals(parameterMapping.getJavaType())) { handleRefCursorOutputParameter( (ResultSet) cs.getObject(i + 1), parameterMapping, metaParam); } else { final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler(); metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); } } } }
@VisibleForTesting String tryConvertSql(BoundSql boundSql) { ExecutionConfig executeInfo = ExecuteInfoContext.getExecuteInfo(); if (executeInfo == null) { return null; } TableConfig tableConfig = executeInfo.getTableConfig(); if (tableConfig == null) { return null; } Locator locator = Locators.instance.takeLocator(checkNotNull(tableConfig.getRule())); String targetSuffix = locator.locate(tableConfig.getParams()); SqlConverterFactory converterFactory = SqlConverterFactory.getInstance(); return converterFactory.convert( boundSql.getSql(), targetSuffix, checkNotNull(tableConfig.getTablePattern())); }
/** * 查询总纪录数。 * * @param sql SQL语句 * @param connection 数据库连接 * @param mappedStatement mapped * @param parameterObject 参数 * @param boundSql boundSql * @return 总记录数 * @throws SQLException sql查询错误 */ public static int getCount( final String sql, final Connection connection, final MappedStatement mappedStatement, final Object parameterObject, final BoundSql boundSql) throws SQLException { final String countSql = "select count(1) from (" + sql + ")"; PreparedStatement countStmt = null; ResultSet rs = null; try { countStmt = connection.prepareStatement(countSql); BoundSql countBS = new BoundSql( mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject); SQLHelp.setParameters(countStmt, mappedStatement, countBS, parameterObject); rs = countStmt.executeQuery(); int count = 0; if (rs.next()) { count = rs.getInt(1); } logger.debug("Pagination TotalCount SQL: " + countSql); return count; } finally { if (rs != null) { rs.close(); } if (countStmt != null) { countStmt.close(); } if (connection != null) { connection.close(); } } }
/** * 获取一个Mybatis运行时调用的SQL和参数 * * @param ms * @param parameterObject * @return */ public static MyBatisSql getMyBatisSql(MappedStatement ms, Object parameterObject) { MyBatisSql ibatisSql = new MyBatisSql(); BoundSql boundSql = ms.getBoundSql(parameterObject); ibatisSql.setSql(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { Object[] parameterArray = new Object[parameterMappings.size()]; MetaObject metaObject = parameterObject == null ? null : MetaObject.forObject(parameterObject); for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); PropertyTokenizer prop = new PropertyTokenizer(propertyName); if (parameterObject == null) { value = null; } else if (ms.getConfiguration() .getTypeHandlerRegistry() .hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) { value = boundSql.getAdditionalParameter(prop.getName()); if (value != null) { value = MetaObject.forObject(value) .getValue(propertyName.substring(prop.getName().length())); } } else { value = metaObject == null ? null : metaObject.getValue(propertyName); } parameterArray[i] = value; } } ibatisSql.setParameters(parameterArray); } return ibatisSql; }
@Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = MetaObject.forObject( statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 // 可以分离出最原始的的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } // 分离最后一个代理对象的目标类 while (metaStatementHandler.hasGetter("target")) { Object object = metaStatementHandler.getValue("target"); metaStatementHandler = MetaObject.forObject( object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY); } if (null == dialect || "".equals(dialect)) { logger.warn("Property dialect is not setted,use default 'mysql' "); dialect = defaultDialect; } if (null == pageSqlId || "".equals(pageSqlId)) { logger.warn("Property pageSqlId is not setted,use default '.*Page$' "); pageSqlId = defaultPageSqlId; } MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); PageParameter page = null; Object type = metaStatementHandler.getValue("delegate.boundSql.parameterObject"); if (PageParameter.class.isInstance(type)) { page = (PageParameter) type; } // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的 // MappedStatement的sql if (mappedStatement.getId().matches(pageSqlId) && page != null && page.getLimit() > 0) { BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); Object parameterObject = boundSql.getParameterObject(); if (parameterObject == null) { throw new NullPointerException("parameterObject is null!"); } else { // 分页参数作为参数对象parameterObject的一个属性 String sql = boundSql.getSql(); // 重写sql String pageSql = buildPageSql(sql, page, dialect); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); Connection connection = (Connection) invocation.getArgs()[0]; // 重设分页参数里的总页数等 setPageParameter(sql, connection, mappedStatement, boundSql, page); } } // 将执行权交给下一个拦截器 return invocation.proceed(); }
@Override @SuppressWarnings({"unchecked", "rawtypes"}) public Object intercept(Invocation invocation) throws Throwable { if (invocation.getTarget() instanceof StatementHandler) { // 控制SQL和查询总数的地方 Page page = pageThreadLocal.get(); Order order = orderThreadLocal.get(); RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget(); StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate"); BoundSql boundSql = delegate.getBoundSql(); if (page == null) { // 不是分页查询 if (order != null) { String orderSql = buildOrderSql(order, boundSql.getSql()); ReflectUtil.setFieldValue(boundSql, "sql", orderSql); } return invocation.proceed(); } Connection connection = (Connection) invocation.getArgs()[0]; prepareAndCheckDatabaseType(connection); // 准备数据库类型 if (page.getTotalPage() > -1) { if (log.isTraceEnabled()) { log.trace("已经设置了总页数, 不需要再查询总数."); } } else { Object parameterObj = boundSql.getParameterObject(); MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement"); queryTotalRecord(page, parameterObj, mappedStatement, connection); } String sql = boundSql.getSql(); if (order != null) { sql = buildOrderSql(order, sql); } String pageSql = buildPageSql(page, sql); if (log.isDebugEnabled()) { log.debug("分页时, 生成分页pageSql: " + pageSql); } ReflectUtil.setFieldValue(boundSql, "sql", pageSql); return invocation.proceed(); } else { // 查询结果的地方 try { // 获取是否有分页Page对象 Page<?> page = findPageObject(invocation.getArgs()[1]); // 获取是否有排序Order对象 Order order = findOrderObject(invocation.getArgs()[1]); if (order != null) { orderThreadLocal.set(order); } if (page == null) { if (log.isTraceEnabled()) { log.trace("没有Page对象作为参数, 不是分页查询."); } return invocation.proceed(); } else { if (log.isTraceEnabled()) { log.trace("检测到分页Page对象, 使用分页查询."); } } // 设置真正的parameterObj invocation.getArgs()[1] = extractRealParameterObject(invocation.getArgs()[1]); pageThreadLocal.set(page); Object resultObj = invocation.proceed(); // Executor.query(..) if (resultObj instanceof List) { /* @SuppressWarnings({ "unchecked", "rawtypes" }) */ page.setDatas((List) resultObj); } return resultObj; } finally { pageThreadLocal.remove(); orderThreadLocal.remove(); } } }
@Override public List<ParameterMapping> getPageParameterMapping( Configuration configuration, BoundSql boundSql) { return boundSql.getParameterMappings(); }
public Object intercept(Invocation ivk) throws Throwable { if (ivk.getTarget() instanceof RoutingStatementHandler) { RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget(); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement"); if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQL BoundSql boundSql = delegate.getBoundSql(); Object parameterObject = boundSql .getParameterObject(); // 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空 if (parameterObject == null) { throw new NullPointerException("parameterObject尚未实例化!"); } else { long count = 0; String sql = ""; try { Connection connection = (Connection) ivk.getArgs()[0]; sql = boundSql.getSql(); String countSql = ""; if ("mysql".equals(dialect)) { countSql = "select count(1) from (" + sql + ") as tmp_count"; // 记录统计 } else if ("oracle".equals(dialect)) { countSql = "select count(1) from (" + sql + ") tmp_count"; // 记录统计 } PreparedStatement countStmt = connection.prepareStatement(countSql); BoundSql countBS = new BoundSql( mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject); setParameters(countStmt, mappedStatement, countBS, parameterObject); ResultSet rs = countStmt.executeQuery(); if (rs.next()) { count = rs.getLong(1); } rs.close(); countStmt.close(); } catch (Exception e) { throw new RuntimeException("分页查询无法获取总记录数", e); } Pagination page = null; if (parameterObject instanceof Pagination) { // 参数就是Pagination实体 page = (Pagination) parameterObject; page.setTotalRows(count); } else { // 参数为某个实体,该实体拥有Page属性 Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "pagination"); if (pageField != null) { page = (Pagination) ReflectHelper.getValueByFieldName(parameterObject, "pagination"); if (page == null) page = new Pagination(); page.setTotalRows(count); ReflectHelper.setValueByFieldName( parameterObject, "pagination", page); // 通过反射,对实体对象设置分页对象 } else { throw new NoSuchFieldException( parameterObject.getClass().getName() + "不存在 pagination 属性!"); } } String pageSql = generatePageSql(sql, page); ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql. } } } return ivk.proceed(); }