Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

springboot多数据源 配置对应数量的PageInterceptor 导致重复查询问题? #166

Closed
jht385 opened this issue Jan 8, 2018 · 6 comments

Comments

@jht385
Copy link

jht385 commented Jan 8, 2018

我这的需求是从一个oracle库读数据,写到mysql库

pagehelper 5.1.2
mybatis-spring-boot-starter 1.3.1

数据源我采用分目录的方式

@MapperScan(basePackages = "com.bingo.mapper.mysql", sqlSessionTemplateRef = "mysqlSqlSessionTemplate")
public class MysqlDataSourceConfig {
@MapperScan(basePackages = "com.bingo.mapper.oracle", sqlSessionTemplateRef = "oracleSqlSessionTemplate")
public class OracleDataSourceConfig {

SqlSessionFactory 配置对应的PageInterceptor

	@Bean(name = "mysqlSqlSessionFactory")
	@Primary
	public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource);
		bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/mysql/*.xml"));

		PageInterceptor pageHelper = new PageInterceptor();
		Properties properties = new Properties();
		properties.setProperty("dialect", "com.github.pagehelper.dialect.helper.MySqlDialect");
		properties.setProperty("reasonable", "false");
		properties.setProperty("pageSizeZero", "true");
		pageHelper.setProperties(properties);
		bean.setPlugins(new Interceptor[] { pageHelper });

		return bean.getObject();
	}
@Bean(name = "oracleSqlSessionFactory")
	public SqlSessionFactory oracleSqlSessionFactory(@Qualifier("oracleDataSource") DataSource dataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource);
		bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/oracle/*.xml"));
		
		PageInterceptor pageHelper = new PageInterceptor();
		Properties properties = new Properties();
		properties.setProperty("dialect", "com.github.pagehelper.dialect.helper.OracleDialect");
		properties.setProperty("reasonable", "false");
		properties.setProperty("pageSizeZero", "true");
		pageHelper.setProperties(properties);
		bean.setPlugins(new Interceptor[] { pageHelper });

		return bean.getObject();
	}

查询会出现的问题
1.查询数量会翻倍
2.查询结果,第一个元素会变成long,数据是总数,为了保证运行我要instanceof 判断一下,但这样肯定不对
如下查询的结果会变成:
[15598, com.xx.bean.oracle.VYktCardinfo@40c76f5a, com.xx.bean.oracle.VYktCardinfo@a323a5b, 15598, com.xx.bean.oracle.VYktCardinfo@40c76f5a, com.xx.bean.oracle.VYktCardinfo@a323a5b]

	@Test
	public void testOracle() {
		PageHelper.offsetPage(0, 2);
		List<VYktCardinfo> vYktCardinfos = vYktCardinfoMapper.selectByExample(null);
		PageInfo<VYktCardinfo> pageInfo = new PageInfo<>(vYktCardinfos); //取分页信息
		for (int i = 0; i < pageInfo.getList().size(); i++) {
			if (vYktCardinfos.get(i) instanceof VYktCardinfo) {
				System.out.println(vYktCardinfos.get(i));
			}
		}
	}

这种需求能支持到吗

@abel533
Copy link
Collaborator

abel533 commented Jan 9, 2018

按理说配置多个应该没问题。。

能不能发个执行分页的完整日志(含SQL)。

@jht385
Copy link
Author

jht385 commented Jan 10, 2018

看到你的回复我就又跑了一次@test,惊奇的发现不配置好像可以,因为前面我发现会重复查询,就把加入PageInterceptor到SqlSessionFactoryBean的部分去掉,然后不用PageHelper,今天测试开始就加上了PageHelper.offsetPage(0, 10); 然后跑下面代码能够生效。
然后我把PageInterceptor又加上再跑一次就出现了问题的情况。
测试如下:

	@Test
	public void testOracle() {
		PageHelper.offsetPage(0, 10);
		List<VYktCardinfo> vYktCardinfos = vYktCardinfoMapper.selectByExample(null);
		PageInfo<VYktCardinfo> pageInfo = new PageInfo<>(vYktCardinfos); //取分页信息
		for (int i = 0; i < pageInfo.getList().size(); i++) {
			//			if (vYktCardinfos.get(i) instanceof VYktCardinfo) {
			log.debug(vYktCardinfos.get(i) + "");
			//			}
		}
	}

日志在这里:
https://github.com/jht385/files/tree/master/Mybatis-PageHelper/issue-166

@abel533
Copy link
Collaborator

abel533 commented Jan 10, 2018

你用pagehelper-starter了吗?

直接用starter,配置动态获取数据库类型就能用。

@jht385
Copy link
Author

jht385 commented Jan 11, 2018

具体要配置配置自动切换 dialect啊,需要自己写切面吗?
我用默认配置,单个执行是可以,但是混合两个类型数据源的就不行了,我的业务需要混合用
比如下面Test,必须是运行过程中切换dialect
`
@test
public void testMix() {

PageHelper.offsetPage(0, 2);
List<VYktCardinfo> vYktCardinfos = vYktCardinfoMapper.selectByExample(null);
PageInfo<VYktCardinfo> pageInfo = new PageInfo<>(vYktCardinfos); //取分页信息
for (int i = 0; i < pageInfo.getList().size(); i++) {
	log.debug(vYktCardinfos.get(i) + "");
}
PageHelper.offsetPage(0, 2);
List<SyncOracle> syncOracles = SyncOracleMapper.selectByExample(null);
for (SyncOracle syncOracle : syncOracles) {
	log.debug(syncOracle + "");
}

}`

而自动配置不能配置出两种类型吧,不能这么配啊 pagehelper.helperDialect=oracle,mysql
`
/**
* 接受分页插件额外的属性
*
* @return
*/
@bean
@ConfigurationProperties(prefix = PageHelperProperties.PAGEHELPER_PREFIX)
public Properties pageHelperProperties() {
return new Properties();
}

@PostConstruct
public void addPageInterceptor() {
	PageInterceptor interceptor = new PageInterceptor();
	Properties properties = new Properties();
	//先把一般方式配置的属性放进去
	properties.putAll(pageHelperProperties());
	//在把特殊配置放进去,由于close-conn 利用上面方式时,属性名就是 close-conn 而不是 closeConn,所以需要额外的一步
	properties.putAll(this.properties.getProperties());
	interceptor.setProperties(properties);
	for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
		sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
	}
}`

@xiaomozhang
Copy link

@jht385 配置多数据源code能发我看下吗?

@jht385
Copy link
Author

jht385 commented Jan 12, 2018

@xiaomozhang 我用的是分目录方式(另一种是切面的方式),目录区分mapper目录,配置注入不同DataSource,DataSource在生成对应的SqlSessionFactory->SqlSessionTemplate
DataSourceTransactionManager 事务我只需mysql的,所以只在MysqlDataSourceConfig配了一个
@Configuration @MapperScan(basePackages = "com.bingo.mapper.mysql", sqlSessionTemplateRef = "mysqlSqlSessionTemplate") public class MysqlDataSourceConfig {

`

@bean(name = "mysqlDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql")
@primary
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().type(dataSourceType).build();
}`

然后PageInterceptor在应用启动时就遍历SqlSessionFactory为每个SqlSessionFactory添加上了配置的或默认的,那么不同数据库执行时用同一种类型的PageInterceptor应该是会出错的,你有什么解决办法吗?
我现在这模块用不了分页插件只有自己写sql了

@abel533 abel533 closed this as completed Sep 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants