怎么在Hibernate 4和Spring中使用批注定义不同类型的

家电修理 2023-07-16 19:16www.caominkang.com电器维修

我有两个课程,

Foo
Bar
,如下所示

public class Foo {  private Long fooId;  private Bar bar;  //Yes, this doesn't actually make any sense,  //having both a list and a single object here, its an example.  private List<Bar> bars;}public class Bar { private Long barId; private Foo foo;}

创建带注释的关系
假定所有带有@Entity和注释的类@Table

单向一对一关系

public class Foo{ private UUID fooId; @oneToOne private Bar bar;}public class Bar{ private UUID barId; //No corresponding mapping to Foo.class}

由Foo.class管理的双向一对一关系

public class Foo{ private UUID fooId; @oneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "barId") private Bar bar;}public class Bar{ private UUID barId; @oneToOne(mappedBy = "bar") private Foo foo;}

使用用户管理的联接表的单向一对多关系

public class Foo{ private UUID fooId; @oneToMany @JoinTable(name="FOO_BAR",  joinColumns = @JoinColumn(name="fooId"),  inverseJoinColumns = @JoinColumn(name="barId")) private List<Bar> bars;}public class Bar{ private UUID barId; //No Mapping specified here.}@Entity@Table(name="FOO_BAR")public class FooBar{ private UUID fooBarId; @ManyToOne @JoinColumn(name = "fooId") private Foo foo; @ManyToOne @JoinColumn(name = "barId") private Bar bar; //You can store other objects/fields on this table here.}

当设置一个User对象时,

Spring Security
经常与
Spring Security
一起使用,这些对象Role可以执行的列表。您可以向用户添加和删除角色,而不必担心级联删除Role。

使用外键映射的双向一对多关系

public class Foo{ private UUID fooId; @oneToMany(mappedBy = "bar") private List<Bar> bars;}public class Bar{ private UUID barId; @ManyToOne @JoinColumn(name = "fooId") private Foo foo;}

使用

Hibernate
托管联接表的双向多对多

public class Foo{ private UUID fooId; @oneToMany @JoinTable(name="FOO_BAR",  joinColumns = @JoinColumn(name="fooId"),  inverseJoinColumns = @JoinColumn(name="barId")) private List<Bar> bars;}public class Bar{ private UUID barId; @oneToMany @JoinTable(name="FOO_BAR",  joinColumns = @JoinColumn(name="barId"),  inverseJoinColumns = @JoinColumn(name="fooId")) private List<Foo> foos;}

使用用户管理的联接表对象的双向多对多

通常在要在连接对象上存储其他信息(例如创建关系的日期)时使用。

public class Foo{ private UUID fooId; @oneToMany(mappedBy = "bar") private List<FooBar> bars;}public class Bar{ private UUID barId; @oneToMany(mappedBy = "foo") private List<FooBar> foos;}@Entity@Table(name="FOO_BAR")public class FooBar{ private UUID fooBarId; @ManyToOne @JoinColumn(name = "fooId") private Foo foo; @ManyToOne @JoinColumn(name = "barId") private Bar bar; //You can store other objects/fields on this table here.}

确定双向关系的哪一方“拥有”该关系
这是制定Hibernate关系的棘手方面之一,因为无论采用哪种方式建立关系,Hibernate都能正常运行。唯一会改变的是外键存储在哪个表上。通常,您具有集合的对象将拥有该关系。

示例User对象上具有Roles声明的列表。在大多数应用程序中,系统将比User对象实例更多地操纵对象实例Roles。,我将使Role对象成为关系的拥有方,并Role通过by级联Role上的列表处理对象User。有关实际示例,请参见双向“一对多”示例。通常,除非有特殊要求,否则您将级联此方案中的所有更改。

确定您的fetchType

延迟获取的集合导致SO上的问题比我关心的要多,因为默认情况下,Hibernate会延迟加载相关对象。根据Hibernate文档,关系是一对一还是多对多并不重要

默认情况下,

Hibernate
对集合使用延迟选择获取,对单值关联使用延迟代理获取。对于大多数应用程序中的大多数关联而言,这些默认设置有意义。

考虑一下这是我何时使用

fetchType.LAZYvs fetchType.EAGER
在对象上的两分钱。如果您知道50%的时间不需要访问父对象上的集合,则可以使用fetchType.LAZY。

这样的性能优势是巨大的,并且只有在您向集合中添加更多对象时,它才会增长。这是因为对于急切加载的集合,Hibernate在后台进行了大量检查以确保您的数据都没有过期。虽然我确实主张将

Hibernate
用于集合,请注意,使用会降低性能
fetchType.EAGE
R。,以我们的Person对象为例。当我们加载a时,我们很可能Person想知道Roles它们的性能。我通常将此收藏标记为
fetchType.EAGER
。不要自反地将您的收藏标记为fetchType.EAGER简单的周围
LazyInitializationException
。它不仅由于性能原因而不好,而且通常表明您遇到了设计问题。问问自己,这个集合实际上是一个急切加载的集合,还是我只是通过这种方法访问该集合?Hibernate有解决此问题的方法,不会对您的操作性能产生太大影响。Service如果只想为一次调用初始化延迟加载的集合,则可以在图层中使用以下代码。

//Service Class@Override@Transactionalpublic Person getPersonWithRoles(UUID personId){ Person person = personDAO.find(personId); Hibernate.initialize(person.getRoles()); return person;}

调用Hibernate.initialize强制创建和加载收集对象。,请注意,如果仅将其传递给Person实例,则将获得代理Person。有关更多信息,请参见文档。此方法的唯一缺点是您无法控制Hibernate如何实际获取对象集合。如果要控制它,则可以在DAO中进行控制。

//DAO@Overridepublic Person findPersonWithRoles(UUID personId){ Criteria criteria = sessionFactory.getCurrentSession().createCritiera(Person.class); criteria.add(Restrictions.idEq(personId); criteria.setFetchMode("roles", FetchMode.SUBSELECT);}

这里的性能取决于FetchMode您指定的内容。我已阅读出于性能原因而使用的答案FetchMode.SUBSELECT。如果您真的有兴趣,链接的答案会更详细。

如果您想在我重复自己时阅读我,请随时在此处查看我的其他答案

确定级联方向
Hibernate可以双向关系中的一种或两种方式级联操作。所以,如果你有一个列表Role的一个User可以级联变化Role的两个方向。如果您Role在UserHibernate 上更改了特定的名称,则可以自动更新Table Role上的关联Role。

,这并非总是期望的行为。如果您考虑一下,在这种情况下,Role根据的更改对进行更改User没有任何意义。,朝相反的方向前进是有意义的。Role在Role对象本身上更改一个名称,该更改可以级联到所有User带有该名称的对象Role。

在效率方面,Role通过保存User对象所属的对象来创建/更新对象是有意义的。这意味着您可以将@OneToMany注释标记为级联注释。我举一个例子

public User saveOrUpdate(User user){ getCurrentSession.saveOrUpdate(user); return user;}

在上述例子中,

Hibernate
会生成一个
INSERT
用于查询
User
对象,然后级联的创建Role的,一旦User已被插入到数据库中。这些插入语句将能够使用的
PK User
作为其外键,您最终将获得N + 1个插入语句,其中
N
Role
用户列表中对象的数量。

相反,如果要保存

Role
级联回到对象的单个User对象,可以执行以下操作

//Assume that user has no roles in the list, but has been saved to the//database at a cost of 1 insert.public void saveOrUpdateRoles(User user, List<Roles> listOfRoles){ for(Role role : listOfRoles){  role.setUser(user);  getCurrentSession.saveOrUpdate(role); }}

此结果在N + 1个插入其中N是数目Role的在

listOfRoles
,但作为hibernate级联每增加一个的产生也可为N更新语句
Role
User
表。与您以前的方法O(n)相比,此DAO方法的时间复杂度比O(1)高,因为​​您必须遍历角色列表。尽可能避免这种情况。

,实际上,关系的所有者通常是标记级联的位置,并且通常会将所有级联。

Orphan Removal

如果删除与对象的所有关联,

Hibernate
可以为您解决。假设您有一个User具有的列表的,Role并且在此列表中有5个不同角色的链接。假设您删除了一个
Role
称为
ROLE_EXAMPLE
的对象,并且碰巧该
ROLE_EXAMPLE
在任何其他
User
对象上都不存在。如果您已
orphanRemoval = true
设置@OneToMany注释,则
Hibernate
将通过级联从数据库中删除现在“孤立”的Role对象。

不应在所有情况下都启用孤立删除功能。实际上,在上面的示例中使用orphanRemoval没有任何意义。仅仅因为

no User
无法执行
ROLE_EXAMPLE
对象所代表的任何动作,并不意味着任何将来User都将永远无法执行该动作。

该问答旨在补充正式的Hibernate文档,该文档针对这些关系具有大量的XML配置。

这些示例并非要复制粘贴到生产代码中。它们是如何使用JPA注释在Spring frameork中配置和配置Hibernate 4的通用示例。这些示例假定所有类都有以以下格式声明的ID字段fooId。此ID字段的类型无关。

如何为这些类使用Hibernate 4的批注实现一个(单向/双向)一对多,多对一或多对多关系?

,我该如何配置我的一对多对象以移除孤儿,延迟加载以及

LazyInitialiaizationException
在处理集合时会导致a的原因以及如何解决问题?



Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by