Hibernate参考文档学习笔记——Hibernate入门(二)
“10,000小时的标准”——《异类》
今天的学习任务就是关联映射。看看Hibernate是如何处理关联关系的。
1、创建映射类
为了说明关联关系,添加一个Person实体类,每个Person有自己对应的Event列表。
1 public class Person { 2 private Long id; 3 private int age; 4 private String firstName; 5 private String lastname; 6 7 public Person(){ 8 } 9 10 public Long getId() { 11 return id; 12 } 13 public void setId(Long id) { 14 this.id = id; 15 } 16 17 public int getAge() { 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public String getFirstName() { 25 return firstName; 26 } 27 public void setFirstName(String firstName) { 28 this.firstName = firstName; 29 } 30 31 public String getLastname() { 32 return lastname; 33 } 34 public void setLastname(String lastname) { 35 this.lastname = lastname; 36 } 37 }
创建对应的映射文件Person.hbm.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="events"> 6 <class name="Person" table="PERSON"> 7 <id name="id" column="PERSON_ID"> 8 <generator class="native" /> 9 </id> 10 11 <property name="age" /> 12 <property name="firstName" /> 13 <property name="lastname" /> 14 </class> 15 </hibernate-mapping>
创建好后将该映射文件添加到Hibernate.cfg.xml配置文件中。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <!-- 设置连接数据库的驱动 --> 8 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 9 <!-- 设置数据库服务器的连接路径 --> 10 <property name="connection.url">jdbc:mysql://localhost:3306/db</property> 11 <!-- 设置数据库服务器的连接用户 --> 12 <property name="connection.username">root</property> 13 <!-- 设置数据库服务器的连接用户的密码 --> 14 <property name="connection.password">Lynn0714</property> 15 <!-- 数据库连接池大小 --> 16 <property name="connection.pool_size">1</property> 17 <!-- SQL方言,要根据使用的数据库来配置 --> 18 <property name="dialect">org.hibernate.dialect.MySQLDialect</property> 19 <!-- 设置Hibernate的自动session管理 --> 20 <property name="current_session_context_class">thread</property> 21 <!-- 设置二级cache --> 22 <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 23 <!-- 设置运行时是否显示调用的SQL语句 --> 24 <property name="show_sql">true</property> 25 <!-- Drop and re-create the database schema on startup --> 26 <property name="hbm2ddl.auto">create</property> 27 28 <!-- 使用的映射文件 --> 29 <mapping resource="events/Event.hbm.xml" /> 30 <mapping resource="events/Person.hbm.xml"/> 31 </session-factory> 32 </hibernate-configuration>
配置好后,我们就可以开始添加关联了。
2、单向Set-based关联
对于每个Person可以参与一系列的Event,而每个Event也可能有不同的参加的Person,因此,Person和Event直接的关系如下图:
因此需要在Person中添加一个Event集合来表示与当前人员关联的事件,同时,我们也可以在Event中添加一个Person集合来表示当前事件的所有参与者,这样我们就得到了双向映射的多对多关联。也可以采用单向的多对多关联,即只选取上述的其中一条,另一条通过一个显示查询获取结果集。在本例中,使用单向的多对多关联映射:
(1) 在Person类中添加Event集合以及对应的getter、setter
1 private Set events = new HashSet(); 2 public Set getEvents() { 3 return events; 4 } 5 6 public void setEvents(Set events) { 7 this.events = events; 8 } 9
(2) 映射文件中添加集合映射
1 <set name="events" table="PERSON_EVENT"> 2 <key column="PERSON_ID" /> 3 <many-to-many column="EVENT_ID" class="Event" /> 4 </set>
这样,我们就可以得到下面的表关系了
3、使关联工作
为了使关联工作起来,需要在EventManager中添加一些代码,
1 private void addPersonToEvent(Long personId,Long eventId){ 2 Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 3 session.beginTransaction(); 4 5 Person aPerson = (Person)session.load(Person.class, personId); 6 Event anEvent = (Event)session.load(Event.class, eventId); 7 8 aPerson.getEvents().add(anEvent); 9 10 session.getTransaction().commit(); 11 }
在这段代码中我们没有显示的使用save()或update()方法,这是因为通过load方法得到的对象都是持久化状态的,他们在事务提交的时候会自动和数据库进行同步,以此来保证数据的一致性。如果对象不是持久化状态的,那么就需要显示的调用save()或update()方法了。
4、值类型的集合
对Person实体添加一个值类型对象的集合,假如保存email地址
1 private Set emailAddresses = new HashSet(); 2 3 public Set getEmailAddresses(){ 4 return emailAddresses; 5 } 6 7 public void setEmailAddresses(Set emailAddresses){ 8 this.emailAddresses = emailAddresses; 9 }
然后在映射文件中配置如下
1 <set name="emailAddresses" table="PERSON_EMAIL_ADDR"> 2 <key column="PERSON_ID" /> 3 <element type="string" column="EMAIL_ADDR" /> 4 </set>
这次又是使用了set,但是却使用了element属性,与前面的many-to-many的不同在于,使用element并不会包含对其他实体引用的集合。
下面就把元素加入到集合中
1 private void addEmailToPerson(Long personId, String emailAddress){ 2 Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 3 session.beginTransaction(); 4 5 Person person = (Person)session.load(Person.class, personId); 6 person.getEmailAddresses().add(emailAddress); 7 8 session.getTransaction().commit(); 9 }
这样就可以给Person添加email了。
5、双向关联
双向关联式指让关联的两端可以相互访问,即任何一端都存有另一端的引用。前面已经将Event加入到Person中了,现在只需将Person集合加入到Event实体中即可。
1 private Set participants = new HashSet(); 2 3 public Set getParticipants(){ 4 return participants; 5 } 6 7 public void setParticipants(Set participants){ 8 this.participants = participants; 9 }
Event.hbm.xml映射文件中添加对应的配置
1 <set name="participants" table="PERSON_EVENT" inverse="true"> 2 <key column="EVENT_ID"/> 3 <many-to-many column="PERSON_ID" class="Person"/> 4 </set>
这里的配置与在Person.hbm.xml中的配置一样,唯一的区别在于inverse=“true”属性。