引入seata后框架中的分页插件不能正常使用

现象: 框架中的分页插件不自动的查询count值了; 找了对应的分页插件信息并没有什么变化,并且在有些服务中可以正常使用,有些服务中不能正常使用了,这就很让人费解

首先这个分页的插件是自定义,自动查询count 数量,前端传递不同参数,对应的控制当前页,和每页显示几条;分页插件只对数据库的查询操作进行拦截,后面我会发源码出来;

原因: 近期在各服务项目中改用了seata 来出来分布式事物问题

alibaba-seata和自定义的数据库分页插件PaginationInterceptor相互影响了,只要是开启了seate 注解对应的服务,都会导致分页的插件不能正常的分页.是因为我们在初始化seata 时对sqlSessionFactory 进行了代理修改了一些内容导致了分页插件不能正常使用;

结论:如果对sqlSessionFactory 进行了代理,就需要彻底的把自己用到的一些功能信息都加上,不然就会导致一些bug出现sqlSessionFactoryBean.setPlugins(new Interceptor[] { pageHelper });

下面是分页插件代码;

public class PaginationInterceptor extends BaseInterceptor {

    private static final long serialVersionUID = 1L;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (ConverterUtil.isEmpty(DIALECT)) {
            setProperties(null);
        }

        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();
            // 若不是多表关联分页查询,进行分页处理,关联查询则跳过
            if (StringUtils.indexOfIgnoreCase(mappedStatement.getId(), "subQuery") == -1) {
                // 得到总记录数
                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);
                }
                if (Reflections.getFieldValue(boundSql, "additionalParameters") != null) {
                    Map<String, Object> map = (Map<String, Object>) Reflections.getFieldValue(boundSql, "additionalParameters");
                    Reflections.setFieldValue(newBoundSql, "additionalParameters", map);
                }
                //解决MyBatis 分页foreach 参数失效 end
                MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));

                invocation.getArgs()[0] = newMs;
            } else {
                String sqlName = mappedStatement.getId();
                // 一对多翻页查询对应两个方法*SubQuery和*SubQueryCount count应只查询主表的记录 SubQuery应关联子表数据
                final MappedStatement mappedStatementForCount = mappedStatement.getConfiguration().getMappedStatement(sqlName + "Count");
                BoundSql boundSqlCount = mappedStatementForCount.getBoundSql(parameter);
                Object parameterObjectCount = boundSqlCount.getParameterObject();
                if (StringUtils.isBlank(boundSqlCount.getSql())) {
                    return null;
                }
                String originalSqlCount = boundSqlCount.getSql().trim();
                page.setCount(SQLHelper.getCount(originalSqlCount, null, mappedStatement, parameterObjectCount, boundSqlCount, log));
            }
        }
        // }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        super.initProperties(properties);
    }

    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null) {
            for (String keyProperty : ms.getKeyProperties()) {
                builder.keyProperty(keyProperty);
            }
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.cache(ms.getCache());
        return builder.build();
    }

    public static class BoundSqlSqlSource implements SqlSource {
        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
}

seata 初始化的代码

public class DynamicDataSourceConfiguration {
    @Autowired
    private MultiDataSourceRegister register;
    @Autowired
    private DynamicDataSource dynamicDataSource;
    @Autowired
    private PaginationInterceptor pageHelper;

    @PostConstruct
    public void initDataSourceProxy() {
        Map<String, DataSource> dataSources = register.getDataSources();
        Map<Object, Object> targetDataSources = Maps.newHashMap();

        dataSources.forEach((e, d)->{
            DataSourceProxy dataSourceProxy = new DataSourceProxy(d);
            dataSources.put(e, dataSourceProxy);
            targetDataSources.put(e, dataSourceProxy);
        });

        if(dataSources.containsKey("master")){
            dynamicDataSource.setDefaultTargetDataSource(dataSources.get("master"));
        }else{
            AtomicReference<DataSource> defaultDataSource = new AtomicReference();
            dataSources.forEach((e, d)->{
                if(ConverterUtil.isEmpty(defaultDataSource.get())){
                    defaultDataSource.set(d);
                }
            });
            dynamicDataSource.setDefaultTargetDataSource(defaultDataSource.get());
        }
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.afterPropertiesSet();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory()throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:/mappings/**/*.xml"));
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        sqlSessionFactoryBean.setTypeAliasesPackage("com.wisea.cloud.common");
        sqlSessionFactoryBean.setTypeAliasesSuperType(BaseEntity.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setPlugins(new Interceptor[] { pageHelper });
        return sqlSessionFactoryBean.getObject();
    }
}

将工程中分页的插件 注入进来,进行设置

posted on 2020-12-30 15:14  时倏珍慧  阅读(258)  评论(0编辑  收藏  举报