Hibernate(2)——案例解析(一对多,多对多,一对一),注解

1 一对多 案例解析

1.1 一对多,XML版

映射类的设计:
在这里插入图片描述
①新增:
在这里插入图片描述
发现一个问题,多了一些update语句
通常, 为避免生成冗余SQL方言, 建议把关联关系的维护主动权交给N的一方,这时需要在1方的set元素 inverse=“false”:表示主外键关系由自己维护;
解决的办法:
在这里插入图片描述
②删除
如果在数据库表中没有设置级联,在删除的时候会报错
在这里插入图片描述
解决的办法:
1.在数据库表的外键上设置级联
2.在主键表对应的映射文件的set标签中设置cascade=”delete”
cascade属性有如下取值:
none: 不级联
save-update: 级联保存或更新
merge: 级联保存或更新
delete: 级联删除
all: 包含所有级联行为
在这里插入图片描述
③修改

id不能修改,关联id的时候,通过id查询对象,然后设计对象即可
在这里插入图片描述
④查询
一般查询外键对象信息的同时,查询出关联的主键对象信息
一般查询主键对象信息的同时,不查询出关联的外键对象信息,延迟加载

Hibernate 监听器与拦截器(介绍)

拦截器(Intercept):与Struts2的拦截器机制基本一样,都是一个操作穿过一层层拦截器,每穿过一个拦截器就会触发相应拦截器的事件做预处理或善后处理。

监听器(Listener):其实功能与拦截器类似,但它实现原理不同,它是为每一个事件注册一个或多个监听器,一旦事件发生,则事件源通知所有监听该事件的监听器,然后监听器处理通知(观察者模式)。

以上是老师给的教程,自己写了一个demo,是关于省市县,级联查询的,巩固复习一下,增删改查很简单,就是有下面几个点注意一下:
主表(Provinces):

  1. 实体类中添加Set< Cities >citySet;
  2. XML:配置主键表,name属性(Provinces.hbm.xml)
<set name="citiesSet">
	<key column="provinceid"></key>
	<one-to-many class="com.cn.entity.Cities"/>
</set>

从表(Cities):

  1. 实体类中把关联的键private String provinceid改成private Provinces provinces;
  2. XML:一对多,外键表(Cities.hbm.xml)
<many-to-one name="provinces" class="com.cn.entity.Provinces" column="provinceid">
</many-to-one>

hibernate.cfg.xml:
要映射几个表的xml文件

<mapping resource="mapping/Areas.hbm.xml"/>
<mapping resource="mapping/Cities.hbm.xml"/>
<mapping resource="mapping/Provinces.hbm.xml"/>

1.2 一对多,注解版

  1. 主表(Provinces)

实体类中添加private Set < Cities > citiesSet;

private int id;
private String provinceid;
private String province;
private Set<Cities> citiesSet;
    @OneToMany(mappedBy ="provinces",cascade = {CascadeType.ALL})
    // @JoinColumn(name = "provinceid")
    public Set<Cities> getCitiesSet() {
        return citiesSet;
    }
    //getter,setter...

@Onetomany 的参数:
mappedBy:用于双向关联(两个实体类都写了@manytoone或者@onetomany)时使用,否则会引起数据不一致的问题。
(该属性的值是“多”方class里的“一”方的表名)
fetch:可取的值有FetchType.EAGER和FetchType.LAZY,前者表示主类被加载时加载,后者表示被访问时才会加载
cascade:CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)、CascadeType.ALL(选择全部)
@JoinColumn
与@Column用法相同,区别是@JoinColumn作用的属性必须是实体类

private int id;
    private String provinceid;
    private String province;
    private Set<Cities> citiesSet;
    @OneToMany(mappedBy ="provinces",cascade = {CascadeType.ALL})
    //  @JoinColumn(name = "provinceid")
    public Set<Cities> getCitiesSet() {
        return citiesSet;
    }
    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }
    // getter/setter...
  1. 从表(cities)
    实体类中把关联的键private String provinceid改成private Provinces provinces;
	@ManyToOne(cascade = {CascadeType.ALL})
	@JoinColumn(name = "provinceid") //cities类中对应外键的属性:provinceid
    public Provinces getProvinces() {
        return provinces;
    }
  1. hibernate.cfg.xml
    检查用户名密码,需要映射实体类
