Spring Batch Paging พร้อม sortKeys และค่าพารามิเตอร์

ฉันมีโปรเจ็กต์ Spring Batch ที่ทำงานใน Spring Boot ซึ่งทำงานได้อย่างสมบูรณ์แบบ สำหรับผู้อ่านของฉัน ฉันกำลังใช้ JdbcPagingItemReader กับ 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
}

อย่างไรก็ตาม เมื่อฉันแก้ไขแบบสอบถามด้วยพารามิเตอร์ที่มีชื่อบางตัวเพื่อแทนที่ค่าวันที่ที่ฮาร์ดโค้ดก่อนหน้านี้ และตั้งค่าพารามิเตอร์เหล่านี้บนเครื่องอ่านดังที่แสดงด้านบน ฉันได้รับข้อยกเว้นต่อไปนี้ในหน้า ที่สอง ที่อ่าน (หน้าแรก หน้าทำงานได้ดีเนื่องจากพารามิเตอร์ _id ไม่ได้ถูกใช้โดยผู้ให้บริการค้นหาเพจ):

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)

นี่คือตัวอย่างของ SQL ซึ่งไม่มีส่วนคำสั่ง WHERE ตามค่าเริ่มต้น จะมีการสร้างขึ้นโดยอัตโนมัติเมื่อมีการอ่านหน้าที่สอง:

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

ในหน้าสอง sql ได้รับการแก้ไขดังต่อไปนี้ แต่ดูเหมือนว่าพารามิเตอร์ที่มีชื่อสำหรับ _id ไม่ได้รับการระบุ:

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

ฉันสงสัยว่าฉันไม่สามารถใช้คีย์การเรียงลำดับ MySqlPagingQueryProvider ร่วมกับพารามิเตอร์ที่มีชื่อเพิ่มเติมที่ตั้งค่าใน JdbcPagingItemReader ได้ ถ้าไม่ ทางเลือกที่ดีที่สุดในการแก้ปัญหานี้คืออะไร? ฉันจำเป็นต้องสามารถระบุพารามิเตอร์ให้กับแบบสอบถามและเพจได้ (เทียบกับการใช้เคอร์เซอร์) ขอบคุณ!


person th3morg    schedule 20.11.2014    source แหล่งที่มา
comment
ดูเหมือนว่าคุณไม่ได้ตั้งค่าตำแหน่งส่วนคำสั่งสำหรับค่าใหม่ของคุณ นั่นหายไปจากตัวอย่างการกำหนดค่าของคุณใช่ไหม   -  person Michael Minella    schedule 21.11.2014
comment
@MichaelMinella ขอบคุณสำหรับความช่วยเหลือของคุณ ฉันให้ SQL บางส่วนไว้ข้างต้น ไม่มีส่วนคำสั่ง WHERE ในการสืบค้นเริ่มต้นของฉัน อย่างไรก็ตาม ผู้ให้บริการเพจจะเพิ่มส่วนคำสั่งหลังหน้าแรกโดยอัตโนมัติ   -  person th3morg    schedule 21.11.2014
comment
ฉันหมายความว่าเมื่อคุณกำหนดค่าผู้ให้บริการของคุณ คุณไม่ได้ตั้งค่าส่วนคำสั่ง Where สำหรับ startDate และ endDate หรือฉันพลาดอะไรไปหรือเปล่า   -  person Michael Minella    schedule 21.11.2014
comment
@MichaelMinella โปรดทราบว่าสิ่งเหล่านั้นไม่ได้ใช้ในส่วนคำสั่ง แต่ใช้ในส่วนที่เลือกย่อย คุณคิดว่าด้วยเหตุผลบางอย่างที่จะทำให้เกิดปัญหาที่ฉันมีกับฟิลด์ _id หรือไม่ ฉันรู้ว่าฉันสามารถเปลี่ยนแปลงสิ่งนั้นเป็นการเข้าร่วมแทนการเลือกย่อยและใช้คำสั่งย่อยได้ แต่ฉันมีตัวเลือกย่อยเพิ่มเติมมากมายที่ไม่สามารถทำให้เป็นการรวมที่ฉันลบออกเพื่อพยายามลดความสับสน แบบสอบถามได้รับการทดสอบและใช้งานได้ อย่างที่ฉันบอกไปแล้ว หน้าที่ 1 ทำงานได้ดี จนกระทั่งหน้าที่ 2 ซึ่งส่วนคำสั่ง WHERE จะถูกเพิ่มโดยอัตโนมัติ พารามิเตอร์ _id ที่มีชื่อจะไม่ถูกผูกไว้ ขอขอบคุณอีกครั้ง!   -  person th3morg    schedule 21.11.2014
comment
ดูที่ source และวิธีการทำงานของฟังก์ชัน getParameterMap ซึ่งดูเหมือนว่าจะครอบคลุมอย่างแน่นอน มีโอกาสใดบ้างที่คุณสามารถเปิดการบันทึกและดูว่าผลลัพธ์ใดสำหรับการใช้ parameterMap   -  person David Coutu    schedule 21.11.2014
comment
th3morg คุณช่วยรวบรวมกรณีทดสอบง่ายๆ แล้วโยนมันลงบน git ได้ไหม?   -  person Michael Minella    schedule 21.11.2014
comment
ขอบคุณพวกคุณที่พยายามช่วย! ฉันคิดว่าปัญหานี้ค่อนข้างคลุมเครือและวินิจฉัยได้ยากหากไม่มีชิ้นส่วนทั้งหมด ซึ่งฉันต้องขออภัยด้วย ฉันขอขอบคุณที่สละเวลา ขอบคุณอีกครั้ง!   -  person th3morg    schedule 21.11.2014


