我正在使用Spring Batch
3.0.7
版本Mysql
我遇到的问题是person_reader
表的id
列定义了varchar
,因此对于简单的select
有序会发生以下情况>:
id
--
1
10 <--- !!!
2
3
...
需要什么
id
--
1
2
3
...
10 <--- ok!
...
解决方案使用ORDER BY cast(id as unsigned)
如果我使用JdbcCursorItemReader
,我可以安心使用:
setSql("SELECT id, first_name, last_name FROM person_reader ORDER BY cast(id as unsigned)");
工作正常。直到这里一切都还可以。
注意:对于批处理过程,非常重要的是以正确的顺序读取数据。
问题在于JdbcPagingItemReader
首先尝试:
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);
观察:
setFromClause("FROM person_reader ORDER BY cast(id as unsigned)")
put("id", Order.ASCENDING)
出现以下错误:
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
有道理,SQL
生成的SELECT id, first_name, last_name FROM person_reader ORDER BY cast(id as unsigned) ORDER BY id ASC LIMIT 100
不正确。
第二次尝试
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);
观察:
setFromClause("FROM person_reader")
put("cast(id as unsigned)", Order.ASCENDING)
出现以下错误:
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.
对失踪&#39;感到失望。柱
Order
是enum
,因此无法延期。
什么是正确的方法?
α
如果我在MySQL
的工作台中使用以下内容:
SELECT id, first_name, last_name, cast(id as unsigned) as sb_sort_column FROM person_reader ORDER BY sb_sort_column ASC
工作正常。如果我使用:
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'
从上面仔细查看关于生成的sql
语句的第3行。
答案 0 :(得分:1)
Manuel's earlier answer会有效,所以删除我的重复部分......
不幸的是,尽管功能上准确,但在函数上执行ORDER BY
可能会运行得很差,因为它必须扫描整个表来执行cast
,我不相信MySQL允许你在函数上创建一个索引。
也就是说,从MySQL 5.7.6开始,您可以向表中添加一个虚拟列CAST(ID as UNSIGNED) as SORT_ID
,然后索引虚拟列。
答案 1 :(得分:0)
<强>解决方案强>:
评论中提供的链接很有用。 来自:
因此正确的配置是:
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_column