网站无法排版,东莞网络优化公司排名,设计公司起名怎么起好,网站文章在哪发布做seo在使用Hibernate作为ORM开发服务器和嵌入式应用程序8年后#xff0c;我全力以赴地寻求提高Hibernate性能的解决方案#xff0c;阅读博客和参加会议#xff0c;我决定与您分享这几年获得的知识。 这是更多新帖子中的第一篇#xff1a; 去年#xff0c;我以Devoxx的身份参加… 在使用Hibernate作为ORM开发服务器和嵌入式应用程序8年后我全力以赴地寻求提高Hibernate性能的解决方案阅读博客和参加会议我决定与您分享这几年获得的知识。 这是更多新帖子中的第一篇 去年我以Devoxx的身份参加了演讲但我也参加了有关休眠反模式的 Patrycja Wegrzynowicz会议。 在该演示中 Patrycja向我们展示了一种反模式这种模式令我震惊因为事实证明它预料到了意外情况。 我们将看到当Hibernate检测到一个肮脏的集合并应该重新创建它时所产生的效果。 让我们从将要使用的模型开始只有两个与一对多关联相关的类 Entity
public class Starship {private Long id;Id GeneratedValue(strategyGenerationType.SEQUENCE) public Long getId() {return id;}public void setId(Long id) {this.id id;}private Date launched;Temporal(TemporalType.DATE) public Date getLaunched() {return launched;}public void setLaunched(Date launched) {this.launched launched;}private String registry;Column(uniquetrue, nullablefalse) public String getRegistry() {return registry;}public void setRegistry(String registry) {this.registry registry;}private StarshipClassEnum starshipClassEnum;Enumerated public StarshipClassEnum getStarshipClassEnum() {return starshipClassEnum;}public void setStarshipClassEnum(StarshipClassEnum starshipClassEnum) {this.starshipClassEnum starshipClassEnum;}private AffiliationEnum affiliationEnum;Enumerated public AffiliationEnum getAffiliationEnum() {return affiliationEnum;}public void setAffiliationEnum(AffiliationEnum affiliationEnum) {this.affiliationEnum affiliationEnum;}private Physics physics;Embedded public Physics getPhysics() {return physics;}public void setPhysics(Physics physics) {this.physics physics;}private ListOfficer officers new ArrayListOfficer();OneToMany(cascade{CascadeType.ALL}) public ListOfficer getOfficers() {return Collections.unmodifiableList(officers);}protected void setOfficers(ListOfficer officers) {this.officers officers;}public void addOfficer(Officer officer) {officer.setStarship(this);this.officers.add(officer);}public Starship() {super();}public Starship(String registry) {setRegistry(registry);}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result ((registry null) ? 0 : registry.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Starship other (Starship) obj;if (registry null) {if (other.registry ! null)return false;} else if (!registry.equals(other.registry))return false;return true;}
}Entity
public class Officer {private Long id;Id GeneratedValue(strategyGenerationType.SEQUENCE)public Long getId() {return id;}protected void setId(Long id) {this.id id;}private String name;Column(uniquetrue, nullablefalse) public String getName() {return this.name;}public void setName(String name) {this.name name;}private SpeciesEnum speciesEnum;Enumerated public SpeciesEnum getSpeciesEnum() {return speciesEnum;}public void setSpeciesEnum(SpeciesEnum speciesEnum) {this.speciesEnum speciesEnum;}private PlanetEnum homePlanet;Enumerated public PlanetEnum getHomePlanet() {return homePlanet;}public void setHomePlanet(PlanetEnum homePlanet) {this.homePlanet homePlanet;}private AffiliationEnum affiliationEnum;Enumerated public AffiliationEnum getAffiliationEnum() {return affiliationEnum;}public void setAffiliationEnum(AffiliationEnum affiliationEnum) {this.affiliationEnum affiliationEnum;}private RankEnum rank;Enumerated NotNull public RankEnum getRank() {return rank;}public void setRank(RankEnum rank) {this.rank rank;}private Starship starship; ManyToOne public Starship getStarship() {return starship;}protected void setStarship(Starship starship) {this.starship starship;}public Officer() {super();}public Officer(String name, RankEnum rank) {setName(name);setRank(rank);}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result ((name null) ? 0 : name.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Officer other (Officer) obj;if (name null) {if (other.name ! null)return false;} else if (!name.equals(other.name))return false;return true;}} 在上一堂课中我们应注意三个重点 我们在属性级别而不是字段级别进行注释。 OneToMany和 ManyToOne使用默认选项 级联定义除外 星际飞船类的军官getter返回一个不变的列表。 为了测试模型配置我们将创建一个测试该测试创建并保留一个Starship和七个高级管理人员 并在不同的Transaction和EntityManager中找到创建的Starship 。 ContextConfiguration
RunWith(SpringJUnit4ClassRunner.class)
public class StarshipPersistenceTests {Injectprivate EntityManagerFactory entityManagerFactory;Testpublic void testSaveOrderWithItems() throws Exception {Starship starship createData();findStarship(starship);}private Starship createData() {EntityManager entityManager entityManagerFactory.createEntityManager();EntityTransaction transaction entityManager.getTransaction();transaction.begin();Physics physics physics().height(137.5D).length(642.5D).power(Wrap reactor).width(467.0D).build();Calendar launched Calendar.getInstance();launched.set(2363, 9, 4);Starship starship starship().registry(NCC-1701-D).physics(physics).launched(launched.getTime()).starshipClass(StarshipClassEnum.GALAXY).affiliation(AffiliationEnum.STARFLEET).build();Officer jeanLucPicard officer().name(Jean-Luc Picard).rank(RankEnum.CAPTAIN).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.EARTH).speciment(SpeciesEnum.HUMAN).build();starship.addOfficer(jeanLucPicard);Officer williamRiker officer().name(William Riker).rank(RankEnum.COMMANDER).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.EARTH).speciment(SpeciesEnum.HUMAN).build();starship.addOfficer(williamRiker);Officer data officer().name(Data).rank(RankEnum.LIEUTENANT_COMMANDER).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.OMICRON_THETA).speciment(SpeciesEnum.ANDROID).build();starship.addOfficer(data);Officer geordiLaForge officer().name(Geordi La Forge).rank(RankEnum.LIEUTENANT).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.EARTH).speciment(SpeciesEnum.HUMAN).build();starship.addOfficer(geordiLaForge);Officer worf officer().name(Worf).rank(RankEnum.LIEUTENANT).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.QONOS).speciment(SpeciesEnum.KLINGON).build();starship.addOfficer(worf);Officer beverlyCrusher officer().name(Beverly Crusher).rank(RankEnum.COMMANDER).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.EARTH).speciment(SpeciesEnum.HUMAN).build();starship.addOfficer(beverlyCrusher);Officer deannaTroi officer().name(Deanna Troi).rank(RankEnum.COMMANDER).affiliation(AffiliationEnum.STARFLEET).homePlanet(PlanetEnum.BETAZED).speciment(SpeciesEnum.BETAZOID).build();starship.addOfficer(deannaTroi);entityManager.persist(starship);transaction.commit();entityManager.close();return starship;}private void findStarship(Starship starship) {EntityManager entityManager this.entityManagerFactory.createEntityManager();EntityTransaction transaction entityManager.getTransaction();transaction.begin();System.out.println(Before Find);Starship newStarship entityManager.find(Starship.class, starship.getId());System.out.println(After Find Before Commit);transaction.commit();System.out.println(After commit);entityManager.close();}
} 现在我们已经创建了这个测试我们可以运行它并且我们将观察Hibernate控制台的输出。 Hibernate: insert into Starship (affiliationEnum, launched, height, length, power, width, registry, starshipClassEnum, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)Before Find Starship By IdHibernate: select starship0_.id as id1_0_, starship0_.affiliationEnum as affiliat2_1_0_, starship0_.launched as launched1_0_, starship0_.height as height1_0_, starship0_.length as length1_0_, starship0_.power as power1_0_, starship0_.width as width1_0_, starship0_.registry as registry1_0_, starship0_.starshipClassEnum as starship9_1_0_ from Starship starship0_ where starship0_.id?After Find Starship By Id and Before CommitHibernate: select officers0_.Starship_id as Starship1_1_2_, officers0_.officers_id as officers2_2_, officer1_.id as id0_0_, officer1_.affiliationEnum as affiliat2_0_0_, officer1_.homePlanet as homePlanet0_0_, officer1_.name as name0_0_, officer1_.rank as rank0_0_, officer1_.speciesEnum as speciesE6_0_0_, officer1_.starship_id as starship7_0_0_, starship2_.id as id1_1_, starship2_.affiliationEnum as affiliat2_1_1_, starship2_.launched as launched1_1_, starship2_.height as height1_1_, starship2_.length as length1_1_, starship2_.power as power1_1_, starship2_.width as width1_1_, starship2_.registry as registry1_1_, starship2_.starshipClassEnum as starship9_1_1_ from Starship_Officer officers0_ inner join Officer officer1_ on officers0_.officers_idofficer1_.id left outer join Starship starship2_ on officer1_.starship_idstarship2_.id where officers0_.Starship_id?
Hibernate: delete from Starship_Officer where Starship_id?
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)
Hibernate: insert into Starship_Officer (Starship_id, officers_id) values (?, ?)After commit 查看在第一次提交期间持久对象和在第二次事务提交期间查找Starship 执行的查询数。 在忽略序列生成器的总和中我们可以计数22个inserts 2个selects和1个delete 这在我们仅创建8个对象和1个通过主键查找时很不错。 此时让我们检查为什么执行这些SQL查询 前八个插页不可避免。 通过将数据插入数据库需要它们。 接下来的七都需要插入因为我们已经注释getOfficers财产没有的mappedBy属性。 如果我们仔细查看Hibernate文档它会指出“在不描述任何物理映射的情况下将使用具有连接表的单向一对多 ”。 下一组查询甚至更陌生第一个选择语句是通过id查找Starship但是我们已经创建的这些数据删除和插入是什么 在提交期间 Hibernate通过比较对象引用来验证集合属性是否脏。 当一个集合被标记为脏集合时 Hibernate需要重新创建整个集合甚至包含相同的对象。 在本例中当我们要招募军官时我们要返回一个不同的收集实例具体来说是不可修改的列表因此Hibernate认为军官的收集是肮脏的。 由于使用了联接表因此应重新创建Starship_Officer表删除先前插入的元组并插入新的元组尽管它们具有相同的值。 让我们尝试解决此问题。 我们首先映射一个双向的一对多关联并以多对一的一方为拥有方。 private ListOfficer officers new ArrayListOfficer();
OneToMany(mappedBystarship, cascade{CascadeType.ALL}) public ListOfficer getOfficers() {return Collections.unmodifiableList(officers);}
protected void setOfficers(ListOfficer officers) {this.officers officers;}
public void addOfficer(Officer officer) {this.officers.add(officer);} 现在我们再次重新运行相同的测试并再次检查输出。 Hibernate: insert into Starship (affiliationEnum, launched, height, length, power, width, registry, starshipClassEnum, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)Before Find Starship By IdHibernate: select starship0_.id as id1_0_, starship0_.affiliationEnum as affiliat2_1_0_, starship0_.launched as launched1_0_, starship0_.height as height1_0_, starship0_.length as length1_0_, starship0_.power as power1_0_, starship0_.width as width1_0_, starship0_.registry as registry1_0_, starship0_.starshipClassEnum as starship9_1_0_ from Starship starship0_ where starship0_.id?After Find Starship By Id and Before CommitHibernate: select officers0_.starship_id as starship7_1_1_, officers0_.id as id1_, officers0_.id as id0_0_, officers0_.affiliationEnum as affiliat2_0_0_, officers0_.homePlanet as homePlanet0_0_, officers0_.name as name0_0_, officers0_.rank as rank0_0_, officers0_.speciesEnum as speciesE6_0_0_, officers0_.starship_id as starship7_0_0_ from Officer officers0_ where officers0_.starship_id?After commit 尽管我们已将SQL语句的数量从25个减少到10个但仍然有一个不必要的查询即第二个事务的commit部分中的查询。 为什么如果默认情况下军官是懒惰的 JPA规范而我们又没有让军官进行交易那么Hibernate会在“军官”表上执行选择吗 由于与先前配置相同的原因返回的集合具有不同的Java标识符因此Hibernate将其标记为新实例化的集合但是现在显然不再需要连接表操作。 我们减少了查询数量但是仍然存在性能问题。 可能我们需要其他解决方案而该解决方案不是最明显的解决方案我们不会返回Hibernate返回的集合对象我们稍后可能会对此进行扩展但是我们将更改批注的位置。 我们要做的是将映射位置从属性方法更改为使用字段映射。 简单来说我们将所有注释移至类属性而不是getter上 。 Entity
public class Starship {Id GeneratedValue(strategyGenerationType.SEQUENCE) private Long id;public Long getId() {return id;}protected void setId(Long id) {this.id id;}Temporal(TemporalType.DATE) private Date launched;public Date getLaunched() {return launched;}public void setLaunched(Date launched) {this.launched launched;}...OneToMany(mappedBystarship, cascade{CascadeType.ALL}) private ListOfficer officers new ArrayListOfficer();public ListOfficer getOfficers() {return Collections.unmodifiableList(officers);}protected void setOfficers(ListOfficer officers) {this.officers officers;}public void addOfficer(Officer officer) {officer.setStarship(this);this.officers.add(officer);}public Starship() {super();}public Starship(String registry) {setRegistry(registry);}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result ((registry null) ? 0 : registry.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Starship other (Starship) obj;if (registry null) {if (other.registry ! null)return false;} else if (!registry.equals(other.registry))return false;return true;}
}Entity
public class Officer {Id GeneratedValue(strategyGenerationType.SEQUENCE) private Long id;public Long getId() {return id;}protected void setId(Long id) {this.id id;}Column(uniquetrue, nullablefalse) private String name;public String getName() {return this.name;}public void setName(String name) {this.name name;}Enumerated private SpeciesEnum speciesEnum;public SpeciesEnum getSpeciesEnum() {return speciesEnum;}public void setSpeciesEnum(SpeciesEnum speciesEnum) {this.speciesEnum speciesEnum;}...ManyToOne private Starship starship; public Starship getStarship() {return starship;}protected void setStarship(Starship starship) {this.starship starship;}public Officer() {super();}public Officer(String name, RankEnum rank) {setName(name);setRank(rank);}Overridepublic int hashCode() {final int prime 31;int result 1;result prime * result ((name null) ? 0 : name.hashCode());return result;}Overridepublic boolean equals(Object obj) {if (this obj)return true;if (obj null)return false;if (getClass() ! obj.getClass())return false;Officer other (Officer) obj;if (name null) {if (other.name ! null)return false;} else if (!name.equals(other.name))return false;return true;}
} 最后我们将再次运行测试看看会发生什么 Hibernate: insert into Starship (affiliationEnum, launched, height, length, power, width, registry, starshipClassEnum, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Officer (affiliationEnum, homePlanet, name, rank, speciesEnum, starship_id, id) values (?, ?, ?, ?, ?, ?, ?)Before Find
Hibernate: select starship0_.id as id1_0_, starship0_.affiliationEnum as affiliat2_1_0_, starship0_.launched as launched1_0_, starship0_.height as height1_0_, starship0_.length as length1_0_, starship0_.power as power1_0_, starship0_.width as width1_0_, starship0_.registry as registry1_0_, starship0_.starshipClassEnum as starship9_1_0_ from Starship starship0_ where starship0_.id?After Find Before Commit
After commit 为什么使用属性映射Hibernate在提交期间运行查询并且不执行使用字段映射 提交事务后Hibernate执行刷新以使基础持久性存储与内存中保持的可持久状态同步。 当使用属性映射时Hibernate调用getter / setter方法来同步数据对于getOfficers方法它将返回一个脏集合由于进行了unmodifiableList调用。 另一方面当我们使用字段映射时 Hibernate直接获取字段因此收集不被认为是肮脏的并且不需要重新创建。 但是我们还没有完成我想您想知道为什么我们还没有从getter中删除Collections.unmodifiableList而是返回Hibernate集合 是的我同意您的意见我们很快完成了工作更改看起来像 OneToManycascade {CascadeType.ALL} public List Officer getOfficers{ 但是返回原始集合最终会导致封装问题实际上我们的封装已损坏 我们可以将任何所需的内容添加到可变列表中 我们可以将不受控制的更改应用于对象的内部状态。 使用unmodifiableList是避免破坏封装的一种方法但是我们当然可以对公共访问和休眠访问使用不同的访问器而不用调用Collections.unmodifiableList方法。 考虑到我们今天所看到的我建议您使用始终字段注释而不是属性映射我们将避免很多意外。 希望您发现这篇文章有用。 此示例的屏幕截图 下载代码 参考 Hibernate性能提示 JCG合作伙伴的 脏回收效应 在一个罐子统治他们所有博客的亚历克斯·索托。 翻译自: https://www.javacodegeeks.com/2012/03/hibernate-performance-tips-dirty.html