我们学习了hibernate的一对一和一对多,下面就剩下一个多对多啦,这次我们就来学习一下它的多对多关联映射。
废话不多说,直接上代码:
这次我们举的例子是Group和Role,一般情况下,我们一个组可以对应多个角色,同时一个角色也可以对应多个组。
先看一下实体类代码:
public class TGroup implements Serializable{
private static final long serialVersionUID = 1L;
private int id;
private String name;
private Set<TRole> roles = new HashSet<TRole>();
//省略Get/Set方法
}
public class TRole implements Serializable{
private static final long serialVersionUID = 1L;
private int id;
private String name;
private Set<TGroup> groups = new HashSet<TGroup>();
//省略Get/Set方法
}
简单的实体类,在看映射文件之前我们需要说明一下多对多映射与之前讲的映射不同的地方。
多对多映射需要用到另外一张关联表,用以关联两个表的ID。
我们看一下映射文件:
<hibernate-mapping package="org.hibernate.tutorial.domain7"> <class name="TGroup" table="t_group" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <set name="roles" table="t_group_role" lazy="false" cascade="save-update"> <key column="group_id"/> <many-to-many class="TRole" column="role_id" /> </set> </class> </hibernate-mapping>
这里我们用到了一个中间表,t_group_role,在该表中指定了此表对应的列group_id,另外一个不同的地方就是我们设置了lazy="false",这个属于懒惰加载机制的内容,我们以后会讲到。这里先大概了解一下,把它设为false(也是默认值),它表明这个实体会在hibernate加载的时候全部加载进来。如果设为true,则表明当我们需要访问到此属性时才进行取出(这里的访问是指调用get方法等)。
我们再看一下另外一个映射文件:
<hibernate-mapping package="org.hibernate.tutorial.domain7"> <class name="TRole" table="t_role" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <set name="groups" table="t_group_role" lazy="false" inverse="true" cascade="save-update"> <key column="role_id"/> <many-to-many class="TGroup" column="group_id" /> </set> </class> </hibernate-mapping>
两个表的映射文件变化不大,主要是这里有inverse="true"表明把插入权交给TGroup,即当TGroup进行保存的时候,会把user_id和group_id同时进行插入。
下面我们看一下测试类,由于是多对多关联,类会比较长:
public static void main(String[] args) {
Configuration cfg = new Configuration().configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
TRole role1 = new TRole();
role1.setName("role1");
TRole role2 = new TRole();
role2.setName("role2");
TRole role3 = new TRole();
role3.setName("role3");
TGroup group1 = new TGroup();
group1.setName("group1");
TGroup group2 = new TGroup();
group2.setName("group2");
TGroup group3 = new TGroup();
group3.setName("group3");
role1.getGroups().add(group1);
role1.getGroups().add(group2);
role2.getGroups().add(group2);
role2.getGroups().add(group3);
role3.getGroups().add(group1);
role3.getGroups().add(group2);
group1.getRoles().add(role1);
group1.getRoles().add(role2);
group2.getRoles().add(role2);
group2.getRoles().add(role3);
group3.getRoles().add(role2);
group3.getRoles().add(role3);
session.save(role1);
session.save(role2);
session.save(role3);
session.save(group1);
session.save(group2);
session.save(group3);
session.getTransaction().commit();
session.close();
}
运行此测试类,我们可以看到输出的语句为:
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
插入的语句与我们前面通过add有关联,这个可以自己仔细看一下,只是数数的问题而已。
也许,某些童鞋看到这里,又会想想说如果去掉inverse="true"会是什么情况呢?
那么我们来试一下:
把inverse="true"去掉,然后再运行测试类:我们同样看到插入语句,但紧跟着的是异常,看看是什么异常:
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_group_role (role_id, group_id) values (?, ?)
Hibernate: insert into t_group_role (role_id, group_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (group_id, role_id) values (?, ?)
Hibernate: insert into t_group_role (role_id, group_id) values (?, ?)
Hibernate: insert into t_group_role (role_id, group_id) values (?, ?)
22:23:46,062 ERROR JDBCExceptionReporter:101 - Duplicate entry '13-14' for key 'PRIMARY'
22:23:46,064 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
重复的记录,这个错误看来是插入了两条重复的记录,肯定两个字段都相同,而后一个异常是因为找不到需要更新的记录。这个的原因是因为我们没有指定inverse="true",那么两个表都对t_gropu_role有责任,就因为这样,它们都会进行插入,这也就超成了前面的错误,而后面的错误更多的是由前面的错误所引起的。