<property name="show_sql">true</property>
<property name="format_sql">true</property>

<mapping class="com.cn.entity.Cities"/>
<mapping class="com.cn.entity.Provinces"/>
在开发时用到@OneToMany注解方式遇到错误:

1、要么在属性上添加注解要么在getter方法上添加注解,不能混合使用;
2、遇到异常:Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn错误,主要原因是,mappedBy="parent"和@JoinColumn(name=“parent_id”)不能同时使用

后来发现在3.5.3版本中@JoinColumn与mappingBy是互斥的,之前在hibernate.3.3.2中都是正确无误的,也就是hibernate.3.3.2允许这两个互相存在。
所以,如果升级到hibernate3.5.3想测试成功的话,mappBy=“parent”,就应该去掉,正确的配置应该是这样:
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name=“parent_id”)

2 多对多 案例解析

多对多映射类设计:
在这里插入图片描述

2.1 多对多,XML版本

  1. 下载依赖包(pom.xml)
    hibernate-core,mysql-connector-java
  2. 创建多对多的实体类(Factory.java,Product.java)
public class Factory {                                                                                                                                                                                                                                                                                                                                                                                                    
    private Integer facId;
    private String facName;
    private String facAddres;
    private Set<Product> productSet = new HashSet<>();  //防止空指针
    public Factory() {}
    public Factory(String facName, String facAddres) {
        this.facName = facName;
        this.facAddres = facAddres;
    }
    //getter,setter...
}
public class Product {
    private Integer proId;
    private String proName;
    private Double proPrice;
    private Set<Factory> factorySet = new HashSet<>();//防止空指针
    public Product() {}
    public Product(String proName, Double proPrice) {
        this.proName = proName;
        this.proPrice = proPrice;
    }
    //getter,setter...
}
  1. hibernate配置文件(hibernate.cfg.xml)
<session-factory>
        <property name="connection.url">jdbc:mysql://localhost:3306/crm</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.username">root</property>
        <property name="connection.password">1234</property>
        <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <!-- DB schema will be updated if needed -->
        <!--  update   Position.hbm.xml  与数据库进行对比
         如果没有表就创建表  如果实体有某个字段 数据库里面没有 就新增一个字段
         create  每次启动就新建
         -->
        <property name="hbm2ddl.auto">update</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <mapping resource="mapping/Factory.hbm.xml"/>
        <mapping resource="mapping/Product.hbm.xml"/>
    </session-factory>
  1. 实体类的配置文件
    数据库里面没有表,就自己创建表,关联表也是自动创建出来的:
    Factory.hbm.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.cn.orm.Factory" table="Factory" schema="crm">
        <id name="facId">
            <column name="facId" sql-type="int(11)"/>
            <generator class="native"></generator>
        </id>
        <property name="facName">
            <column name="facName" sql-type="varchar(64)" length="64"/>
        </property>
        <property name="facAddres">
            <column name="facAddres" sql-type="varchar(255)"/>
        </property>
        <!--name:当前属性  table:第三张表,关联关系表 -->
        <set name="productSet" table="product_factory_relation">
            <!-- this  当前 字段名 -->
            <key column="factoryId"></key>
            <!-- class 当前属性的类型  列:对方外键列 -->
            <many-to-many class="com.cn.orm.Product" column="productId">
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

Product.hbm.xml

<hibernate-mapping>
    <class name="com.cn.orm.Product" table="Product" schema="crm">
        <id name="proId">
            <column name="proId" sql-type="int(11)"/>
            <generator class="native"></generator>
        </id>
        <property name="proName">
            <column name="proName" sql-type="varchar(64)" length="64"/>
        </property>
        <property name="proPrice">
            <column name="proPrice" sql-type="double"/>
        </property>
        <set name="factorySet" table="product_factory_relation" >
            <key column="productId"></key>
            <!-- class:当前属性的类型  column:属性关联的外键字段 -->
            <many-to-many class="com.cn.orm.Factory" column="factoryId">
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>
  1. 测试类
    SessionFactoryUtil.java
