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 ...
随机推荐
- jq购物车结算功能
css *{font-style: normal} .gw{margin: 8px;} .gw::after{display: block;clear: both;content: '';margin ...
- 详解proxy_pass、upstream与resolver
详解proxy_pass.upstream与resolver boldcautious 关注 2018.06.04 10:48 字数 1204 阅读 1434评论 0喜欢 2 应用场景 这里列举几个应 ...
- Async/await语法糖实现(Generator)
// generator也是一种迭代器(Iterator) 有next方法,并返回一个对象{value:...,done:...} function run(generatorFunction) { ...
- Fang Fang HDU - 5455 (思维题)
Fang Fang says she wants to be remembered. I promise her. We define the sequence FF of strings. F0 = ...
- [Luogu] P3413 萌数
题目背景 本题由世界上最蒟蒻最辣鸡最撒比的SOL提供. 寂月城网站是完美信息教室的官网.地址:已和谐 . 题目描述 辣鸡蒟蒻SOL是一个傻逼,他居然觉得数很萌! 好在在他眼里,并不是所有数都是萌的.只 ...
- 使用Scrapy爬取图书网站信息
重难点:使用scrapy获取的数值是unicode类型,保存到json文件时需要特别注意处理一下,具体请参考链接:https://www.cnblogs.com/sanduzxcvbnm/p/1030 ...
- MySQL的分组和排序
分组操作 select count(id) from userinfo group by pat(id); -- 聚合函数: --count --max --sum --avg ---如果对于二次函数 ...
- 【Codeforces 429B】Working out
[链接] 我是链接,点我呀:) [题意] 两个人,一个人在左上角,一个人在左下角. 左上角要到右下角去 左下角要到右上角去 只能走到相邻的格子(不能往回走,即一个往右下,一个往右上走) 要求这两个人必 ...
- 使用Eclipse 创建Spring Boot项目
一.为什么要使用 Spring Boot ? Spring Boot解决的问题 (1) Spring Boot使编码变简单 (2) Spring Boot使配置变简单 (3) Spring Boot使 ...
- Nginx不转发http header
使用nginx做http代理时,在Header中使用了一个名为api_key的属性,碰到http header不转发的问题. 问题源码: rc = ngx_http_parse_header_line ...