Spring Batch Paging dengan sortKeys dan nilai parameter

Saya memiliki proyek Spring Batch yang berjalan di Spring Boot yang berfungsi dengan baik. Untuk pembaca saya, saya menggunakan JdbcPagingItemReader dengan MySqlPagingQueryProvider.

@Bean
public ItemReader<Person> reader(DataSource dataSource) {
    MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider()
    provider.setSelectClause(ScoringConstants.SCORING_SELECT_STATEMENT)
    provider.setFromClause(ScoringConstants.SCORING_FROM_CLAUSE)
    provider.setSortKeys("p.id": Order.ASCENDING)

    JdbcPagingItemReader<Person> reader = new JdbcPagingItemReader<Person>()
    reader.setRowMapper(new PersonRowMapper())
    reader.setDataSource(dataSource)
    reader.setQueryProvider(provider)
    //Setting these caused the exception
    reader.setParameterValues(
        startDate: new Date() - 31,
        endDate: new Date()
    ) 
    reader.afterPropertiesSet()
    return reader
}

Namun, ketika saya memodifikasi kueri saya dengan beberapa parameter bernama untuk menggantikan nilai tanggal yang dikodekan sebelumnya dan menetapkan nilai parameter ini pada pembaca seperti yang ditunjukkan di atas, saya mendapatkan pengecualian berikut pada halaman kedua yang dibaca (yang pertama halaman berfungsi dengan baik karena parameter _id belum digunakan oleh penyedia kueri paging):

org.springframework.dao.InvalidDataAccessApiUsageException: No value supplied for the SQL parameter '_id': No value registered for key '_id'
at org.springframework.jdbc.core.namedparam.NamedParameterUtils.buildValueArray(NamedParameterUtils.java:336)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.getPreparedStatementCreator(NamedParameterJdbcTemplate.java:374)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:192)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:199)
at org.springframework.batch.item.database.JdbcPagingItemReader.doReadPage(JdbcPagingItemReader.java:218)
at org.springframework.batch.item.database.AbstractPagingItemReader.doRead(AbstractPagingItemReader.java:108)

Berikut adalah contoh SQL, yang tidak memiliki klausa WHERE secara default. Seseorang dibuat secara otomatis ketika halaman kedua dibaca:

select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id)  from person p

Pada halaman kedua, sql diubah menjadi berikut, namun tampaknya parameter bernama untuk _id tidak diberikan:

select *, (select id from family f where date_created between :startDate and :endDate and f.creator_id = p.id) from person p WHERE id > :_id

Saya ingin tahu apakah saya tidak bisa menggunakan kunci pengurutan MySqlPagingQueryProvider bersama dengan parameter bernama tambahan yang disetel di JdbcPagingItemReader. Jika tidak, apa alternatif terbaik untuk mengatasi masalah ini? Saya harus dapat memberikan parameter ke kueri dan juga halamannya (vs. menggunakan kursor). Terima kasih!