public class SessionFactoryUtil {//饿√  懒
    private static SessionFactory sessionFactory;
    static{
        //先解析配置文件
        //要写路径   1.没有使用默认名称  2.不在根目录下
        Configuration configuration = new Configuration();
        //用配置问价对象来获得sessionFactory
        sessionFactory = configuration.configure().buildSessionFactory();
    }
    public static SessionFactory getSessionFactory(){
        return  sessionFactory;
    }
}

测试类AppTest.java

public class AppTest {
    Session session;
    //测试方法
   /* @BeforeClass
    public  static  void beforeClass(){}*/
    @Before
    public void before(){
        session = SessionFactoryUtil.getSessionFactory().openSession();
    }
    @After
    public void after(){
        session.close();
    }
    @Test
    public void test(){
        System.out.println("---测试建表---");
    }
    @Test
    public void add() {
        // 创建工厂对象
        Factory factory1 = new Factory("四川皮革厂","金华");
        Factory factory2 = new Factory("温江皮革厂","温江");
        // 商品
        Product product1 = new Product("鳄鱼皮",25.0);
        Product product2 = new Product("牛皮",120.0);
        Product product3 = new Product("皮衣",280.0);
        Product product4 = new Product("牛牛",2220.0);
        // 搭建关系   只需要搭建一方的关系
//        factory1.setProductSet(new HashSet<>());
        factory1.getProductSet().add(product1);
        factory1.getProductSet().add(product2);
        factory2.getProductSet().add(product3);
        factory2.getProductSet().add(product4);
        session.save(factory1);
        session.save(factory2);
        session.save(product1);
        session.save(product2);
        session.save(product3);
        session.save(product4);
        session.beginTransaction().commit();//不写这一句的话就不会添加关联表的数据
    }
    @Test
    public void update() {
        System.out.println();
    }
    @Test
    public void delete() {
        System.out.println();
        // 写出解决方案,在 表示需要 程序维护的时候;关系表不需要业务直接维护,所有 默认 级联 第三张表
        Product product = session.get(Product.class,1);
//        System.out.println("----确定是否延迟加载----");
//        System.out.println(product.getFactorySet().size());
         session.delete(product);
         session.beginTransaction().commit();
    }
}

2.2 多对多 注解版

hibernate.cfg.xml文件添加类:

// .......
<mapping class="com.cn.orm.Factory"></mapping>
<mapping class="com.cn.orm.Idcard"></mapping>
<mapping class="com.cn.orm.Personnel"></mapping>
<mapping class="com.cn.orm.Product"></mapping>

主要是实体类的注解:
Product.java

package com.cn.orm;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Product {
    private int proId;
    private String proName;
    private Double proPrice;
    private Set<Factory> factorySet = new HashSet<>();//预防空指针
    public Product(){}
    public Product(String proName, Double proPrice) {
        this.proName = proName;
        this.proPrice = proPrice;
    }
    @Id
    @Column(name = "proId")
    @GeneratedValue(strategy = GenerationType.IDENTITY)//默认
    public int getProId() {
        return proId;
    }  //setter
    @Basic
    @Column(name = "proName")
    public String getProName() {
        return proName;
    }  //setter
    @Basic
    @Column(name = "proPrice")
    public Double getProPrice() {
        return proPrice;
    }  //setter

    @ManyToMany(targetEntity=Factory.class,mappedBy="productSet") //让对方维护外键表
    @Cascade(CascadeType.ALL)
    public Set<Factory> getFactorySet() {
        return factorySet;
    }	
    public void setFactorySet(Set<Factory> factorySet) {
        this.factorySet = factorySet;
    }
}

Factory.java

	@ManyToMany(targetEntity=Product.class)
    // 使用JoinTabl来描述中间表,并描述中间表中外键与factory,product的映射关系
    // joinColumns它是用来描述factory与中间表中的映射关系
    // inverseJoinColums它是用来描述product与中间表中的映射关系
    @JoinTable(name="product_factory_relation",
            joinColumns={@JoinColumn(name="factoryId",referencedColumnName="facId")},
            inverseJoinColumns={@JoinColumn(name="productId",referencedColumnName="proId")})
    public Set<Product> getProductSet() {
        return productSet;
    }