คำตอบ (2)


ฉันแก้ไขปัญหานี้ด้วยการดีบักอย่างเข้มข้น ปรากฎว่า MySqlPagingQueryProvider ใช้วิธีการ getSortKeysWithoutAliases() เมื่อสร้างแบบสอบถาม SQL เพื่อเรียกใช้สำหรับหน้าแรกและหน้าถัดไป ดังนั้นจึงต่อท้าย and (p.id > :_id) แทนที่จะเป็น and (p.id > :_p.id) ในภายหลัง เมื่อมีการสร้างค่าการเรียงลำดับเพจที่สองและจัดเก็บไว้ในฟิลด์ startAfterValues ของ JdbcPagingItemReader ค่านั้นจะใช้สตริง "p.id" ดั้งเดิมที่ระบุ และท้ายที่สุดจะใส่ลงในพารามิเตอร์ที่มีชื่อซึ่งแมปคู่ ("_p.id",10) อย่างไรก็ตาม เมื่อผู้อ่านพยายามกรอก _id ในแบบสอบถาม จะไม่มีอยู่เนื่องจากผู้อ่านใช้คีย์ที่ถูกลบที่ไม่ใช่นามแฝง

เรื่องสั้นสั้น ฉันต้องลบการอ้างอิงนามแฝงออกเมื่อกำหนดคีย์การเรียงลำดับ

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

ต้องเปลี่ยนเพื่อให้ทุกอย่างทำงานร่วมกันได้ดี

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

person th3morg    schedule 21.11.2014

ฉันมีปัญหาเดียวกันและได้รับวิธีแก้ไขปัญหาอื่นที่เป็นไปได้

ตารางของฉัน T มีฟิลด์คีย์หลัก INTERNAL_ID

แบบสอบถามใน JdbcPagingItemReader เป็นดังนี้:

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

ดังนั้น สิ่งสำคัญคือ: ในบางเงื่อนไข ข้อความค้นหา ไม่ส่งคืนผลลัพธ์ จากนั้นทำให้เกิดข้อผิดพลาดด้านบน ไม่มีการระบุค่าสำหรับ...

วิธีแก้ไขคือ:

  • ตรวจสอบองค์ประกอบ decider ของ Spring Batch หากมีแถวอยู่
  • หากเป็นเช่นนั้น ให้ดำเนินการต่อด้วย chunk: reader-processor-writer
  • มันไม่ใช่ ให้ไปที่ขั้นตอนอื่น

โปรดทราบว่านี่เป็นสองสถานการณ์ที่แตกต่างกัน:

  • ในตอนต้นจะมีแถวๆ คุณได้รับมันโดยการเพจและสุดท้ายก็ไม่มีแถวอีกต่อไป ไม่มีปัญหาและไม่จำเป็นต้องใช้เคล็ดลับการตัดสินใจ
  • ในตอนแรกไม่มีแถว จากนั้นข้อผิดพลาดนี้ก็ได้เกิดขึ้น และผู้ตัดสินก็แก้ไขมัน

หวังว่านี่จะช่วยได้

person yaki_nuka    schedule 16.02.2016