User對Room是多對一的關系,那么反過來Room對User就是一對多的關系了。
User.java:
- package com.hb3.pack_17.model;
- public class User {
- private Integer id;
- private String name;
- public User() {
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
Room.java:
- package com.hb3.pack_17.model;
- import java.util.Set;
- public class Room {
- private Integer id;
- private String address;
- private Set<User> users;
- public Room() {
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public Set<User> getUsers() {
- return users;
- }
- public void setUsers(Set<User> users) {
- this.users = users;
- }
- public void addUser(User user) {
- users.add(user);
- }
- public void removeUser(User user) {
- users.remove(user);
- }
- }
Room.hbm.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping
- PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.hb3.pack_17.model.Room" table="room">
- <id name="id" column="id">
- <generator class="native"/>
- </id>
- <property name="address"
- column="address"
- type="java.lang.String"/>
- <set name="users" table="user" cascade="all">
- <key column="room_id"/>
- <one-to-many class="com.hb3.pack_17.model.User"/>
- </set>
- </class>
- </hibernate-mapping>
User.hbm.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping
- PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.hb3.pack_17.model.User" table="user">
- <id name="id" column="id" type="java.lang.Integer">
- <generator class="native"/>
- </id>
- <property name="name" column="name" type="java.lang.String"/>
- </class>
- </hibernate-mapping>
測試代碼:
- package com.hb3.pack_17;
- import java.io.IOException;
- import java.sql.SQLException;
- import java.util.HashSet;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import com.hb3.pack_17.model.Room;
- import com.hb3.pack_17.model.User;
- public class BusinessService {
- public static void main(String[] args) throws IOException, SQLException {
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.openSession();
- User user1 = new User();
- user1.setName("yangye");
- User user2 = new User();
- user2.setName("shenbin");
- User user3 = new User();
- user3.setName("chenyan");
- Room room1 = new Room();
- room1.setUsers(new HashSet<User>());
- room1.setAddress("NTU-M8-419");
- room1.addUser(user1);
- room1.addUser(user2);
- Room room2 = new Room();
- room2.setUsers(new HashSet<User>());
- room2.setAddress("NTU-G3-302");
- room2.addUser(user3);
- Transaction tx = session.beginTransaction();
- session.save(room1);
- session.save(room2);
- tx.commit();
- session.close();
- sessionFactory.close();
- }
- }
雙向關聯:
以上多對一,一對多的關系都是單向關聯,也就是一方聯系到另一方,而另一方不知道自己被關聯。
如果上方都意識到另一方的存在,則形成雙向關聯。現將上面的代碼改寫如下:
在User類中追加Room類型的字段:
- package com.hb3.pack_20.model;
- public class User {
- private Integer id;
- private String name;
- private Room room;
- public Room getRoom() {
- return room;
- }
- public void setRoom(Room room) {
- this.room = room;
- }
- public User() {
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
User.hbm.xml中也同樣追加關于Room的信息:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping
- PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.hb3.pack_20.model.User" table="user">
- <id name="id" column="id" type="java.lang.Integer">
- <generator class="native"/>
- </id>
- <property name="name" column="name" type="java.lang.String"/>
- <many-to-one name="room"
- column="room_id"
- class="com.hb3.pack_20.model.Room"
- cascade="save-update"
- outer-join="true"/>
- </class>
- </hibernate-mapping>
這里我們將Room.hbm.xml文件里set的cascade屬性也設為save-update:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping
- PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.hb3.pack_20.model.Room" table="room">
- <id name="id" column="id">
- <generator class="native"/>
- </id>
- <property name="address"
- column="address"
- type="java.lang.String"/>
- <set name="users" table="user" cascade="save-update">
- <key column="room_id"/>
- <one-to-many class="com.hb3.pack_20.model.User"/>
- </set>
- </class>
- </hibernate-mapping>
這樣我們可以用多對一的方式來維持管理:
- package com.hb3.pack_20;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import com.hb3.pack_20.model.Room;
- import com.hb3.pack_20.model.User;
- public class BusinessService {
- public static void main(String[] args) {
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.openSession();
- User user1 = new User();
- user1.setName("chenyan");
- User user2 = new User();
- user2.setName("shenbin");
- Room room1 = new Room();
- room1.setAddress("NTU-M8-419");
- user1.setRoom(room1);
- user2.setRoom(room1);
- Transaction tx = session.beginTransaction();
- session.save(user1);
- session.save(user2);
- tx.commit();
- session.close();
- sessionFactory.close();
- }
- }
或者反過來由一對多的方式來維持關系:
- package com.hb3.pack_20;
- import java.util.HashSet;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import com.hb3.pack_20.model.Room;
- import com.hb3.pack_20.model.User;
- public class BusinessService {
- public static void main(String[] args) {
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.openSession();
- User user1 = new User();
- user1.setName("chenyan");
- User user2 = new User();
- user2.setName("shenbin");
- Room room1 = new Room();
- room1.setUsers(new HashSet<User>());
- room1.setAddress("NTU-M8-419");
- room1.addUser(user1);
- room1.addUser(user2);
- Transaction tx = session.beginTransaction();
- session.save(room1);
- tx.commit();
- session.close();
- sessionFactory.close();
- }
- }
但是一對多的方式來維持的話,先看一下生成的SQL文:
Hibernate: insert into room (address) values (?)
Hibernate: insert into user (name, room_id) values (?, ?)
Hibernate: insert into user (name, room_id) values (?, ?)
Hibernate: update user set room_id=? where id=?
Hibernate: update user set room_id=? where id=?
可見,如果把一的一方Room作為主控方,多的一方User因為不知道Room的room_id是多少,所以 必須等Room和User存儲之后再更新room_id。所以在多對一,一對多形成雙向關聯的時候,應該把控制權交給多的一方,這樣比較有效率。理由很簡 單,就像在公司里一樣,老板記住所有員工的名字來得快,還是每個員工記住老板的名字來得快。
基于這個理由,我們對Room.hbm.xml再稍作修改:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping
- PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.hb3.pack_20.model.Room" table="room">
- <id name="id" column="id">
- <generator class="native"/>
- </id>
- <property name="address"
- column="address"
- type="java.lang.String"/>
- <set name="users" table="user" cascade="save-update" inverse="true">
- <key column="room_id"/>
- <one-to-many class="com.hb3.pack_20.model.User"/>
- </set>
- </class>
- </hibernate-mapping>
如此控制權就交給了多的一方。當直接存儲一的一方前,必須讓多的一方意識的一的一方的存在。
- package com.hb3.pack_20;
- import java.io.IOException;
- import java.sql.SQLException;
- import java.util.HashSet;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- import com.hb3.pack_20.model.Room;
- import com.hb3.pack_20.model.User;
- public class BusinessService {
- public static void main(String[] args) throws IOException, SQLException {
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- Session session = sessionFactory.openSession();
- User user1 = new User();
- user1.setName("bush");
- User user2 = new User();
- user2.setName("caterpillar");
- Room room1 = new Room();
- room1.setUsers(new HashSet<User>());
- room1.setAddress("NTU-M8-419");
- room1.addUser(user1);
- room1.addUser(user2);
- //多方必須認識到單方的存在
- user1.setRoom(room1);
- user2.setRoom(room1);
- Transaction tx = session.beginTransaction();
- session.save(room1);
- tx.commit();
- session.close();
- sessionFactory.close();
- }
- }
此時生成的SQL文為:
Hibernate: insert into room (address) values (?)
Hibernate: insert into user (name, room_id) values (?, ?)
Hibernate: insert into user (name, room_id) values (?, ?)
從而提高了效率。
如果把代碼中user1.setRoom(room1);和user2.setRoom(room1);這2 行移去,你會發現數據庫中room_id的值為null。這個結果就好比在多對一的關系中沒有分配給User一個Room,那么理所當然room_id的 值為null了。
ExtJS教程- Hibernate教程-Struts2 教程-Lucene教程