Hibernate多表映射(三)
一对多|多对一
一个分类对应多个商品,一个商品只属于一个分类
创建分类表 products用set装,set特点值不能够重复
package com.hibernate.domain; import java.util.HashSet;
import java.util.Set; public class Category {
private Integer cid;
private String cname; private Set<Product> products = new HashSet<Product>(); public Integer getCid() {
return cid;
} public void setCid(Integer cid) {
this.cid = cid;
} public String getCname() {
return cname;
} public void setCname(String cname) {
this.cname = cname;
} public Set<Product> getProducts() {
return products;
} public void setProducts(Set<Product> products) {
this.products = products;
} }
创建商品表 category表示所属分类
package com.hibernate.domain;
public class Product {
private Integer pid;
private String pname;
private Category category;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
配置映射关系
Category.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hibernate.domain">
<class name="Category" table="Category">
<id name="cid" column="cid">
<generator class="native"/>
</id>
<property name="cname"/>
<!--配置一对多关系
set表示所有products
name 实体类中 商品集合属性
-->
<set name="products">
<!--column 外键名 -->
<key column="cpid"></key>
<one-to-many class="Product"></one-to-many>
</set>
</class>
</hibernate-mapping>
Product.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hibernate.domain">
<class name="Product" table="Product">
<id name="pid">
<generator class="native"/>
</id>
<property name="pname"/> <!--配置多对一 所属分类
name 分类属性
class 分类全路径
column 外键名称 要与 一对多设置的外键一样
-->
<many-to-one name="category" class="Category" column="cpid"></many-to-one>
</class>
</hibernate-mapping>
配置全局映射hibernate.cfg.xml
<mapping resource="com/hibernate/domain/Category.hbm.xml"></mapping>
<mapping resource="com/hibernate/domain/Product.hbm.xml"></mapping>
插入
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
Category category = new Category();
category.setCname("产品分类");
Product p1 = new Product();
p1.setPname("产品1");
p1.setCategory(category);
Product p2 = new Product();
p2.setPname("产品2");
p2.setCategory(category);
category.getProducts().add(p1);
category.getProducts().add(p2);
session.save(category);
session.save(p1);
session.save(p2);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
为已有分类追加商品
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
//获得已有分类对象
Category category = session.get(Category.class,1);
Product p = new Product();
p.setCategory(category);
p.setPname("小米电脑");
category.getProducts().add(p);
session.save(p);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
移除分类下的商品 (将商品的外键设置为null 并没有删除)
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
//获得已有分类对象
Category category = session.get(Category.class,1);
Product p = session.get(Product.class,2);
category.getProducts().remove(p);
p.setCategory(null);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
cascade级联操作
级联保存更新 只保存分类 自动把产品也保存
首先配置category.hbm.xml
<hibernate-mapping package="com.hibernate.domain">
<class name="Category" table="Category">
...
<!--级联操作:cascade
save-update:级联保存更新
delete:级联删除
all:save-update+delete -->
<set name="products" cascade="save-update">
<key column="cpid"></key>
<one-to-many class="Product"></one-to-many>
</set>
</class>
</hibernate-mapping>
编辑代码 只需要save 分类即可
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
Category category = new Category();
category.setCname("产品分类1");
Product p1 = new Product();
p1.setPname("产品11");
p1.setCategory(category);
Product p2 = new Product();
p2.setPname("产品22");
p2.setCategory(category);
category.getProducts().add(p1);
category.getProducts().add(p2);
session.save(category);
//session.save(p1);
//session.save(p2);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
级联删除 配置hbm.xml 为delete
<hibernate-mapping package="com.hibernate.domain">
<class name="Category" table="Category">
。。。
<!--级联操作:cascade
save-update:级联保存更新
delete:级联删除
all:save-update+delete-->
<set name="products" cascade="delete">
<key column="cpid"></key>
<one-to-many class="Product"></one-to-many>
</set>
</class>
</hibernate-mapping>
编写删除代码 该分类下的产品都将被删除
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
Category category = session.get(Category.class,4);
session.delete(category);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
cascade="all" 就是 添加 修改 删除时 不用save 商品 直接操作分类即可
在产品的配置文件中 也可以设置 many-to-one cascade="save-update" 操作时 就是不用操作分类表了
作用:简化操作,如果一定要用就用save-update,不要用delete。
inverse属性
关系维护,在保存时,两方都会维护外键关系,存在多余的维护关系语句。
上面保存分类和商品时 生成的sql语句如下:
Hibernate: insert into Category (cname) values (?)
Hibernate: insert into Product (pname, cpid) values (?, ?)
Hibernate: insert into Product (pname, cpid) values (?, ?)
Hibernate: update Product set cpid=? where pid=?
Hibernate: update Product set cpid=? where pid=?
配置Category.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hibernate.domain">
<class name="Category" table="Category">
。。。
<!-- inverse:配置关系是否维护
true:不维护
false:维护(默认值)-->
<set name="products" inverse="true">
<key column="cpid"></key>
<one-to-many class="Product"></one-to-many>
</set>
</class>
</hibernate-mapping>
修改配置文件后 重新运行程序 sql语句如下:
Hibernate: insert into Category (cname) values (?)
Hibernate: insert into Product (pname, cpid) values (?, ?)
Hibernate: insert into Product (pname, cpid) values (?, ?)
inverse的作用就是 优化性能,此配置只能设置一的一方放弃维护关系,多的一方不可以放弃维护关系。
多对多
一个用户可以有很多角色,一个角色可以有很多用户。
使用中间表,至少两列,都是外键,分别引用其他两张表的主键
创建user表 set装role集合
package com.hibernate.domain; import java.util.HashSet;
import java.util.Set; public class User {
private Integer uid;
private String uname;
private Set<Role> roles = new HashSet<Role>(); public Integer getUid() {
return uid;
} public void setUid(Integer uid) {
this.uid = uid;
} public String getUname() {
return uname;
} public void setUname(String uname) {
this.uname = uname;
} public Set<Role> getRoles() {
return roles;
} public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
创建role表 set装user
package com.hibernate.domain; import java.util.HashSet;
import java.util.Set; public class Role {
private Integer rid;
private String rname;
private Set<User> users = new HashSet<User>(); public Integer getRid() {
return rid;
} public void setRid(Integer rid) {
this.rid = rid;
} public String getRname() {
return rname;
} public void setRname(String rname) {
this.rname = rname;
} public Set<User> getUsers() {
return users;
} public void setUsers(Set<User> users) {
this.users = users;
} }
编写 User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hibernate.domain">
<class name="User" table="User">
<id name="uid">
<generator class="native"/>
</id>
<property name="uname"/>
<!--多对多关系
table:中间表名
-->
<set name="roles" table="User_Role">
<!--column 别人引入我的外键 uid -->
<key column="uid"></key>
<!--column 另外一方的外键 rid -->
<many-to-many class="Role" column="rid"></many-to-many>
</set>
</class>
</hibernate-mapping>
编写role.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.hibernate.domain">
<class name="Role" table="Role">
<id name="rid">
<generator class="native"/>
</id>
<property name="rname"/>
<set name="users" table="User_Role">
<key column="rid"></key>
<many-to-many column="uid" class="User"></many-to-many>
</set>
</class>
</hibernate-mapping>
最后写入全局配置中
<mapping resource="com/hibernate/domain/User.hbm.xml"></mapping>
<mapping resource="com/hibernate/domain/Role.hbm.xml"></mapping>
添加操作
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
User u1 = new User();
u1.setUname("武大郎");
User u2 = new User();
u2.setUname("武松");
Role r1 = new Role();
r1.setRname("卖烧饼");
Role r2 = new Role();
r2.setRname("武都头");
u1.getRoles().add(r1);
u2.getRoles().add(r2);
//武松帮大哥卖卖烧饼
u2.getRoles().add(r2);
r1.getUsers().add(u1);
r1.getUsers().add(u2);
r2.getUsers().add(u2);
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
虽然会插入数据成功 但是运行后会报错:could not execute statement(插入主键报错),是因为双方都维护关系导致。
解决办法1: 去掉一方的维护关系
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
User u1 = new User();
u1.setUname("武大郎");
User u2 = new User();
u2.setUname("武松");
Role r1 = new Role();
r1.setRname("卖烧饼");
Role r2 = new Role();
r2.setRname("武都头");
u1.getRoles().add(r1);
u2.getRoles().add(r2);
//武松帮大哥卖卖烧饼
u2.getRoles().add(r2);
// r1.getUsers().add(u1);
// r1.getUsers().add(u2);
// r2.getUsers().add(u2);
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
解决办法2:
修改配置文件,选择一方不维护关系 加入节点inverse=true
<hibernate-mapping package="com.hibernate.domain">
<class name="User" table="User">
<id name="uid">
<generator class="native"/>
</id>
<property name="uname"/>
<!--user一方 放弃维护 -->
<set name="roles" table="User_Role" inverse="true">
<key column="uid"></key>
<many-to-many class="Role" column="rid"></many-to-many>
</set>
</class>
</hibernate-mapping>
然后把注释放开 ,运行 也不会报错了。
级联操作cascade
编辑user.hbm.xml配置文件
<hibernate-mapping package="com.hibernate.domain">
<class name="User" table="User">
<id name="uid">
<generator class="native"/>
</id>
<property name="uname"/>
<!--user一方 放弃维护 -->
<set name="roles" table="User_Role" inverse="true" cascade="save-update">
<key column="uid"></key>
<many-to-many class="Role" column="rid"></many-to-many>
</set>
</class>
</hibernate-mapping>
剩下联行save而已
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
User u1 = new User();
u1.setUname("武大郎");
User u2 = new User();
u2.setUname("武松");
Role r1 = new Role();
r1.setRname("卖烧饼");
Role r2 = new Role();
r2.setRname("武都头");
u1.getRoles().add(r1);
u2.getRoles().add(r2);
//武松帮大哥卖卖烧饼
u2.getRoles().add(r2);
r1.getUsers().add(u1);
r1.getUsers().add(u2);
r2.getUsers().add(u2);
session.save(u1);
session.save(u2);
//session.save(r1);
//session.save(r2);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
只save一方,另一方自动save。
不建议使用 如果非要用就用save-update。
解除权限关系
public class Main {
public static void main(String[] args) {
Session session = HibernateUtils.getCurrentSession();
Transaction trans = session.beginTransaction();
try {
User u = session.get(User.class,2);
//武松不想卖烧饼了
Role r = session.get(Role.class,1);
r.getUsers().remove(u);
trans.commit();
} catch (Exception ex){
System.out.println(ex);
trans.rollback();
}
}
}
Hibernate多表映射(三)的更多相关文章
- Hibernate单表映射学习笔记之一——hibernalnate开发环境配置
1.什么是ORM? Object/Relationship Mapping:对象/关系映射 2.写SQL语句不好之处: (1)不同数据库使用的SQL语法不同(PL/SQL.T/SQL) (2)同样的功 ...
- Hibernate 表映射 主键生成策略与复合主键
主要分析三点: 一.数据表和Java类的映射 : 二.单一主键映射和主键的生成策略 : 三.复合主键的表映射 : 一.数据表和Java类的映射 Hibernate封装了数据库DDL语句,只需要将数据 ...
- 同一个数据库实例,不同用户下多表创建视图,Hibernate完毕ORM映射,Spring整合,后台实现
1.同一个数据库实例.同用户,多表创建视图 2.同一个数据库实例,不同用户下.多表创建视图 3.同一个数据库,不同数据库实例,多表创建视图 4.不同类型数据库,多表创建视图 1.同一个数据库实例.同用 ...
- hibernate之单表映射
目录 第一章 Hibernate初识 1-1 课程介绍 1-2 什么是ORM 1-3 Hibnerate简介 1-4 开发前的准备 1-5 编写第一个Hibernate例子 1-6 创建hiberna ...
- 怎么让Intellj Idea 把数据库的表映射成hibernate的domain对象
步骤如下: 第一步:连接数据源: 点击:idea右边的database.如下图所示: 或者你依次点击:view-->Tool windows--->database 然后你将看在如下点击下 ...
- Hibernate初探之单表映射——Hibernate概念及插件的安装
什么是ORM ORM(Object/Relationship Mapping):对象/关系映射 为什么要有ORM? 利用面向对象思想编写的数据库应用程序最终都是把对象信息保存在关系型数据库中,于是要编 ...
- hibernate(3) —— 关系映射
hibernate中关系映射指的是实体类与实体类间的关系.和数据库中表与表之间的关系类似,有一对一,多对一,一对多,多对多四种映射关系. 一:一对一映射 两个对象之间是一对一的关系,如人和身份证之间是 ...
- Hibernate的关联映射
单向N-1关联 <many-to-one> 单向N-1关系,比如多个人对应同一个住址,只需要从人实体端找到对应的住址实体,无须关系某个地址的全部住户.程序在N的一端增加一个属性,该属性引用 ...
- Hibernate配置文件和映射元素解释
象关系的映射是用一个XML文档来说明的.映射文档可以使用工具来生成,如XDoclet,Middlegen和AndroMDA等.下面从一个映射的例子开始讲解映射元素. AD:干货来了,不要等!WOT20 ...
随机推荐
- JDK5-8特性归纳
jdk5新特性1.自动装箱和拆箱2.枚举3.静态导入4.可变参数5.內省 是Java语言对Bean类属性.事件的一种缺省处理方法.例如类A中有属性那么,那我们可以通过getName,setName ...
- (蓝桥)2017C/C++A组第一题迷宫
#include<iostream> #include<memory.h> using namespace std; char mi[10][10] ; int visited ...
- kafka监控工具kafka-manager
1.几个kafka监控工具 Kafka Web Console:监控功能较为全面,可以预览消息,监控Offset.Lag等信息,但存在bug,不建议在生产环境中使用. Kafka Manager:偏向 ...
- Likecloud-吃、吃、吃(洛谷 1508)
题目背景 问世间,青春期为何物? 答曰:“甲亢,甲亢,再甲亢:挨饿,挨饿,再挨饿!” 题目描述 正处在某一特定时期之中的李大水牛由于消化系统比较发达,最近一直处在饥饿的状态中.某日上课,正当他饿得头昏 ...
- npm install socket.io 提示缺少"VCBuild.exe"
http://www.cnblogs.com/yangzhx/p/4648501.html https://www.v2ex.com/t/120493
- 51nod——T1267 4个数和为0
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1267 题目描述 给出N个整数,你来判断一下是否能够选出4个数,他们的和 ...
- HDU 5239 上海大都会 D题(线段树+数论)
打表,发现规律是存在一定次数(较小)后,会出现a=(a*a)%p.可以明显地发现本题与线段树有关.设置标记flag,记录本段内的数是否均已a=a*a%p.若是,则不需更新,否则更新有叶子结点,再pus ...
- 使用python获取CPU和内存信息的思路与实现(linux系统)
linux里一切皆为文件,在linux/unix的根文件夹下,有个/proc文件夹,这个/proc 是一种内核和内核模块用来向进程(process)发送信息的机制(所以叫做"/proc&qu ...
- js 推断字符串是否包括某字符串
var Cts = "bblText"; if(Cts.indexOf("Text") > 0 ) { alert('Cts中包括Text字符串'); } ...
- 最新版本号cocos2d­2.0­x­2.0.2使用新资源载入策略!不再沿用-hd、-
前段时间cocos2dx更新了最新版本号cocos2d2.0x2.0.2.也从这个版本号開始对于资源载入与管理都改变了策略. 在之前的载入方式都是通过沿用与cocos2d-iphone一样 ...