Spring batch Spring批处理:JdbcPagingItemReader无法通过setSortKeys和强制转换工作(id为未签名)

Spring batch Spring批处理:JdbcPagingItemReader无法通过setSortKeys和强制转换工作(id为未签名),spring-batch,Spring Batch,我正在使用Mysql的SpringBatch版本3.0.7 我遇到的问题是person_reader表的id列定义了varchar的方式,因此对于简单的select排序,会发生以下情况: 它很好用。直到这里一切都好 注意:对于批处理过程,按正确顺序读取数据非常重要 问题在于JdbcPagingItemReader 第一次尝试: 从某种意义上讲,SQL从person\u reader ORDER BY castid生成的SELECT id、first\u name、last\u name作为id

我正在使用Mysql的SpringBatch版本3.0.7

我遇到的问题是person_reader表的id列定义了varchar的方式,因此对于简单的select排序,会发生以下情况:

它很好用。直到这里一切都好

注意:对于批处理过程,按正确顺序读取数据非常重要

问题在于JdbcPagingItemReader

第一次尝试:

从某种意义上讲,SQL从person\u reader ORDER BY castid生成的SELECT id、first\u name、last\u name作为id ASC LIMIT 100的未签名订单是不正确的

第二次尝试

对“缺失”一栏有感觉

Order是枚举,因此无法扩展

正确的方法是什么

阿尔法

如果我在MySQL的工作台中使用以下内容:

从person\u reader ORDER BY sb\u sort\u column ASC中选择id、名字、姓氏、castid作为未签名的sb\u sort\u column 它很好用。如果我使用:

MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column");
pagingQueryProvider.setFromClause("FROM person_reader");

Map<String, Order> sortKeys= new HashMap<>();
sortKeys.put("sb_sort_column", Order.ASCENDING);
pagingQueryProvider.setSortKeys(sortKeys);

itemReader.setQueryProvider(pagingQueryProvider);
从上面仔细查看关于生成的sql语句的第三行

解决方案:

评论中提供的链接很有用。 它来自:

因此,正确的配置是:

    MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
    pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name, sb_sort_column");
    pagingQueryProvider.setFromClause("FROM (SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column FROM person_reader) person_reader");

    Map<String, Order> sortKeys= new HashMap<>();
    sortKeys.put("sb_sort_column", Order.ASCENDING);
    pagingQueryProvider.setSortKeys(sortKeys);
注意:请确保在setSelectClause方法中包含别名列,在这种情况下,sb_sort_列将起作用,因此删除我的重复部分

不幸的是,尽管在功能上是准确的,但在函数上执行orderby可能会运行得非常糟糕,因为它必须扫描整个表才能执行强制转换,而且我认为MySQL还不能让您在函数上创建索引


也就是说,从MySQL 5.7.6开始,您可以将一个虚拟列CASTID添加到表中,作为SORT_ID的无符号,然后对该虚拟列进行索引。

实际情况下,这是您的数据模型的一个问题。是否可以将id列修改为数字?即使可能,也存在不可能的情况,例如旧应用与其他应用一起工作。是否测试了代码?我做了类似的事情,但它不起作用。阅读我自己的答案。你把它放在选择栏,你没有把子选择栏放在表格里。啊,当我起草我的答案时,你没有看到。但是我很困惑。。。你是说你下面的答案有用还是无效?如果它不起作用,新的stacktrace是什么?它起作用了,我要到明天才能检查正确答案,所以限制。我的代码片段包含正确的Java+sql配置。在其他链接中,只需介绍sql部分即可。。。我删除了答案的重复部分,只留下与缓解性能问题相关的部分。对于一个小表来说,这不是一个问题,但是如果您有一个最新的MySQL版本和一个相当大的数据量,那么可能值得添加这个虚拟列和索引。
setSql("SELECT id, first_name, last_name FROM person_reader ORDER BY cast(id as unsigned)");
    JdbcPagingItemReader<Person> itemReader = new JdbcPagingItemReader<>();
    itemReader.setDataSource(dataSource);
    itemReader.setPageSize(100);
    itemReader.setRowMapper(new PersonRowMapper());

    MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
    pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name");
    pagingQueryProvider.setFromClause("FROM person_reader ORDER BY cast(id as unsigned)");

    Map<String, Order> sortKeys= new HashMap<>();
    sortKeys.put("id", Order.ASCENDING);
    pagingQueryProvider.setSortKeys(sortKeys);

    itemReader.setQueryProvider(pagingQueryProvider); 
org.springframework.jdbc.BadSqlGrammarException: StatementCallback;
bad SQL grammar [SELECT id, first_name, last_name FROM person_reader ORDER BY cast(id as unsigned) ORDER BY id ASC LIMIT 100];
nested exception is java.sql.SQLSyntaxErrorException:
You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY id ASC LIMIT 100' at line 1
    JdbcPagingItemReader<Person> itemReader = new JdbcPagingItemReader<>();
    itemReader.setDataSource(dataSource);
    itemReader.setPageSize(100);
    itemReader.setRowMapper(new PersonRowMapper());

    MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
    pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name");
    pagingQueryProvider.setFromClause("FROM person_reader");

    Map<String, Order> sortKeys= new HashMap<>();
    sortKeys.put("cast(id as unsigned)", Order.ASCENDING);
    pagingQueryProvider.setSortKeys(sortKeys);

    itemReader.setQueryProvider(pagingQueryProvider);
org.springframework.jdbc.UncategorizedSQLException: StatementCallback;
uncategorized SQLException for SQL [SELECT id, first_name, last_name FROM person_reader ORDER BY cast(id as unsigned) ASC LIMIT 100];
SQL state [S0022]; error code [0]; Column 'cast(id as unsigned)' not found.;
nested exception is java.sql.SQLException: Column 'cast(id as unsigned)' not found.
MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column");
pagingQueryProvider.setFromClause("FROM person_reader");

Map<String, Order> sortKeys= new HashMap<>();
sortKeys.put("sb_sort_column", Order.ASCENDING);
pagingQueryProvider.setSortKeys(sortKeys);

itemReader.setQueryProvider(pagingQueryProvider);
org.springframework.jdbc.BadSqlGrammarException: 
PreparedStatementCallback; 
bad SQL grammar [SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column FROM person_reader WHERE ((sb_sort_column > ?)) ORDER BY sb_sort_column ASC LIMIT 100]; 
nested exception is java.sql.SQLSyntaxErrorException: 
Unknown column 'sb_sort_column' in 'where clause'
    MySqlPagingQueryProvider pagingQueryProvider = new MySqlPagingQueryProvider();
    pagingQueryProvider.setSelectClause("SELECT id, first_name, last_name, sb_sort_column");
    pagingQueryProvider.setFromClause("FROM (SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column FROM person_reader) person_reader");

    Map<String, Order> sortKeys= new HashMap<>();
    sortKeys.put("sb_sort_column", Order.ASCENDING);
    pagingQueryProvider.setSortKeys(sortKeys);