ใน Hibernate 3 มีวิธีทำข้อ จำกัด MySQL ต่อไปนี้ใน HQL หรือไม่?
select * from a_table order by a_table_column desc limit 0, 20;
ฉันไม่ต้องการใช้ setMaxResults ถ้าเป็นไปได้ สิ่งนี้เป็นไปได้แน่นอนใน Hibernate / HQL รุ่นเก่า แต่ดูเหมือนว่าจะหายไป
ใน Hibernate 3 มีวิธีทำข้อ จำกัด MySQL ต่อไปนี้ใน HQL หรือไม่?
select * from a_table order by a_table_column desc limit 0, 20;
ฉันไม่ต้องการใช้ setMaxResults ถ้าเป็นไปได้ สิ่งนี้เป็นไปได้แน่นอนใน Hibernate / HQL รุ่นเก่า แต่ดูเหมือนว่าจะหายไป
คำตอบ:
สิ่งนี้ถูกโพสต์บนฟอรัมไฮเบอร์เนตเมื่อไม่กี่ปีก่อนเมื่อถูกถามเกี่ยวกับสาเหตุที่ทำงานใน Hibernate 2 แต่ไม่ได้อยู่ใน Hibernate 3:
ข้อ จำกัดไม่เคยเป็นประโยคที่สนับสนุนใน HQL คุณตั้งใจจะใช้ setMaxResults ()
ดังนั้นถ้ามันทำงานในไฮเบอร์เนต 2 ดูเหมือนว่าเป็นเรื่องบังเอิญมากกว่าการออกแบบ ฉันคิดว่าเป็นเพราะตัวแยกวิเคราะห์ Hibernate 2 HQL จะแทนที่บิตของแบบสอบถามที่ได้รับการยอมรับว่าเป็น HQL และออกจากที่เหลือตามเดิมดังนั้นคุณสามารถแอบเข้าไปใน SQL ดั้งเดิมบางตัวได้ Hibernate 3 มีตัวแยกวิเคราะห์ AST HQL ที่เหมาะสมและมีการให้อภัยน้อยกว่ามาก
ฉันคิดว่าQuery.setMaxResults()
เป็นตัวเลือกเดียวของคุณ
setMaxResults
ซึ่งจะ จำกัด จำนวนแถวผลลัพธ์จาก resultset และแสดงให้ผู้ใช้เห็นในกรณีของฉันฉันมี 3 ล้านระเบียนซึ่งถูกสอบถามแล้วเรียก setMaxResults เพื่อตั้งค่า 50 บันทึก แต่ฉันไม่ต้องการที่จะทำในขณะที่แบบสอบถามเองฉันต้องการสอบถาม 50 บันทึกมีวิธีการทำเช่นนั้น?
setMaxResults
Hibernate จะผนวกlimit
ส่วนหนึ่งของแบบสอบถาม มันจะไม่ได้รับผลลัพธ์ทั้งหมด คุณสามารถตรวจสอบแบบสอบถามที่สร้างโดยเปิดใช้งาน:<property name="show_sql">true</property>
// SQL: SELECT * FROM table LIMIT start, maxRows;
Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);
setFirstResult
ถูกกล่าวถึงในคำตอบนี้จริง ๆ ในขณะที่ที่นี่และที่อื่น ๆ พวกเขาแค่พูดแบบsetMaxResults
นี้และsetMaxResults
โดยไม่ต้องพูดถึงวิธีตั้งค่าออฟเซ็ต
หากคุณไม่ต้องการใช้setMaxResults()
กับQuery
วัตถุคุณสามารถเปลี่ยนกลับไปใช้ SQL ปกติได้ตลอดเวลา
หากคุณไม่ต้องการใช้ setMaxResults คุณสามารถใช้ Query.scroll แทนรายการและดึงข้อมูลแถวที่คุณต้องการ มีประโยชน์สำหรับการเพจเช่น
setMaxResults()
โหลดครั้งแรกทุกระเบียนในหน่วยความจำแล้วสร้างรายการย่อยซึ่งเมื่อมีหลายแสนบันทึกหรือมากกว่าเกิดปัญหาเซิร์ฟเวอร์เพราะหน่วยความจำไม่เพียงพอ อย่างไรก็ตามฉันสามารถเปลี่ยนจากเคียวรีที่พิมพ์ JPA ไปเป็นเคียวรีไฮเบอร์เนตได้QueryImpl hibernateQuery = query.unwrap(QueryImpl.class)
จากนั้นฉันก็สามารถใช้scroll()
วิธีการตามที่คุณแนะนำ
คุณสามารถใช้เลขหน้าสำหรับเรื่องนี้ได้อย่างง่ายดาย
@QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value = "true") })
@Query("select * from a_table order by a_table_column desc")
List<String> getStringValue(Pageable pageable);
คุณต้องผ่านnew PageRequest(0, 1)
การดึงข้อมูลระเบียนและจากรายการเรียกระเบียนแรก
เนื่องจากนี่เป็นคำถามที่พบบ่อยมากฉันจึงเขียน บทความนี้ขึ้นอยู่กับคำตอบนี้
setFirstResult
และsetMaxResults
Query
วิธีการสำหรับ JPA และ Hibernate Query
ที่setFirstResult
เป็นวิธีการที่เทียบเท่าOFFSET
และsetMaxResults
วิธีการที่จะเทียบเท่ากับการ จำกัด :
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
LimitHandler
เป็นนามธรรมไฮเบอร์เนตLimitHandler
กำหนดตรรกะการแบ่งหน้าเฉพาะฐานข้อมูลและตามที่แสดงโดยแผนภาพต่อไปนี้ไฮเบอร์เนตรองรับตัวเลือกการแบ่งหน้าเฉพาะฐานข้อมูลจำนวนมาก:
ตอนนี้ขึ้นอยู่กับระบบฐานข้อมูลเชิงสัมพันธ์ที่คุณใช้แบบสอบถาม JPQL ด้านบนจะใช้ไวยากรณ์การแบ่งหน้าที่เหมาะสม
SELECT p.id AS id1_0_,
p.created_on AS created_2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?, ?
SELECT p.id AS id1_0_,
p.created_on AS created_2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
SELECT p.id AS id1_0_,
p.created_on AS created_on2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
OFFSET ? ROWS
FETCH NEXT ? ROWS ONLY
SELECT *
FROM (
SELECT
row_.*, rownum rownum_
FROM (
SELECT
p.id AS id1_0_,
p.created_on AS created_on2_0_,
p.title AS title3_0_
FROM post p
ORDER BY p.created_on
) row_
WHERE rownum <= ?
)
WHERE rownum_ > ?
ข้อดีของการใช้setFirstResult
และsetMaxResults
คือไฮเบอร์เนตสามารถสร้างไวยากรณ์การแบ่งหน้าเฉพาะฐานข้อมูลสำหรับฐานข้อมูลเชิงสัมพันธ์ที่รองรับ
และคุณไม่ จำกัด เฉพาะการสืบค้น JPQL เท่านั้น คุณสามารถใช้setFirstResult
และsetMaxResults
วิธีที่เจ็ดสำหรับการสืบค้น SQL ดั้งเดิม
คุณไม่จำเป็นต้อง hardcode การแบ่งหน้าเฉพาะฐานข้อมูลเมื่อใช้แบบสอบถาม SQL ดั้งเดิม ไฮเบอร์เนตสามารถเพิ่มลงในแบบสอบถามของคุณ
ดังนั้นหากคุณกำลังดำเนินการค้นหา SQL นี้ใน PostgreSQL:
List<Tuple> posts = entityManager
.createNativeQuery(
"SELECT " +
" p.id AS id, " +
" p.title AS title " +
"from post p " +
"ORDER BY p.created_on", Tuple.class)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
ไฮเบอร์เนตจะแปลงดังนี้:
SELECT p.id AS id,
p.title AS title
FROM post p
ORDER BY p.created_on
LIMIT ?
OFFSET ?
เจ๋งใช่มั้ย
การแบ่งหน้าเป็นสิ่งที่ดีเมื่อคุณสามารถจัดทำดัชนีการกรองและเกณฑ์การเรียงลำดับ หากความต้องการการแบ่งหน้าของคุณบ่งบอกถึงการกรองแบบไดนามิกมันเป็นวิธีที่ดีกว่ามากในการใช้โซลูชันดัชนีกลับหัวเช่น ElasticSearch
ตรวจสอบบทความนี้สำหรับรายละเอียดเพิ่มเติม
String hql = "select userName from AccountInfo order by points desc 5";
สิ่งนี้ใช้ได้กับฉันโดยไม่ต้องใช้ setmaxResults();
เพียงแค่ให้ค่าสูงสุดในช่วง (ในกรณีนี้ 5) limit
โดยไม่ต้องใช้คำว่า : P
การสังเกตของฉันคือแม้ว่าคุณจะมีข้อ จำกัด ใน HQL (hibernate 3.x) มันจะทำให้เกิดข้อผิดพลาดในการแยกวิเคราะห์หรือไม่สนใจ (หากคุณมีการสั่งซื้อโดย + desc / asc ก่อนถึงขีด จำกัด มันจะถูกละเว้นหากคุณไม่มี desc / asc ก่อนถึงขีด จำกัด มันจะทำให้เกิดข้อผิดพลาดในการแยกวิเคราะห์)
หากสามารถจัดการขีด จำกัด ในโหมดนี้
public List<ExampleModel> listExampleModel() {
return listExampleModel(null, null);
}
public List<ExampleModel> listExampleModel(Integer first, Integer count) {
Query tmp = getSession().createQuery("from ExampleModel");
if (first != null)
tmp.setFirstResult(first);
if (count != null)
tmp.setMaxResults(count);
return (List<ExampleModel>)tmp.list();
}
นี่เป็นรหัสที่ง่ายมากในการจัดการขีด จำกัด หรือรายการ
Criteria criteria=curdSession.createCriteria(DTOCLASS.class).addOrder(Order.desc("feild_name"));
criteria.setMaxResults(3);
List<DTOCLASS> users = (List<DTOCLASS>) criteria.list();
for (DTOCLASS user : users) {
System.out.println(user.getStart());
}
คุณต้องเขียนแบบสอบถามพื้นเมืองหมายนี้
@Query(value =
"SELECT * FROM user_metric UM WHERE UM.user_id = :userId AND UM.metric_id = :metricId LIMIT :limit", nativeQuery = true)
List<UserMetricValue> findTopNByUserIdAndMetricId(
@Param("userId") String userId, @Param("metricId") Long metricId,
@Param("limit") int limit);
คุณสามารถใช้แบบสอบถามด้านล่าง
NativeQuery<Object[]> query = session.createNativeQuery(select * from employee limit ?)
query.setparameter(1,1);
ตัวอย่างด้านล่างนี้ใช้เพื่อดำเนินการค้นหาแบบ จำกัด โดยใช้ HQL
Query query = session.createQuery("....");
query.setFirstResult(startPosition);
query.setMaxResults(maxRows);
คุณสามารถรับใบสมัครสาธิตได้ที่ลิงค์นี้
@Query(nativeQuery = true,
value = "select from otp u where u.email =:email order by u.dateTime desc limit 1")
public List<otp> findOtp(@Param("email") String email);
Hibernate-5.0.12
ฉันใช้ ยังไม่พร้อมใช้งานหรือไม่ มันจะหนักมากที่จะได้รับหนึ่งล้านแผ่นเสียงจากนั้นจึงใช้ตัวกรองกับมันsetMaxResults
มากกว่าที่สังเกตโดย @Rachel ในคำตอบของ @skaffman