我正在使用现有数据库中的Hibernate替换工作中使用的应用程序。我无法修改数据库,因为它与其他进程一起使用。当Hibernate从db中提取主对象时,子对象将被放入无序集合中。我以前从未真正处理过集合或排序集。
我需要显示每组的最后一个(按时间顺序排列)的孩子。没有为子对象存储日期,但由于数据库中的id字段是AUTO_INCREMENT,我可以用id对它们进行排序来代替日期。
关于现有系统使用的一个抱怨是,它真的非常非常慢。我想用新的应用程序显示速度的明确提高。
给定一个Person对象(变量名称" off"),0到n"家庭地址",我使用:
Set addressSet = off.getAddresses();
List<Address> addressList = new ArrayList<>();
Iterator i = addressSet.iterator();
while(i.hasNext()){
addressList.add((Address) i.next());
}
Collections.sort(addressList, new AddressComparator());
Address a = null;
if(addressList.size()>0){
a = addressList.get(addressList.size()-1);
}else{
a = new Address(); //creates new Address object with empty strings
//for fields
}
我的简单比较器是:
public int compare(Address t, Address t1) {
return t.getId().compareTo(t1.getId());
}
我的问题:通过Java或Hibernate,是否有更快的方法对集合进行排序?
答案 0 :(得分:3)
从我的角度来看,你根本不需要排序。使用
Collections.max()
或
Collections.min()
提供自定义比较器以查找所需的地址。与O(nlog(n))排序时间相比,这在最坏的情况下具有O(n)运行时间,因为您不排序并且仅迭代您的集合一次。积极的一面是,您不需要将Set
转换为List
,因为max和min方法适用于任何Collection
实例。
另一个优点(至少对我来说)是Collections
实用程序是java运行时的一部分,因此您不需要添加任何第三方库。
答案 1 :(得分:0)
您可以在没有临时列表的情况下执行此操作。
TreeSet sortedSet = Sets.newTreeSet(new AddressComparator());
sortedSet.addAll(off.getAddresses());
return sortedSet.first(); // or sortedSet.last() see what is suitable for you
Sets的详细信息。
UPD。
另请参阅Guava Ordering solution。它将允许您获得最大元素而无需临时收集。
Ordering<Adress> ordering = Ordering.from(new AddressComparator());
return ordering.max(off.getAddresses());
答案 2 :(得分:0)
我不确定是否有多个套装,但从代码来看,您似乎只是获得ID最高的Address
。这可以通过以下sql来实现,这不需要排序。
select * from table where id = (select max(id) from table);
答案 3 :(得分:0)
您可以使用@OrderBy属性在JPA / Hibernate中对数据库级别进行排序,其中排序位于非嵌套属性上。所以在你的情况下你可以这样做。
e.g。
@OneToMany
@OrderBy("id");
public Set<Address> addresses;
和Hibernate将确保集合处于有序集合中。
如果排序字段恰好位于嵌套属性上(在您的情况下不是这样),例如person.address.town.population那么你仍然可以让Hibernate使用Hibernate特定的(非JPA)@Sort注释处理排序,它将确保如上所述的排序集,但是将使用内存排序而不是数据库顺序排序子句。
@OneToMany
@Sort(//natural or specify a comparator);
public Set<Address> addresses;
当然,这不能为您提供最新的地址。如果您不想将映射从Set更改为允许您获取最新的索引,那么您也可以通过各种方式在数据库层中执行此操作,例如:通过基于每个人的最大地址id创建视图。
@Entity
@Table(name = "vw_most_recent_addresses"
public class MostRecentAddress extends Address{
}
public class Person{
@OneToMany
@OrderBy("id");
public Set<Address> addresses;
@OneToOne
public MostRecentAddress mostRecentAddress;
}