Hibernate多表映射
Posted 海盗屋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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多表映射的主要内容,如果未能解决你的问题,请参考以下文章