如何在Hibernate 4和Spring中使用批注定义不同类型的关系?
我有两个课程,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;
}
如何为这些类使用Hibernate 4的批注实现一个(单向/双向)一对多,多对一或多对多关系?
另外,我该如何配置我的一对多对象以移除孤儿,延迟加载以及LazyInitialiaizationException
在处理集合时会导致a的原因以及如何解决问题?
回答:
我有两个课程,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
@Transactional
public Person getPersonWithRoles(UUID personId){
Person person = personDAO.find(personId);
Hibernate.initialize(person.getRoles());
return person;
}
调用Hibernate.initialize强制创建和加载收集对象。但是,请注意,如果仅将其传递给Person实例,则将获得代理Person。有关更多信息,请参见文档。此方法的唯一缺点是您无法控制Hibernate如何实际获取对象集合。如果要控制它,则可以在DAO中进行控制。
//DAO@Override
public 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)高,因为您必须遍历角色列表。尽可能避免这种情况。
但是,实际上,关系的所有者通常是标记级联的位置,并且通常会将所有级联。
如果删除与对象的所有关联,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 Framework中配置和配置Hibernate 4的通用示例。这些示例假定所有类都有以以下格式声明的ID字段:fooId。此ID字段的类型无关。
如何为这些类使用Hibernate 4的批注实现一个(单向/双向)一对多,多对一或多对多关系?
另外,我该如何配置我的一对多对象以移除孤儿,延迟加载以及LazyInitialiaizationException
在处理集合时会导致a的原因以及如何解决问题?
以上是 如何在Hibernate 4和Spring中使用批注定义不同类型的关系? 的全部内容, 来源链接: utcz.com/qa/402462.html