在關聯關系的映射中使用得最多的就是一對多的關聯,一對多的關聯關系分為兩種:單向一對多,雙向一對多。下面分別對這兩種情況進行總結:
首先準備兩張表:用戶表user和用戶組表group
- CREATE TABLE
`test`.`group` ( - `id` int(10) unsigned NOT NULL auto_increment,
- `name` varchar(45) NOT NULL,
- PRIMARY KEY
(`id`) - )
-
-
- CREATE TABLE
`test`.`user` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `name` varchar(45) NOT NULL,
- `group_id` int(10) unsigned default
NULL, - PRIMARY KEY
(`id`), - KEY `FK_users_1` (`group_id`),
- CONSTRAINT `FK_users_1` FOREIGN
KEY (`group_id`) REFERENCES `group`
(`id`) - )
首先,來看看單向一對多的情況:
Group類中有如下屬性:
- private Integer id;
- private String name;
- private Set users = new
HashSet(0);//用戶的set集合,用于存一對多中的“多”的一方
User類只需要有本身的屬性即可:
- private Integer id;
- private String name;
接下來才是重點,配置單向一對多之間的關聯
Group.hbm.xml文件的配置如下:
- <hibernate-mapping>
- <class
name="com.stream.model.Group" table="group"
catalog="test"> - <id
name="id" type="java.lang.Integer"> - <column
name="id" /> - <generator
class="identity" /> - </id>
- <property
name="name" type="java.lang.String"> - <column
name="name" length="45" not-null="true"
/> - </property>
- <!-- 以下是單向一對多的配置信息-->
- <set
name="users" inverse="false"
cascade="all"> - <key>
- <!-- 指定user表中引用外鍵的是哪一列-->
- <column
name="group_id"/> - </key>
- <!--配置是與哪一個類之間的一對多 -->
- <one-to-many class="com.stream.model.User" />
- </set>
- </class>
- </hibernate-mapping>
在該配置文件中,inverse可以使用默認false,或者顯示指定false,如以上代碼。這樣就指定一對多之間的關系由group這個POJO來維護。在單項一對多關聯中,這一點很重要,下面我們通過測試來說明。cascade="all"指定級聯的之間的等級,它具有如下幾種值:
all : 所有情況下均進行關聯操作。
none:所有情況下均不進行關聯操作。這是默認值。
save-update:在執行save/update/saveOrUpdate時進行關聯操作。
delete:在執行delete時進行關聯操作。
user.hbm.xml文件的配置與User這個類一樣,不需要包含如何關于關聯關系的配置:
- <class name="com.stream.model.User" table="user"
catalog="test"> - <id
name="id" type="java.lang.Integer"> - <column
name="id" /> - <generator
class="identity" /> - </id>
- <property
name="name" type="java.lang.String"> - <column
name="name" length="45" not-null="true"
/> - </property>
- </class>
下面只舉單向一對多關聯保存一例來說明,其他操作類似:
-
- Group group = new Group();
- group.setName("group1");
- User user1 = new User();
- user1.setName("stream");
- User user2 = new User();
- user2.setName("fangqi");
- //添加用戶
- group.getUsers().add(user1);
- group.getUsers().add(user2);
- //開啟事務
- Transaction transaction =session.beginTransaction();
- //保存用戶組
- session.save(group);
- //將緩沖區中的sql送到數據庫中
- session.flush();
- //提交事務
- transaction.commit();
我們沒有顯示的插入user1和uesr2兩條記錄,但是由于我們設置了cascade=all,那么在group表進行任何操作時都會關聯到user表,即在保存group時,也會把user1和user2保存,這就是級聯為我們帶來的好處。
但是,在這里有兩點需要說明的是:
1、如果在Group.hbm.xml映射文件中設置了inverse=true,那么說明這個一對多的關聯關系由多的一方來維護。而在單向的一對多關聯中,“多”的一方完全不知情,所以在保存往user
表中插入的兩條數據,其外鍵group_id這一字段都是為null值。如果user表中group_id是not null的話就會出現如下異常:
org.hibernate.exception.GenericJDBCException: could not insert:
[com.stream.model.User]
....
Caused by: java.sql.SQLException: Field 'group_id' doesn't have a default
value。
異常信息室group_id這個字段沒有設置一個默認值,其實就是我們往group_id這個非空的字段插入了一個null值。
2、如果再Group.hbm.xml映射文件中設置inverse=false,或者不設置該屬性,即表示由自身來維護這個關聯關系。但在保存group后,會先將user1和user2插入到數據庫,并且group_id的值都為null。然后再接著兩條update語句,將這兩天記錄的group_id字段值設置為前面插入的group的id。同樣的如果user
表中group_id字段是非空的,仍然會出現上面的異常。
---------------------------------------------單向一對多的關聯完畢----------------------------------------------------------