Hibernate联盟的替代品
我必须使用Hibernate来实现联合查询吗? 我知道hibernate目前不支持联合查询,现在我看到联合的唯一方法是使用查看表。
另一个select是使用普通的jdbc,但是这样我就会失去所有的示例/条件查询的好处,以及hibernate针对表/列执行的hibernate映射validation。
使用VIEW。 相同的类可以使用实体名称映射到不同的表/视图,所以你甚至不会有太多的重复。 在那里,做到了,行得通。
普通的JDBC有另一个隐藏的问题:它不知道Hibernate会话caching,所以如果事务被caching到事务结束而不从Hibernate会话刷新,JDBC查询将无法find它。 有时可能会非常困惑。
你可以使用id in (select id from ...) or id in (select id from ...)
例如,而不是非工作
from Person p where p.name="Joe" union from Person p join p.children c where c.name="Joe"
你可以做
from Person p where p.id in (select p1.id from Person p1 where p1.name="Joe") or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");
至less在使用MySQL的时候,你以后会遇到性能问题。 相反,在两个查询中执行一个穷人的连接有时会更容易:
// use set for uniqueness Set<Person> people = new HashSet<Person>((List<Person>) query1.list()); people.addAll((List<Person>) query2.list()); return new ArrayList<Person>(people);
做两个简单的查询往往比一个复杂的查询更好。
编辑:
举个例子,下面是从subselect解决scheme得到的MySQL查询的EXPLAIN输出:
mysql> explain select p.* from PERSON p where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") or p.id in (select p2.id from PERSON p2 join CHILDREN c on p2.id = c.parent where c.name="Joe") \G *************************** 1. row *************************** id: 1 select_type: PRIMARY table: a type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 247554 Extra: Using where *************************** 2. row *************************** id: 3 select_type: DEPENDENT SUBQUERY table: NULL type: NULL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: NULL Extra: Impossible WHERE noticed after reading const tables *************************** 3. row *************************** id: 2 select_type: DEPENDENT SUBQUERY table: a1 type: unique_subquery possible_keys: PRIMARY,name,sortname key: PRIMARY key_len: 4 ref: func rows: 1 Extra: Using where 3 rows in set (0.00 sec)
最重要的是1.行不使用任何索引,并考虑200k +行。 坏! 这个查询的执行时间都是0.7s,这两个子查询都在几毫秒之内。
我不得不同意弗拉基米尔。 我也研究了在HQL中使用UNION,并找不到解决办法。 奇怪的是,我可以发现(在Hibernate常见问题解答中)UNION不受支持,与UNION标记为“固定”的错误报告,人们的新闻组称这些报表将在UNION中截断,而其他报告新闻组的人员罚款…经过一天的磨合,我最终将我的HQL移植回普通的SQL,但是在数据库中的View中执行它将是一个不错的select。 在我的情况下,部分查询是dynamic生成的,所以我不得不在代码中构buildSQL。
我有一个关键场景的解决scheme(我为此苦苦挣扎了很多),在HQL中使用union。
例如,而不是不工作: –
select i , j from A a , (select i , j from B union select i , j from C) d where ai = di
要么
select i , j from A a JOIN (select i , j from B union select i , j from C) d on ai = di
你可以在Hibernate HQL – >中做
Query q1 =session.createQuery(select i , j from A a JOIN B b on ai = bi) List l1 = q1.list(); Query q2 = session.createQuery(select i , j from A a JOIN C b on ai = bi) List l2 = q2.list();
那么你可以添加列表 – >
l1.addAll(l2);
视图是一个更好的方法,但由于hql通常返回一个List或Set …你可以做list_1.addAll(list_2)。 与一个工会相比完全不好,但应该工作。
也许我有一个更直接的问题来解决。 我的“例如”在JPA与Hibernate作为JPA的提供者。
我将三个select(第二个情况下是两个)分成多个select,并将自己收集的select合并,有效地取代了“全部联合”。
我也经历过这种痛苦 – 如果查询是dynamic生成的(例如Hibernate Criteria),那么我找不到一个实际的方法来做到这一点。
对我来说好消息是,我只是在调查工会在Oracle数据库中使用“或”时解决性能问题。
帕特里克所发布的解决scheme(使用集合以编程方式结合结果)虽然丑陋(尤其是因为我也想做结果分页),这对我来说已经足够了。
正如帕特里克所说,从每个SELECT附加列表将是一个好主意,但请记住它的行为像UNION ALL 。 为了避免这种副作用,只需要控制对象是否已经添加到最终的集合中。 如果不是,则添加它。
还有一些你应该关心的是,如果你在每个SELECT中有JOIN ,结果将会是一个对象数组( List<Objetc[]>
)的列表,所以你必须迭代它才保留你需要的对象。
希望它的作品。
这是一个特例,但可能会激励你创造你自己的工作。 这里的目标是计算logging符合特定标准的两个不同表中的logging总数。 我相信这种技术适用于任何需要汇总多个表格/数据源中的数据的情况。
我有一些特殊的中间类设置,所以调用命名查询的代码是简短而又甜蜜的,但是您可以使用通常与命名查询结合使用的任何方法来执行查询。
QueryParms parms=new QueryParms(); parms.put("PROCDATE",PROCDATE); Long pixelAll = ((SourceCount)Fetch.row("PIXEL_ALL",parms,logger)).getCOUNT();
正如你在这里看到的那样,这个命名查询开始像一个union声明看起来很像:
@Entity @NamedQueries({ @NamedQuery( name ="PIXEL_ALL", query = "" + " SELECT new SourceCount(" + " (select count(a) from PIXEL_LOG_CURR1 a " + " where to_char(a.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " + " )," + " (select count(b) from PIXEL_LOG_CURR2 b" + " where to_char(b.TIMESTAMP, 'YYYYMMDD') = :PROCDATE " + " )" + ") from Dual1" + "" ) }) public class SourceCount { @Id private Long COUNT; public SourceCount(Long COUNT1, Long COUNT2) { this.COUNT = COUNT1+COUNT2; } public Long getCOUNT() { return COUNT; } public void setCOUNT(Long COUNT) { this.COUNT = COUNT; } }
这里的部分魔力是创build一个虚拟表格,并在其中插入一条logging。 在我的情况下,我把它命名为dual1,因为我的数据库是Oracle,但是我不认为这对于你所说的虚拟表格来说很重要。
@Entity @Table(name="DUAL1") public class Dual1 { @Id Long ID; }
不要忘记插入您的虚拟logging:
SQL> insert into dual1 values (1);