public class Event{
Long id;
String title;
Date date;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
<hibernate-mapping package="org.hibernate.tutorial.domain">
<class name="Event" table="EVENTS">
<id name="id" column="EVENTS_ID">
<generator class="native"></generator>
</id>
<property name="date" type="timestamp" column="EVENTS_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>
[img]http://dl.iteye.com/upload/attachment/0070/4674/3c1768b3-ae26-3d53-91e0-c163f22425f9.jpg[/img]
关于实体映射文件中的type属性中指定的属性值,既不是java中的类型,也不是数据库中的数据类型,而是"Hibernate Mapping Types" 用于java类中属性的类型与数据库字段类型的映射。如果省略了type字段,hibernate将自动尝试用正确的类型去匹配。
另外hibernate官方文档中提示:在处理实体映射文件时如果省略type属性时hibernate将使用反射技术对类型尝试进行匹配,这是一个耗费资源和时间的操作,因此出于对性能和资源的影响,最好在映射文件的属性中都加入type属性。
========================================================================================================================================
hibernate.cfg.xml文件中关于session的配置
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
获取current Session
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
[img]http://dl.iteye.com/upload/attachment/0070/4692/16a49534-059f-3187-b86a-d0b25240fc0c.jpg[/img]
调用getCurrentSession()方法总是返回"当前"的工作单元,这与hibernate.cfg.xml配置文件中(<property name="current_session_context_class">[u]thread[/u]</property>
)是有关系的org.hibernate.Session被设计用来表示单一的工作单元,getCurrentSession()方法返回的session,将与当前的java线程绑定来处理相关的操作,当事务提交\结束\回滚时,hibernate会将该session自动与当前线程解除绑定并关闭,再次调用getCurrentSession()方法,返回的又是一个新的session(工作单元)
另外:[b]在hibernate中提供了三种方式用于对current session 进行管理,配置文件中"thread"值的配置不建议在生产上使用[/b],当前只是为了小的demo的演示,具体讲解放到后面
(1)增加一个Person对象 person中包含event
public class Person {
private Long id;
private int age;
private String firstname;
private String lastname;
Set events = new HashSet();
//增加set\get方法
}
(2)配置文件
<class name="Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native"/>
</id>
<property name="age"/>
<property name="firstname"/>
<property name="lastname"/>
<set name="events" table="PERSON_EVENT">
<key column="PERSON_ID"/>
<many-to-many column="EVENT_ID" class="Event"/>
</set>
</class>
(3)数据库表关系映射说明:
[img]http://dl.iteye.com/upload/attachment/0071/1257/e3cbf5eb-caa6-3093-b6f8-f88fbfa8a780.jpg[/img]
(4)测试
private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);
aPerson.getEvents().add(anEvent);
session.getTransaction().commit();
}
测试说明:
[img]http://dl.iteye.com/upload/attachment/0071/1263/4d551eda-6e15-3f55-ba53-728da7296514.jpg[/img]
通过上面的代码可以看到:我们不需要显式的执行update或者save方法,hibernate会自动探测到某些属性值发生变化了,需要更新,这叫做"automatic dirty checking" 只要数据处在"persistent stat"状态,会绑定一个当前独有的org.hibernate.Session对象,hibernate会监视任何的变化并在后台生成相关的SQL语句,在调用flushing/commit/rollback等方法后会进行内存与数据库的同步,把变化的数据持久化到数据库。
不同session下的测试:
private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId)
.uniqueResult(); // Eager fetch the collection so we can use it detached
Event anEvent = (Event) session.load(Event.class, eventId);
session.getTransaction().commit();
// End of first unit of work
aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
// Begin second unit of work
Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();
session2.update(aPerson); // Reattachment of aPerson
session2.getTransaction().commit();
}
说明:
You can load person and event in different units of work. Or you can modify an object outside of a org.hibernate.Session, when it is not in persistent state (if it was persistent before, this state is called detached). You can even modify a collection when it is detached:
The call to update makes a detached object persistent again by binding it to a new unit of work, so any modifications you made to it while detached can be saved to the database. This includes any modifications (additions/deletions) you made to a collection of that entity object.
我们可以通过不同的session来装载对象,我们可以在这个对象不是"persistent state"状态时修改对象,调用update方法可以使detached状态的对象持久(会将对象绑定到一个新的session); 所以对于detached对象的任何的修改对可以被持久化到数据库。
非实体关系的xml映射 Person类中增加如下属性代码
private Set emailAddresses = new HashSet();
public Set getEmailAddresses() {
return emailAddresses;
}
public void setEmailAddresses(Set emailAddresses) {
this.emailAddresses = emailAddresses;
}
xml配置文件
<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
<key column="PERSON_ID"/>
<element type="string" column="EMAIL_ADDR"/>
</set>
数据库映射关系:
[img]http://dl.iteye.com/upload/attachment/0071/1297/6290c7d8-2aaa-3ecb-adb6-01fd9a0e2f4b.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/0071/1299/40f990ce-1185-3bec-bc9c-a5152cbbeb6d.jpg[/img]
这次的映射跟上次的映射唯一不同是把many-to-mangy 改成了element,此配置告诉hibernate,增加的该collection不参考任何的其他实体。其他个标签中属性配置的意义与前面例子中的events映射相同。
双向映射: 结合上面Person中单项映射Event类例子来看下面的代码
Event类增加如下代码:
private Set emailAddresses = new HashSet();
public Set getEmailAddresses() {
return emailAddresses;
}
public void setEmailAddresses(Set emailAddresses) {
this.emailAddresses = emailAddresses;
}
Event.hbm.xml代码
<set name="participants" table="PERSON_EVENT" inverse="true">
<key column="EVENT_ID"/>
<many-to-many column="PERSON_ID" class="Person"/>
</set>
此处的核心是属性inverse的含义:
[img]http://dl.iteye.com/upload/attachment/0071/1313/7eeb0dfb-26fa-3d0a-a7b7-1c418af9ef6d.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/0071/1315/dbecf930-8545-3219-8587-dc45d50bb1d5.jpg[/img]
此处关于inverse的解释不是很清楚,后面文档中如有讲解到在进行补充。