怎么在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;}
创建带注释的关系
假定所有带有@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.EAGER。,以我们的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的原因以及如何解决问题?
空调维修
- 海信电视维修站 海信电视维修站点
- 格兰仕空调售后电话 格兰仕空调维修售后服务电
- 家电售后服务 家电售后服务流程
- 华扬太阳能维修 华扬太阳能维修收费标准表
- 三菱电机空调维修 三菱电机空调维修费用高吗
- 美的燃气灶维修 美的燃气灶维修收费标准明细
- 科龙空调售后服务 科龙空调售后服务网点
- 华帝热水器维修 华帝热水器维修常见故障
- 康泉热水器维修 康泉热水器维修故障
- 华凌冰箱维修电话 华凌冰箱维修点电话
- 海尔维修站 海尔维修站点地址在哪里
- 北京海信空调维修 北京海信空调售后服务
- 科龙空调维修 科龙空调维修故障
- 皇明太阳能售后 皇明太阳能售后维修点
- 海信冰箱售后服务 海信冰箱售后服务热线电话
- 海尔热水器服务热线