Hibernate

文章目录

Hibernate 的框架概述

什么是框架

框架,指的是软件半成品,已经完成了部分功能。

EE 的三层架构

在这里插入图片描述

Hibernate 概述

一个持久层的 ORM 框架。

什么是 ORM

ORM : object relation mapping(对象关系映射)。指的是将一个 Java 中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。
在这里插入图片描述

创建第一个 Hibernate 程序

下载 Hibernate 的开发环境
解压 Hibernate

在这里插入图片描述

  • documentation 【Hibernate 开发文档】
  • lib
    1. required 【Hibernate 开发的必须依赖包】
    2. optional 【Hibernate 开发的可选 jar 包】
  • project 【Hibernate 提供的项目】
创建一个项目,引入 jar 包
  1. 数据库驱动包
  2. Hibernate 开发必须的 jar 包
  3. Hibernate 开发的日志记录包
创建表
CREATE TABLE `cst_customer` (
  `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
  `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
  `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
  `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
  `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
  `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
创建实体类
public class Customer {
    private Long cust_id;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;
创建映射(******)

映射需要通过一个 xml 的配置文件来完成,这个配置文件可以任意命名,但是尽量统一命名规范(类名.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="hibernate_demo1.Customer" table="cst_customer">
        <!--建立类中的属性与表中的逐渐对应-->
        <id name="cust_id" column="cust_id">
            <generator class="native"/>
        </id>

        <!--建立类中的普通属性和表的字段的对应-->
        <property name="cust_name" column="cust_name"/>
        <property name="cust_source" column="cust_source"/>
        <property name="cust_industry" column="cust_industry"/>
        <property name="cust_level" column="cust_level"/>
        <property name="cust_phone" column="cust_phone"/>
        <property name="cust_mobile" column="cust_mobile "/>
    </class>
</hibernate-mapping>
创建一个 Hibernate 的核心配置文件(******)

Hibernate 核心配置文件的名称:hibernate.cfg.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!--连接数据库的基本参数-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">1183787376</property>
        <!--配置Hibernate 的方言-->

        <!--可选配置===============-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!--打印sql-->
        <property name="hibernate.show_sql">true</property>
        <!--格式化sql-->
        <property name="hibernate.format_sql">true</property>

        <mapping resource="hibernate_demo1/Customer.hbm,xml"/>
    </session-factory>
</hibernate-configuration>

Hibernate 映射的配置

映射的配置
  • class 标签的配置
    • 标签用来建立类与表的映射关系
    • 属性
      • 【name】类的全路径
      • 【table】表名
      • 【catalog】数据库名
  • id 标签的配置
    • 用来建立类中的属性与表中的主键的对应关系
    • 属性
      • 【name】类中的属性
      • 【column】标中的字段,当自动建表时使用
      • 【length】
      • 【type】
  • property 标签的配置
    • 用来建立类中的普通属性与标中字段的对应关系
    • 属性
      • 【name】类中的属性
      • 【column】表中的字段,当自动建表时使用
      • 【length】长度
      • 【type】
      • 【not-null】设置非空
      • 【unique】设置唯一

Hibernate 核心配置

Hibernate 核心配置方式
  • 属性文件方式
  • xml 文件方式
核心配置
  • 必须的配置
    • 驱动类
    • url 路径
    • 用户名
    • 密码
  • 可选的配置
    • 显示 SQL : hibernate.show.sql
    • 格式化 SQL : hibernate.format.sql
    • 自动建表:hibernate.hbm2ddl.auto
      • 【none】:不使用 hibernate 的自动建表
      • 【create】:如果数据库中已经有表,删除原表,重新创建表;如果没有表,新建表
      • 【create-drop】:如果数据库中已经有表,删除原表
      • 【update】:如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)
      • 【validate】:如果没有表,不会创建表,只会使用数据库中原有的表(但会校验映射和表结构是否一致)
  • 映射文件的引入
    • 引入映射文件的位置

Session

类似 Connection 对象是连接对象。Session 代表的是 Hibernate 与数据库连接对象,不是线程安全的,所以不能定义成全局的,是与数据库交互的桥梁。

Session 中的 API
保存方法:

Serializable save(Object obj)【此方法返回保存的那条记录的id】

  • 查询方法:
    T get(Class c, Serializable id)
    T load(Class c, Serializable id)

get 方法和 load 方法的区别?

 @Test
    //查询客户
    public void demo3(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        
        /*
        * get方法
        *   采用的是立即加载,执行到这一行代码的时候,就会马上发送SQL语句去执行
        *   查询后返回的是真实对象本身
        *   查询一个找不到的对象,返回null
        * load方法
        *   采用的延迟加载(lazy懒加载),执行到这行代码的时候不会发送SQL语句,当真正使用这个对象的时候才会发送SQL语句
        *   查询后返回的是代理对象
        *   查询一个找不到的对象的时候返回ObjectNotFoundException
        * */
        
        //编写代码
        //使用get方法查询
        Customer customer = session.get(Customer.class, 2l);
        System.out.println(customer);

        //使用load方法查询
        Customer customer1 = session.load(Customer.class, 2l);
        System.out.println(customer);

        tx.commit();
        session.close();
    }
修改方法

void update(Object obj)

@Test
    public void demo3(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();

        //第一种,直接创建对象,进行修改
        Customer customer = new Customer();
        customer.setCust_id(1l);
        customer.setCust_name("王聪");
        session.update(customer);
        //第二种,先查询,再修改
        Customer customer1 = session.get(Customer.class, 2l);
        customer1.setCust_name("王小贱");
        session.update(customer1);

        tx.commit();
        session.close();
    }
删除方法

void delete(Object obj)

@Test
    public void demo4(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();

        //直接创建对象删除
        Customer customer = new Customer();
        customer.setCust_id(1l);
        session.delete(customer);

        //先查询,再删除(推荐)--级联删除
        Customer customer2 = session.get(Customer.class, 4l);
        session.delete(customer2);

        tx.commit();
        session.close();
    }
保存或更新

void saveOrUpdate(Object obj)

查询所有
 @Test
    //查询所有
    public void demo5(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();

        //接收HQL: Hibernate Query Language 面向对象的查询语言
        Query query = session.createQuery("from Customer");
        List<Customer> list = query.list();
        for(Customer customer : list){
            System.out.println(customer);
        }

        //接收SQL
        SQLQuery query1 = session.createSQLQuery("select * from cst_customer");
        List<Object[]> list = query1.list();
        for (Object[] objects: list) {
            System.out.println(Arrays.toString(objects));
        }

        tx.commit();
        session.close();
    }

Transcation:事务对象

Hibernate 中管理事务的对象。

  • commit()
  • rollback()

持久化类编写的规则

持久化类的概述
什么是持久化类

持久化:将内存中的一个对象持久化到数据库中的过程。Hibernate 框架就是用来进行持久化的框架。
持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibernate 中称为持久化类。持久化类 = Java 类 + 映射文件

持久化类的编写规则
  • 对持久化类提供一个无参的构造方法:Hibernate 底层需要使用反射生成实例
  • 属性需要私有,对私有属性提供 public 的 get 和 set 方法:Hibernate 中获取,设置对象的值
  • 对持久化类提供一个唯一的表示 OID 与数据库主键对应:在 Hibernate 中通过持久化类的 OID 的属性来区分是否是统一个属性
  • 持久化类中属性尽量使用包装类类型:因为基本数据类型默认是 0 ,那么 0 会有很多歧义,这样不知到在数据库中插入的值是默认的 0 ,还是插入的值是 0 。包装类类型默认值是 null,容易和 0 去区分。
  • 持久化类不要使用 final 修饰:延迟加载本身是 hibernate 一个优化手段,返回的是一个代理对象。如果不能被继承,不能产生代理类,延迟加载也就失败,load 方法和 get 方法也就变得一样了。

主键生成策略

主键的分类
自然主键
  • 自然主键:主键本身就是表中的一个字段(实体中的一个具体属性)。
    • 创建一个人员表,人员都会有一个身份证号(唯一的不可重复),使用身份证号作为主键,这种主键就是称为自然主键,这个主键也是人的一个属性。
代理主键
  • 代理主键:主键本身不是表中必须的一个字段(不是实体中某个具体的属性)。
    • 创建一个人员表,没有使用人员中的身份证号,用了一个与这个表不相关的字段 ID。这种主键称为代理主键。
    • 在实际的开发当中,尽量使用代理主键。
      • 一旦主键参与到业务逻辑当中,后期有可能需要修改源代码。
      • 好的程序设计满足 OCP 原则,对程序的扩展是 open 的,对修改源码是 close 的。
主键的生成策略
Hibernate 的主键生成策略

在实际开发中,一般不允许用户手动设置主键,一般会将这个主键交给数据库,手动编写程序来进行设置。在 Hibernate 中为了减少程序的编写,提供了多种主键的生成策略。

  • increment :hibernate 中提供的一个自动增长机制,使用于 short、int 和 long 类型的主键。在单线程的程序中使用。

    • 首先发送一条语句,select max(id) from 表,然后 id + 1 作为下一条记录的主键,这里就涉及到了线程安全的问题。
  • identity:使用 short、int 和 long 类型的主键,使用数据库底层的自动增长机制。适用于有自动增长机制的数据库,如 MySQL,但是 Oracle 是没有自动增长的。

  • sequence:适用于 short、int 和 long 类型的主键,采用的是序列的方式。(Oracle 支持序列),但是 MySQL 就不支持sequence。

  • uuid:适用于字符串类型主键,使用 hibernate 中的随机的方式生成字符串的主键。

  • native:本地策略,可以在 identity 和 sequence 之间进行自动切换。

  • assigned:hibernate 会放弃外键的管理,需要通过自己手动编写程序或者用户自己设置。

  • foreign:外部的,一对一的一种关联映射的情况下使用。

持久化类的三种状态

Hibernate 是持久层框架,通过持久化类完成 ORM 操作。Hibernate 为了更好的管理持久化类,将持久化类分为三中状态。持久化类 = Java + 映射

瞬时态
  • 这种对象没有唯一的标识 OID ,没有被 session 管理,称为瞬时态对象。
持久态(******)
  • 这种对象有唯一标识 OID,被 session 管理,称为持久态对象。持久化对象的持久态对象,可以自动更新数据库。
脱管态
  • 这种对象有唯一标识 OID,没有被 session 管理,称为脱管态。
区分这三种状态的对象
public class HibernateDemo2 {
    @Test
    //三种状态的区分
    public void demo1(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();

        Customer customer = new Customer();//瞬时态对象,没有唯一的标识OID,没有被session管理
        customer.setCust_name("王瓜");
        Serializable id = session.save(customer);//持久态对象,有唯一的标识OID,被session管理
        session.get(Customer.class, id);

        transaction.commit();
        session.close();

        System.out.println("客户名称:" + customer.getCust_name());//脱管态对象,有唯一的标识OID,没有被session管理
    }
}
持久化类的状态转换
瞬时态对象
  • 获得 Customer customer = new Customer();
  • 状态转换
    • 瞬时 > 持久 【sava(Object obj) 、saveOrUpdate(Object obj)】
    • 瞬时 > 脱管 【customer.setCust_id(1l)】
持久态对象
  • 获得
    • get()、load()、find()、iterate()
  • 状态转换
    • 持久 > 瞬时 【delete()】
    • 持久 > 脱管 【close()、clear()、evict(Object obj)】
脱管态对象
  • 获得 Customer customer = new Customer(); customer.setCust_id(2l);
  • 状态转换
    • 脱管 > 持久 【update(Object obj)、saveOrUpdate()】
    • 脱管 > 瞬时 【customer.setCust_id(null)】

Hibernate 的一级缓存

什么是缓存

缓存:是一种优化的方式,将数据存入到内存当中,使用的时候直接从缓存中获取,不用通过存储源。

Hibernate 的一级缓存

Hibernate 框架中提供了优化手段,缓存、抓取策略。Hibernate 中提供了两种缓存机制:一级缓存,二级缓存。
Hibernate 的一级缓存:称为 Session 级别的缓存,一级缓存的生命周期与 Session 一致(一级缓存是由 Session 中的一系列的 Java 集合构成)。一级缓存是自带的不可卸载的。(Hibernate 的二级缓存是 SessionFactory 级别的,需要配置的缓存)

证明一级缓存的存在
public class HibernateDemo3 {
    @Test
    //证明一级缓存的存在
    public void demo1(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();

        //第一种证明方法
        Customer customer1 = session.get(Customer.class, 1l);//发送SQL语句,get方法首先会从缓存中找这个对象,缓存中不存在,所以需要从数据库中寻找,这是发送SQL语句
        System.out.println(customer1);
        Customer customer2 = session.get(Customer.class, 1l);//不发送SQL语句,因为缓存中存在了这个对象,所以不发送SQL语句
        System.out.println(customer2);

        //第二种证明方法
        Customer customer = new Customer();
        customer.setCust_name("小峰");
        Serializable id = session.save(customer);
        session.get(Customer.class, id);

        transaction.commit();
        session.close();
    }
}
Hibernate 的一级缓存的结构
一级缓存中特殊区域:快照区

将你放入到一级缓存区域的这个数据进行一个快照(就是把这个数据又备份了一份),当你的数据发生变化的时候,当你的事务要提交的时候,它会拿你一级缓存区的数据和快照区的数据做一个比较,如果数据不一样就会自动更新数据库,如果一样就不更新数据库了。

Hibernate 事务管理
事务的回顾
  • 事务:事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么全都成功,要么全都失败。
  • 事务的特性
    • 原子性:代表不分割
    • 一致性:代表事务执行的前后,数据的完整性保持一致
    • 持久性:代表事务执行完成后,数据就持久数据库当中了
    • 隔离性:代表一个事务在执行的过程当中,不应该受到其他事务的干扰
如果不考虑隔离性,引发安全性问题
  • 读问题
    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交的 update 的数据,导致在前一个事务多次查询结果不一致
    • 幻读:一个事务读到另一个事务已经提交的 insert 的数据,导致在前一个事务多次查询结果不一致
  • 写问题
读问题的解决
  • 设置事物的隔离级别
    • Read uncommitted:以上问题都有可能发生
    • Read comitteed:解决脏读问题,但是不可重复读和幻读有可能发生
    • Repeatable read:解决脏读和不可重复读,但是幻读有可能发生
    • Serializble:解决所有读问题

Hibernate 一对多关联映射

数据库表与表之间的关系
一对多的关系
  • 什么样的关系是一对多?
    一个部门对于多个员工,一个员工只能属于一个部门。
  • 一对多建表原则
    在多的一方创建外键指向一的一方的主键
多对多的关系
  • 什么样的关系属于多对多?
    一个学生可以选择多门课程,一门课程也可以被多个学生选择。
    一个用户可以选择多个角色,一个角色可以被多个用户选择。
  • 多对多建表原则
    创建一个中间表,中间表至少有两个字段分别作为外键指向多对多双方的主键。
一对一的关系
  • 什么样的关系属于一对一?
    一个公司只能有一个注册地址,一个地址只能有一个公司注册。
Hibernate 一对多关系配置
创建一个项目,引入 jar 包
创建数据库和表
  • 客户表
CREATE TABLE `cst_customer` (
  `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
  `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
  `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
  `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
  `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
  `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 联系人表
CREATE TABLE `cst_linkman` (
  `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
  `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
  `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
  `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
  `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
  `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
  `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
  `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
  `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
  `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
  PRIMARY KEY (`lkm_id`),
  KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
创建实体
  • 一的一方的实体
/**
 * 客户实体
 */
public class Customer {
    private Long cust_id;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;

    //如何表示一个客户里有多个联系人?
    //通过ORM的方式表示:一个客户对应多个联系人
    //放置的是多的一方的集合,Hibernate默认使用的是Set集合
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();
  • 多的一方的实体
public class LinkMan {
    private Long lkm_id;
    private String lkm_name;
    private String lkm_gender;
    private String lkm_phone;
    private String lkm_mobile;
    private String lkm_email;
    private String lkm_qq;
    private String lkm_position;
    private String lkm_memo;
    
    //通过ORM的方式表示:一个联系人只能属于某一个客户
    //放置的是一的一方的对象
    private Customer customer;
创建映射文件
多的一方的映射的创建
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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="domain.LinkMan" table="cst_linkman">
        <!--建立OID与主键的映射-->
        <id name="lkm_id" column="lkm_id">
            <generator class="native"/>
        </id>
        <!--建立普通属性与表字段的映射-->
        <property name="lkm_name"/>
        <property name="lkm_gender"/>
        <property name="lkm_phone"/>
        <property name="lkm_mobile"/>
        <property name="lkm_email"/>
        <property name="lkm_qq"/>
        <property name="lkm_position"/>
        <property name="lkm_memo"/>
        <!--配置多对一的关系:放置一的一方的对象
          * name:一的一方的对象的属性名称
          * class:一的一方的类的全路径
          * column:在多的一方的外键的名称
          -->
        <many-to-one name="customer" class="domain.Customer" column="lkm_cust_id"></many-to-one>
    </class>
</hibernate-mapping>
一的一方的映射的创建

<?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="domain.Customer" table="cst_customer">
        <!--建立OID与主键的映射-->
        <id name="cust_id" column="cust_id">
            <generator class="native"/>
        </id>
        <!--建立普通属性与数据库表的字段的映射-->
        <property name="cust_name"/>
        <property name="cust_source"/>
        <property name="cust_industry"/>
        <property name="cust_level"/>
        <property name="cust_phone"/>
        <property name="cust_mobile"/>

        <!--配置一对多的映射:放置多的一方的对象的集合
            set 标签:
               *name:放的是多的一方的对象的集合属性名称-->
        <set name="linkMans">
            <!--key标签
               *colunm:多的一方的外键的名称-->
            <key column="lkm_cust_id"/>
            <!--one-to-many标签
                *class:多的一方的类的全路径-->
            <one-to-many class="domain.LinkMan"/>
        </set>
    </class>
</hibernate-mapping>
编写测试类
public class HibernateDemo1 {
    @Test
    //保存两个客户和三个联系人并且建立好关系
    public void demo1(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();//开启事务

        //创建两个客户
        Customer customer1 = new Customer();
        customer1.setCust_name("王东");
        Customer customer2 = new Customer();
        customer2.setCust_name("赵红");

        //创建三个联系人
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkm_name("如花");
        LinkMan linkMan2 = new LinkMan();
        linkMan2.setLkm_name("凤姐");
        LinkMan linkMan3 = new LinkMan();
        linkMan3.setLkm_name("旺财");

        //设置关系
        linkMan1.setCustomer(customer1);
        linkMan2.setCustomer(customer1);
        linkMan3.setCustomer(customer2);

        customer1.getLinkMans().add(linkMan1);
        customer1.getLinkMans().add(linkMan2);
        customer2.getLinkMans().add(linkMan3);

        //保存数据
        session.save(linkMan1);
        session.save(linkMan2);
        session.save(linkMan3);
        session.save(customer1);
        session.save(customer2);

        tx.commit();//提交事务
        session.close();//结束事务
    }
}
Hibernate 一对多相关操作
一对多关系只保存一边

不可以

一对多的级联操作

级联:操作一个对象的时候,是否会操作其关联的对象
级联是有方向性的:操作一的一方的时候是否操作到多的一方;操作多的一方的时候是否操作到多的一方

级联保存或更新
  • 保存客户级联联系人
 @Test
    //保存两个客户和三个联系人并且建立好关系
    public void demo2(){
        /**
         * 级联保存或更新操作
         * 保存客户级联联系人
         * 操作的主体是客户对象,那么就要在客户的映射文件中进行配置
         * <set name="linkMans" cascade="save-update">
         */
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();//开启事务

        //创建两个客户
        Customer customer = new Customer();
        customer.setCust_name("王东");

        //创建三个联系人
        LinkMan linkMan = new LinkMan();
        linkMan.setLkm_name("如花");


        //设置关系
        linkMan.setCustomer(customer);
        customer.getLinkMans().add(linkMan);

        //保存数据
        session.save(customer);

        tx.commit();//提交事务
        session.close();//结束事务
    }


 <!--配置一对多的映射:放置多的一方的对象的集合
            set 标签:
               *name:放的是多的一方的对象的集合属性名称
               *cascade:级联保存-->
        <set name="linkMans" cascade="save-update">
            <!--key标签
               *colunm:多的一方的外键的名称-->
            <key column="lkm_cust_id"/>
            <!--one-to-many标签
                *class:多的一方的类的全路径-->
            <one-to-many class="domain.LinkMan"/>
        </set>
  • 保存联系人级联客户
<many-to-one name="customer" cascade="save-update" class="domain.Customer" column="lkm_cust_id"/>
级联删除
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值