person th3morg    schedule 20.11.2014    source sumber
comment
Anda sepertinya tidak menyetel klausa Where untuk nilai baru Anda. Apakah itu hilang dari contoh konfigurasi Anda?   -  person Michael Minella    schedule 21.11.2014
comment
@MichaelMinella Terima kasih atas bantuan Anda. Saya memberikan beberapa SQL di atas. Tidak ada klausa WHERE dalam kueri awal saya, namun penyedia paging secara otomatis menambahkan satu klausa setelah halaman pertama.   -  person th3morg    schedule 21.11.2014
comment
Maksud saya, saat Anda mengonfigurasi penyedia, Anda tidak menyetel klausa tempat untuk tanggal mulai dan tanggal akhir, atau apakah saya melewatkan sesuatu?   -  person Michael Minella    schedule 21.11.2014
comment
@MichaelMinella, perhatikan bahwa itu tidak digunakan dalam klausa Where, melainkan dalam subpilihan. Apakah menurut Anda karena alasan tertentu hal itu akan menyebabkan masalah yang saya alami dengan bidang _id? Saya menyadari bahwa saya dapat mengubahnya menjadi gabungan alih-alih subpilihan dan menggunakan klausa tempat, tetapi saya memiliki banyak subpilihan tambahan yang tidak dapat dijadikan gabungan yang telah saya hapus demi mencoba mengurangi kebingungan. Kueri telah diuji dan berfungsi. Seperti yang saya katakan, halaman 1 berfungsi dengan baik dan baru pada halaman 2 klausa WHERE ditambahkan secara otomatis, param bernama _id tidak terikat. Terima kasih lagi!   -  person th3morg    schedule 21.11.2014
comment
Melihat sumber dan cara kerja fungsi getParameterMap sepertinya menutupinya. Adakah kemungkinan Anda dapat mengaktifkan logging dan melihat keluaran apa yang dihasilkan untuk Menggunakan parameterMap?   -  person David Coutu    schedule 21.11.2014
comment
th3morg, bisakah Anda membuat test case sederhana dan melemparkannya ke git?   -  person Michael Minella    schedule 21.11.2014
comment
Terima kasih teman-teman telah mencoba membantu! Saya rasa masalah ini agak tidak jelas dan sulit didiagnosis tanpa mengetahui semua bagiannya, dan saya minta maaf. Saya menghargai waktu yang diambil. Terima kasih lagi!   -  person th3morg    schedule 21.11.2014


Jawaban (2)


Saya memecahkan masalah ini dengan beberapa debugging yang intens. Ternyata MySqlPagingQueryProvider menggunakan metode getSortKeysWithoutAliases() ketika membangun kueri SQL untuk dijalankan pada halaman pertama dan halaman berikutnya. Oleh karena itu, ia menambahkan and (p.id > :_id), bukan and (p.id > :_p.id). Nanti, ketika nilai pengurutan halaman kedua dibuat dan disimpan di bidang startAfterValues JdbcPagingItemReader, ia akan menggunakan String "p.id" asli yang ditentukan dan akhirnya dimasukkan ke dalam peta parameter bernama pasangan ("_p.id",10). Namun ketika pembaca mencoba mengisi _id pada query, tidak ada karena pembaca menggunakan kunci non-alias yang dihapus.

Singkat cerita, saya harus menghapus referensi alias saat menentukan kunci pengurutan saya.

provider.setSortKeys("p.id": Order.ASCENDING)

harus berubah agar semuanya dapat bekerja sama dengan baik

provider.setSortKeys("id": Order.ASCENDING)

person th3morg    schedule 21.11.2014

Saya memiliki masalah yang sama dan mendapatkan solusi lain yang mungkin.

Tabel T saya memiliki bidang kunci utama INTERNAL_ID.

Kueri di JdbcPagingItemReader seperti ini:

SELECT INTERNAL_ID, ... FROM T WHERE ... ORDER BY INTERNAL_ID ASC

Jadi, kuncinya adalah: dalam beberapa kondisi, kueri tidak memberikan hasil, dan kemudian, memunculkan kesalahan di atas Tidak ada nilai yang diberikan untuk...

Solusinya adalah:

  • Periksa elemen decider Spring Batch apakah ada baris.
  • Jika ya, lanjutkan dengan chunk: reader-processor-writer.
  • Jika tidak, lanjutkan ke langkah lain.

Harap dicatat bahwa ini adalah dua skenario yang berbeda:

  • Pada awalnya, ada baris. Anda mendapatkannya dengan melakukan paging dan akhirnya, tidak ada baris lagi. Ini tidak ada masalah dan trik penentu tidak diperlukan.
  • Pada awalnya, tidak ada baris. Kemudian, kesalahan ini muncul, dan pengambil keputusan menyelesaikannya.

Semoga ini membantu.

person yaki_nuka    schedule 16.02.2016