HIbernate学习笔记(六) 关系映射之多对多
六、多对多 - 单向
Ø 一般的设计中,多对多关联映射,需要一个中间表
Ø Hibernate会自动生成中间表
Ø Hibernate使用many-to-many标签来表示多对多的关联
Ø 多对多的关联映射,在实体类中,跟一对多一样,也是用集合来表示的。
(一) 实例场景:
用户与他的角色(一个用户拥有多个角色,一个角色还可以属于多个用户)
(二) 对象模型:
(三) 关系模型:
(四) 实体类
Role实体类:
public class Role {
private int id;
private String name;
public int getId() return id;}
public void setId(int id) {this.id = id;}
public String getName() {return name;}
public void setName(Stringname) { this.name = name;}}
User实体类:
public class User {
private int id;
private String name;
private Set<User> roles = newHashSet<User>();// Role对象的集合
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getName() {return name;}
public void setName(Stringname) {this.name = name;}
public Set<User>getRoles() {return roles;}
public voidsetRoles(Set<User> roles) {this.roles = roles; }
(五) xml方式:映射
Role映射文件:
<class name="com.wjt276.hibernate.Role" table="t_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
</class>
User映射文件:
<class name="com.wjt276.hibernate.User" table="t_user">
<id name="id"column="id">
<generator class="native"/>
</id>
<property name="name"/>
<!--使用<set>标签映射集合(set),标签中的name值为对象属性名(集合roles),而使用table属性是用于生成第三方表名称,例:table="t_user_role",但是第三方面中的字段是自动加入的,作为外键分别指向其它表。
所以表<key>标签设置,例:<key column="userid"/>,意思是:在第三方表(t_user_role)中加入一个外键并且指向当前的映射实体类所对应的表(t_user).使用<many-to-many>来指定此映射集合所对象的类(实例类),并且使用column属性加入一个外键指向Role实体类所对应的表(t_role) -->
<setname="roles" table="t_user_role">
<key column="userid"/>
<many-to-many class="com.wjt276.hibernate.Role" column="roleid"/>
</set>
</class>
(六) annotation注解方式
注意:因为是多对多单向(当然用户拥有多个角色,一个角色也可属性多个用户,但这里角色看不到用户),所以角色只需要正常注解就可以了,
现在要使用@ManyToMany来注解多对多的关系,并使用@JoinTabel来注解第三方表的名称,再使用joinColumns属性来指定当前对象在第三方表中的字段名,并且这个字段会指向当前类相对应的表,最后再用inverseJoinColumns来指定当前类持有引用的实体类在第三方表中的字段名,并且指向被引用对象相对应的表,如下:
@Entity
public class User {
private int id;
private String name;
private Set<User> roles = new HashSet<User>();// Role对象的集合 @Id
@GeneratedValue
public int getId() {return id;}
@ManyToMany
@JoinTable(name="u_r",//使用@JoinTable标签的name属性注解第三方表名称
joinColumns={@JoinColumn(name="userId")},
//使用joinColumns属性来注解当前实体类在第三方表中的字段名称并指向该对象
inverseJoinColumns={@JoinColumn(name="roleId")}
//使用inverseJoinColumns属性来注解当前实体类持有引用对象在第三方表中的字段名称并指向被引用对象表
)
public Set<User> getRoles() {return roles;}
(七) 生成SQL语句
create table t_role (id integer not null auto_increment, namevarchar(255), primary key (id))
create table t_user (id integer not null auto_increment, namevarchar(255), primary key (id))
create table t_user_role (userid integer not null, roleid integer notnull, primary key (userid, roleid))
alter table t_user_role add index FK331DEE5F1FB4B2D4 (roleid), add constraint FK331DEE5F1FB4B2D4 foreign key (roleid) referencest_role (id)
alter table t_user_role add index FK331DEE5F250A083E(userid), add constraint FK331DEE5F250A083E foreign key (userid) referencest_user (id)
注:根据DDL语句可以看出第三方表的主键是一个复合主键(primary key (userid, roleid)),也就是说记录不可以有相同的数据。
(八) 数据库表及结构:
(九) 多对多关联映射 单向数据存储:
session = HibernateUtils.getSession();
tx =session.beginTransaction();
Role r1 = new Role();
r1.setName("数据录入人员");
session.save(r1);
Role r2 = new Role();
r2.setName("商务主管");
session.save(r2);
Role r3 = new Role();
r3.setName("大区经理");
session.save(r3);
User u1 = new User();
u1.setName("10");
Set<Role>u1Roles = new HashSet<Role>();
u1Roles.add(r1);
u1Roles.add(r2);
u1.setRoles(u1Roles);
User u2 = new User();
u2.setName("祖儿");
Set<Role>u2Roles = new HashSet<Role>();
u2Roles.add(r2);
u2Roles.add(r3);
u2.setRoles(u2Roles);
User u3 = new User();
u3.setName("成龙");
Set<Role>u3Roles = new HashSet<Role>();
u3Roles.add(r1);
u3Roles.add(r2);
u3Roles.add(r3);
u3.setRoles(u3Roles);
session.save(u1);
session.save(u2);
session.save(u3);
tx.commit();
发出SQL语句:
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_role (name) values (?)
Hibernate: insert into t_user (name) values (?)
Hibernate: insert into t_user (name) values (?)
Hibernate: insert into t_user (name) values (?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
Hibernate: insert into t_user_role (userid, roleid)values (?, ?)
注:前三条SQL语句,添加Role记录,第三条到第六条添加User,最后7条SQL语句是在向第三方表(t_user_role)中添加多对多关系(User与Role关系)
(十) 多对多关联映射 单向数据加载:
session =HibernateUtils.getSession();
tx =session.beginTransaction();
User user =(User)session.load(User.class, 1);
System.out.println("user.name=" + user.getName());
for(Iterator<Role> iter = user.getRoles().iterator();iter.hasNext();){
Rolerole = (Role) iter.next();
System.out.println(role.getName());
}
tx.commit();
生成SQL语句:
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_useruser0_ where user0_.id=?
user.name=10
Hibernate: select roles0_.userid as userid1_, roles0_.roleid as roleid1_,role1_.id as id2_0_, role1_.name as name2_0_ from t_user_role roles0_ leftouter join t_role role1_ on roles0_.roleid=role1_.id where roles0_.userid=?
商务主管
数据录入人员
七、 多对多 - 双向
多对多关联映射 双向 两方都持有对象引用,修改对象模型,但数据的存储没有变化。
(一) xml方式:映射
再修改映射文件:
<class name="com.wjt276.hibernate.Role" table="t_role">
<id name="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<!—order-by 属性是第三方表哪个字段进行排序-->
<set name="users" table="t_user_role"order-by="userid">
<key column="roleid"/>
<many-to-many class="com.wjt276.hibernate.User" column="userid"/>
</set> </class>
注:数据的存储与单向一样。但一般维护这个多对多关系,只需要使用一方,而使另一方维护关系失效。
总结:
<!— order-by 属性是第三方表哪个字段进行排序-->
<set name="users" table="t_user_role"order-by="userid">
<key column="roleid"/>
<many-to-many class="com.wjt276.hibernate.User" column="userid"/>
</set>
Ø table属性值必须和单向关联中的table属性值一致
Ø <key>中column属性值要与单向关联中的<many-to-many>标签中的column属性值一致
Ø 在<many-to-many>中的column属性值要与单向关联中<key>标签的column属性值一致。
(二) annotation注解方式
多对多关联映射 双向 两方都持有对象引用,修改对象模型,但数据的存储没有变化
只需要修改注解映射就可以了。
User实体类注解没有变化和单向一样:
@Entity
public class User {
private int id;
private Set<User> roles = new HashSet<User>();// Role对象的集合 @Id
@GeneratedValue
public int getId() {return id;}
@ManyToMany
@JoinTable(name="u_r",//使用@JoinTable标签的name属性注解第三方表名称
joinColumns={@JoinColumn(name="userId")},//使用joinColumns属性来注解当前实体类在第三方表中的字段名称并指向该对象
inverseJoinColumns={@JoinColumn(name="roleId")}
//使用inverseJoinColumns属性来注解当前实体类持有引用对象在第三方表中的字段名称并指向被引用对象表
)
public Set<User> getRoles() {return roles;}
Role实体类注解也非常的简单:使用@ManyToMany注解,并使用mappedBy属性指定引用对象持有自己的的属性名
@Entity
public class Role {
private int id;
private String name;
private Set<User> users = newHashSet<User>();
@Id
@GeneratedValue
public int getId() {return id; }
@ManyToMany(mappedBy="roles")
public Set<User>getUsers() {return users;}
public voidsetUsers(Set<User> users) {this.users = users; }
多对多关联映射 双向 数据加载
session =HibernateUtils.getSession();
tx =session.beginTransaction();
Role role= (Role)session.load(Role.class, 1);
System.out.println("role.name=" + role.getName());
for(Iterator<User> iter = role.getUsers().iterator();iter.hasNext();){
Useruser = iter.next();
System.out.println("user.name=" + user.getName());
}
tx.commit();
生成SQL语句:
Hibernate: select role0_.id as id2_0_, role0_.name as name2_0_ from t_rolerole0_ where role0_.id=?
role.name=数据录入人员
Hibernate: select users0_.roleid as roleid1_, users0_.userid as userid1_,user1_.id as id0_0_, user1_.name as name0_0_ from t_user_role users0_ leftouter join t_user user1_ on users0_.userid=user1_.id where users0_.roleid=?order by users0_.userid
user.name=10
user.name=成龙
HIbernate学习笔记(六) 关系映射之多对多的更多相关文章
- hibernate学习四(关系映射一对一与组件映射)
一.关系映射简介 在数据库中,表与表的关系,仅有外键.但使用hibernate后,为面向对象的编程,对象与对象的关系多样化:如 一对一,一对多,多对多,并具有单向和双向之分. 开始练习前,复制上一次项 ...
- hibernate学习五(关系映射多对一与一对多)
一.多对一 多对一(或者一对多):在学生与老师的情况下,一个老师可以教多个学生,但一个学生只能被教一个老师教: 对于类:在多的那方拥有一的那方的一个实体 二.修改student.java和teache ...
- Hibernate学习(二补充)关系映射----基于外键的双向一对一
刚刚写的是基于外键的单向一对一. 那么双向一对一就是在单向一对一的基础上稍微改动就可以了. account.java和account.hbm.xml都不用变动 只要我们小小的变动address.j ...
- Hibernate学习笔记(六) — Hibernate的二级缓存
我们知道hibernate的一级缓存是将数据缓存到了session中从而降低与数据库的交互.那么二级缓存呢? 一.应用场合 比方.在12306购票时.须要选择出发地与目的地,假设每点一次都与数据库交互 ...
- Hibernate学习笔记-Hibernate关系映射
1. 初识Hibernate——关系映射 http://blog.csdn.net/laner0515/article/details/12905711 2. Hibernate 笔记8 关系映射1( ...
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- Hibernate学习笔记(一)
2016/4/18 19:58:58 Hibernate学习笔记(一) 1.Hibernate框架的概述: 就是一个持久层的ORM框架. ORM:对象关系映射.将Java中实体对象与关系型数据库中表建 ...
- Hibernate 学习笔记一
Hibernate 学习笔记一 今天学习了hibernate的一点入门知识,主要是配置domain对象和表的关系映射,hibernate的一些常用的配置,以及对应的一个向数据库插入数据的小例子.期间碰 ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- mybatis学习笔记(7)-输出映射
mybatis学习笔记(7)-输出映射 标签: mybatis mybatis学习笔记7-输出映射 resultType 输出简单类型 输出pojo对象和pojo列表 resultMap result ...
随机推荐
- Quartz任务调度快速入门(转)
概述 了解Quartz体系结构 Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述: ●Jo ...
- C++ static、const和static const 以及它们的初始化
转自C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. s ...
- 获取Android系统时间
目的: 输入 2014-09-09 14:02:03 输出 等待:1小时20分 注意: HH:mm:ss 为获取手机 24小时格式的时间 15:03 hh:mm:ss 为12小时模式的时 ...
- 【mysql的设计与优化专题(2)】数据中设计中的范式与反范式
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小.但是有些时候一昧的追求范式减少冗余,反而会降低数据读写 ...
- Trainning Guide, Data Structures, Example
最近在复习数据结构,发现这套题不错,题目质量好,覆盖广,Data Structures部分包括Example,以及简单,中等,难三个部分,这几天把Example的做完了, 摘要如下: 通过这几题让我复 ...
- strcpy函数的C/C++实现
2013-07-05 14:07:49 本函数给出了几种strcpy与strncpy的实现,有ugly implementation,也有good implementation.并参考标准库中的imp ...
- linux中应用程序main函数中没有开辟进程的,它应该在那个进程中运行呢?
1.main函数是一个进程还是一个线程? 不知道你是用c创建的,还是用java创建的. 因为它们都是以main()做为入口开始运行的. 是一个线程,同时还是一个进程. 在现在的操作系统中,都是多线程的 ...
- fork()和vfork()区别
fork创建进程,子进程和父进程不一定谁先执行 vfork创建的进程,不分配新的资源,子进程用父进程相应的资源,且子进程先执行. 用vfork创建的进程,资源共享,那么,数据是不是不牵扯通信间的机制, ...
- NFC(7)向NFC硬件写入数据的两个示例(nfc硬件启动android应用,nfc硬件打开uri)
向NFC标签写入数据基本步骤 1,获取Tag对象 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 2,判断NFC标签的数据类型(通 ...
- 武汉北大青鸟解读2016年10大IT热门岗位
武汉北大青鸟解读2016年10大IT热门岗位 2016年1月5日 13:37 北大青鸟 这是IT从业者的辉煌时代,IT行业的失业率正处在历史的低点,而且有的岗位——例如网络和安全工程师以及软件开发人员 ...