• 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();
            }
        }
    }
  • 相关阅读:
    【WebTerminal】gotty工具
    【Java】15分钟快速体验阿里Java诊断工具Arthas
    【K8S】helm chart多环境部署最佳实践-示例
    mysql-linux定时备份mysql数据库
    Mockito-简单使用使用
    EasyMock 简单使用
    SpringDataJpa学习
    js-重写jquery的ajax中的内容
    shiro-过滤器
    hadoop ha 读取 activce状态的活动节点
  • 原文地址:https://www.cnblogs.com/baidawei/p/9063478.html
Copyright © 2020-2023  润新知