3 一对一 案例解析

3.1 xml版本

主:实体类Idcard.java

public class Idcard {
    private Integer no;
    private String cardId;
    private String name;
    private Date birthday;
    private Personnel personnel;
    //getter,setter......
}

Idcard.hbm.xml

<class name="com.cn.orm.Idcard" table="Idcard" schema="crm">
        <id name="no">
            <column name="no" sql-type="int(11)"/>
            <generator class="native"></generator>
        </id>
        <property name="name">
            <column name="name" sql-type="varchar(64)" length="64"/>
        </property>
        <property name="cardId">
        <column name="cardId" sql-type="varchar(18)"/>
        </property>
        <property name="birthday">
            <column name="birthday" sql-type="date"/>
        </property>
        <!--一对一-->
        <!--属性 对方的与当前 this  关联的属性名称  property-ref -->
        <one-to-one name="personnel" class="com.cn.orm.Personnel" property-ref="idcard">
        </one-to-one>
    </class>

从:实体类Personnel.java

public class Personnel {
    private Integer id;
    private Double height;
    private Double weight;
    private String headPath; // 头像路径
    private Idcard idcard;
    //getter,setter......
}

Personnel.hbm.xml

<class name="com.cn.orm.Personnel" table="Personnel" schema="crm">
        <id name="id">
            <column name="id" sql-type="int(11)"/>
            <generator class="native"></generator>
        </id>
        <property name="height">
            <column name="height" sql-type="double" />
        </property>
        <property name="weight">
            <column name="weight" sql-type="double" />
        </property>
        <property name="headPath">
        <column name="headPath" sql-type="varchar(225)"/>
        </property>
        <!--一对一  column  外键字段列明-->
        <many-to-one name="idcard"  class="com.cn.orm.Idcard"
            column="cardNo" unique="true" not-null="true">   
        </many-to-one>
    </class>

测试类

3.2 一对一 注解版

Idcard.java

	private int no;
    private String name;
    private String cardId;
    private Date birthday;
    private   Personnel  personnel;

    @Id
    @Column(name = "no")
    @GeneratedValue(strategy = GenerationType.IDENTITY)//默认
    public int getNo() {
        return no;
    }
    // ......
    @OneToOne(targetEntity = Personnel.class)
    @JoinColumn(name="id",referencedColumnName = "id",unique = true)
    public Personnel getPersonnel() {
        return personnel;
    }

Personnel.java

private int id;
    private Double height;
    private Double weight;
    private String headPath;
    private  Idcard idcard;
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)//默认
    public int getId() {
        return id;
    }
    // ......
    @OneToOne(targetEntity = Idcard.class,mappedBy = "personnel")
    public Idcard getIdcard() {
        return idcard;
    }

测试类

注解

在这里插入图片描述
在这里插入图片描述
1.@Entity
表示这个类是一个映射到数据库中的实体类,可以修改名字
2.@Id
表示这一列为主键列
3.@GeneratedValue
设置主键生成策略,默认是自动增长
4.@Column
设置次列的各种属性:名字,类型,是否非空,是否唯一等等
5.Temporal
设置日期格式
6.@OneToOne
加在映射对象属性上面。表示关系是一对一。
如果加在主键表的对应的外键对象,要加入mappedBy,类似于property-ref
如果加在外键表对应的主键对象上面,需要再配置@JoinColumn(name=”外键列的名字”),如果不设置,默认是表名_Id
7.@ManyToOne
配置在外键表对应的主键属性头部
8.@OneToMany
配置在主键表对应的键属性头部
11. @JoinColumn
设置外键
9.@ManyToMany
两个主键表都会加上。任选一方加入mapperBy属性
10.@JoinTable
为了解决多对多中间表名字和列名的问题,可以在这个注解中配置
11.@Cache
设置缓存

注意:
1.from 名字
如果注解修改了表名,from 表名
如果没有,from 类名
2.级联删除
cascade = CascadeType.ALL cascade = CascadeType.REMOVE
一般加在主表对应的外键属性上面
3.fetch查询
需要自己查询默认的属性
EAGER:查询对象的时候,将关联对象也查询出来
LAZY:查询对象的时候,不查询关联对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值