04hibernate

1. 概述

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任

1.1 CRM

> ```
> 客户关系管理是指企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与顾客间在销售、营销和服务上的交互,从而提升其管理方式,向客户提供创新式的个性化的客户交互和服务的过程。其最终目标是吸引新客户、保留老客户以及将已有客户转为忠实客户,增加市场。 
> ```

1.2 ORM

对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。 更重要的是用于控制转换的元数据需要提供和管理;但是同样,这些花费要比维护手写的方案要少;而且就算是遵守ODMG规范的对象数据库依然需要类级别的元数据。
Object Relational Mapping,对象关系映射,将对象与关系型数据库的表建立映射关系,操作对象就可以操作表。

2.配置文件和XML表头

xml文件头信息可以到D:\JavaWeb\TestHibernate\lib\hibernate-core-5.0.7.Final.jar!\org\hibernate\hibernate-configuration-3.0.dtd下找到,即进入core包里面的org\hibernate/就有

2.1 映射文件 Customer.hbm.xml

  • 类中的属性名和表中的字段名如果一致,column可以省略

【id标签】:

  • 属性:
    • name、column、length、type

【property标签】

  • 属性:
    • name、column、length、type、not-null,uinque


<hibernate-mapping><class name="com.gxufe.hibernate.demo01.Customer" table="cst_customer"><id name="cust_id" column="cust_id"><generator class="native">generator>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>

2.2 配置文件 hibernate.cfg.xml

  • 方言

    方言对应不同的数据库使用不同的方言,可以去下载下来的hibernate文件的`hibernate-release-5.0.7.Final\project\etc`目录下的`hibernate.properties`文件里面找对应的方言
    
  • 可选的配置

    • 显示SQL :hibernate.show_sql
    • 格式化sql :hibernate.format_sql
    • 自动建表 : hibernate.hbm2ddl.auto
      • none :不使用hibernate的自动建表
      • create :如果数据库已经有表,删除原有的表,重新创建,如果没有表,新建表(测试)
      • create-drop :如果数据库中有表了,删除原有表,执行操作,删除这个表,如果没有表,新建一个表,使用完了也删除改表(测试)
      • update :如果数据库中有表,使用原有表,如果没有表,创建新表(可以更新表结构)
      • validate :如果没有表,不会创建表,只会使用数据库中存在的表(校验映射和表结构)
  • 映射文件的引入

  • 也可以在cfg.xml添加c3p0的配置(了接即可)



<hibernate-configuration><session-factory><property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driverproperty><property name="hibernate.connection.url">jdbc:mysql:///hibernate?serverTimezone=UTCproperty><property name="hibernate.connection.username">rootproperty><property name="hibernate.connection.password">162263property><property name="hibernate.show_sql">trueproperty><property name="hibernate.format_sql">trueproperty><property name="hibernate.hbm2ddl.auto">updateproperty><property name="hibernate.connection.isolation">4property><property name="hibernate.current_session_context_class">threadproperty><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty><mapping resource="com/gxufe/hibernate/demo01/Customer.hbm.xml"/>session-factory>
hibernate-configuration>

2.3 Hibernate加载文件工具类

public class HibernateUtils {public static final Configuration cfg ;public static final SessionFactory sf;static{cfg = new Configuration().configure();sf = cfg.buildSessionFactory();}public static Session openSession(){return sf.openSession();}public static Session getCurrentSession(){//线程绑定return sf.getCurrentSession();}}

3. Hibernate核心API(对象)

3.1 Configuration

Hibernate的配置对象

  • 作用
  • 加载核心配置文件

    • hibernate.porperties

      configuration cfg = new Configuration();

    • hibernate.cfg.xml
      Configuration configuration = new Configuration.configure();
      
  • 加载映射文件

3.2 SessionFactory

Session工厂:SessionFactory内部维护了hibernate的连接池和Hibernate的二级缓存(被redis替换了)。是线程安全的对象,一个项目创建一个对象即可

  • 抽取工具类
public class HibernateUtils {public static final Configuration cfg ;public static final SessionFactory sf;static{cfg = new Configuration().configure();sf = cfg.buildSessionFactory();}public static Session openSession(){return sf.openSession();}}

3.3 Session

类似JDBC中的Connection对象

Session代表的是Hibernate与数据库的连接对象,不是线程安全的。所以不能设置成全局变量,必须是局部变量,内部维护了一级缓存,是与数据库交互的桥梁

  • Session中的常用API
  • 保存
    • Serializable save(Object obj) -->返回的是可序列化的id
  • 查询方法(get()和load()的区别)
    • T get(Class c, Serializable id);

    • T load(Class c,Serializable id);

      @Test//查询------->get方法和load方法的区别public void demo02(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();/*** get方法*   * 采用的是立即加载,执行到这行代码的时候,就会马上发送Sql语句去查询*   * 查询返回是真实对象本身*   * 查询一个找不到的对象的时候,返回null** load方法*    * 采用的是延迟加载(lazy懒加载),执行到这行代码的时候,不会发送SQL语句,当真正使用这个对象的时候才会发送SQL语句*    *查询返回的是代理对象。 javassist-3.18.1.GA.jar,利用javassist技术产生的代理*    * 查询一个找不到的对象的时候,返回ObjectNotFoundException*///使用get的方法//因为是Long类型,所以后面需要加一个L/*  Customer customer = session.get(Customer.class, 1l);/*  Customer customer = session.get(Customer.class, 100l);//数据库没这个数据System.out.println(customer);*///使用load()方法查询Customer customer = session.load(Customer.class, 2l);/* System.out.println(customer);//使用了除id以为的属性才发sql语句*/System.out.println(customer.getCust_id());//没有发送sql语句,直接从上面的load方法参数获得了idtransaction.commit();session.close();}
      
  • 修改方法
    • void update(Object obj);//无返回值的方法

      public void demo03(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//1.直接创建对象修改,数据库的其他属性没了,没有设置的覆盖为null,就是没有来源,/*Customer customer = new Customer();customer.setCust_id(1l);customer.setCust_name("马尔扎哈");session.update(customer);*///2.(建议)先查询再修改,有来源,来源于查询得到的这行的其他属性,Bean里面的get的方法就有值Customer customer = session.get(Customer.class, 1l);//修改的必须是查询放回的那个对象否则就报错customer.setCust_name("古力娜扎");session.update(customer);transaction.commit();session.close();}
      
  • 删除方法

    • void delete(Object obj)

        //删除方法public void delete(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//1.直接删除对象/*Customer customer = new Customer();customer.setCust_id(1l);//删除第一条session.delete(customer);*///2.先查询再删除(推荐) ---级联删除 --》的前提就是先查询再删除Customer customer = session.get(Customer.class, 2l);session.delete(customer);transaction.commit();session.close();}
      
  • 保存或更新

      //保存或更新public void demo05(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//保存Customer customer = new Customer();/*customer.setCust_name("汪大东");session.saveOrUpdate(customer);*///修改customer.setCust_id(3l);customer.setCust_name("李大而已");session.saveOrUpdate(customer);transaction.commit();session.close();}
    
  • 查询所有

     //查询所有public  void demo06(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//接受HQL:Hibernate Query Language 面向对象的查询语言/* Query query = session.createQuery("from Customer");List list = query.list();for (Customer customer : list){System.out.println(customer);}*///接受Sql语句SQLQuery sql = session.createSQLQuery("select * from cst_customer");List<Object[]> list1 = sql.list();for (Object[] objects: list1) {System.out.println(Arrays.toString(objects));}transaction.commit();session.close();}
    

3.4 Transaction:事务对象

hibernate中管理事务的对象

  • commit()
  • Rollback()

4. 持久化

4.1 概述

  • 什么是持久化类

持久化:将内存中的一个个对象持久化到数据库中过程。

持久化类:一个java对象与数据库的表建立了映射关系,那么这个类就hibernate中称为持久化类。(持久化类 =java类 + 映射文件)

  • 编写规则
  • 对持久化类提供一个无参数的构造方法 :Hibernate底层需要使用反射生成实例。

  • 对属性需要私有,对私有属性提供pblic的get和set方法 :Hibernate中获取,设置对象的值

  • 对持久化类提供一个唯一的标识oid与数据库主键对应 :java中通过对象的地址区分是否是同一个对象,数据库中通过主键确定是否是同一个记录,hibernate中通过持久化类的OID属性区分是否是同一个对象

  • 持久化类中的属性尽量使用使用包装类型(Integer Long String Double),因为基本数据类型默认是0,那么0就会有很多的歧义。包装类型类型默认是null,不会容易产生歧义

  • 持久化类不要使用final进行修饰,延迟加载本身就是hibernate一个优化的手段,返回的是一个代理对象(javassistkey对没有实现接口的类产生一个代理–使用了非常底层的字节码增强技术,继承这个类进行代理),如果不能被继承,不能产生代理对象,延迟加载就失效, load方法和get方法一致了。

5. 主键的生成策略

5.1主键的分类

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

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

  • increment:hibernate中提供的自动增长的机制,使用short、int、long类型的主键,在集群下不要使用,在单线程中的程序中使用。
    • 首先发送一条数据,select max(id) from 表,然后让id+1作为下一条记录的主键。
  • identity : 使用short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长的机制的数据库(MySql、MSSQL),但是Oracle没有自动增长。
  • squence : 适用short、int、long类型的主键,采用的是序列的方式。(Oracle支持序列),像mysql就不支持序列
  • uuid : 使用于字符串类型的主键,使用Hibernate中随机的方式生成的字符串主键
  • native : 本地策略,可以在identuty和sequence之间进行自动切换
  • assigned : Hibernate放弃外键的管理,需要手动编写程序或者用户自己设置
  • foreign : 外部的。一对一的一种关系映射的情况下使用(了解)

6. 持久化的三种状态

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

6.1 瞬时态(transient)

  • 这种对象没有唯一的标识OID,没有被session管理,称为瞬时态对象

6.2 持久态(persistent)

  • 这种对象有唯一标识的OID,被session管理,称为是持久态对象

6.3 脱管态(游离)(detached)

  • 这种对象有唯一标识的OID,没有被session管理,称为托管态对象

6.4 区分

  • 持久化类的持久态对象,可以自动更新数据库。
   @Test//三种状态的区分public void demo01(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//1.刚new出来,瞬时态对象,没有唯一标识OID,就是数据库还没有ID ,没有被session管理Customer customer = new Customer();customer.setCust_name("马尔扎哈");Serializable id = session.save(customer);//2.变成持久态,数据库中已经有了唯一标识的OID,被session管理session.get(Customer.class,id);//操作持久化对象//把资源关闭了transaction.commit();session.close();System.out.println("客户名称:"+customer.getCust_name());//3.变成脱管态对象:有唯一标识的OID,没有被session管理}

6.5 持久化状态的装换

  • 瞬时态对象
  • 获得:

    • Customer customer = new Customer();
      
  • 状态转换

    • 瞬时–》持久
      • save(obj)
      • saveOrUpdate
    • 瞬时–》托管
      • customer.setCust_id(1l),有唯一标识,但是没有被session管
  • 持久化对象
  • 获得
    • get()、load()、find()、iterate()
    • session.get(Customer.class, 1l );
  • 状态转换
    • 持久–>瞬时
      • delete();
    • 持久–托管
      • session.close(); clear() 、 evict()
  • 脱管态对象
  • 获得

    • Customer customer = new Customer();
      customer.setCust_id(1);//有唯一标识,没有被session管
      
  • 状态转换

    • 托管—》持久

      • update()、saveOrUpdate();
    • 托管—》瞬时

      • customer.setCust_id(null);
        

6.6 持久态对象自动更新

原理:依赖hibernate的一级缓存

   @Test//持久态对象自动更新数据库public void demo02(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();Customer customer = session.get(Customer.class, 1l);//已经是一个持久化对象customer.setCust_name("古力娜扎");//修改//session.update(customer);//不是持久化对象需要执行该语句,已经是持久化对象回自动发sql更新语句//把资源关闭了transaction.commit();session.close();}
}

7. Hibernate的一级缓存

7.1 缓存的概述

  • 什么是缓存

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

7.2 Hibernate的一级缓存

Hibernate框架中提供了优化手段:缓存和抓取策略。Hibernate中提供了二种缓存机制;一级缓存和二级缓存。

  • Hibernate的一级缓存

称为是Session级别的缓存,一级缓存的生命周期与Session一致(一级缓存是由Session中的一系列的java集合构成)。一级缓存是**自带的不可卸载。**

  • Hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存

7.3 一级缓存的存在测试

 @Test//证明一级换出的存在public void demo01(){Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//连续发送两次查询数据,只会发送一条sql语句/* Customer customer1 = session.get(Customer.class,1l);//发送System.out.println(customer1);Customer customer2 = session.get(Customer.class,1l);//不发送System.out.println(customer2);//查看对象是否相等System.out.println(customer1 == customer2);//true*/Customer customer = new Customer();customer.setCust_name("马大哈");//发送一条sql语句Serializable id = session.save(customer);Customer customer1 = session.get(Customer.class, id);System.out.println(customer1.getCust_name());//不发送sql语句//把资源关闭了transaction.commit();session.close();}

7.4 一级缓存的内部结构

  • 一级缓存的特殊区域:快照区

比较缓存区和快照区的数据

一致:不更新数据库

不一致:更新数据库

@Test
//一级缓存的快照区
public void demo02() {Session session = HibernateUtils.openSession();Transaction transaction = session.beginTransaction();//发送sql语句查询,同时放入到一级缓存中Customer customer = session.get(Customer.class,1l);customer.setCust_name("古力娜扎!!");//把资源关闭了transaction.commit();session.close();}

8. 事务管理

8.1 什么是事务

  • 事务:事务是指的逻辑上的一组操作,组成这组操作的各个逻辑单元要么成功,要么失败

8.2 事务的特性

  • 原子性 :代表事务不可分割。
  • 一致性 : 代表事务执行的前后,数据的完整性保持一致
  • 隔离性 : 代表一个事务执行过程中,不受到其他事务的干扰
  • 持久性 : 代表事务执行完成后,数据就持久到数据库中。
  • 如果不考虑隔离性,就会引发安全性问题
  • 读问题:
    • 脏读 一个事务读到另一个事务未提交的事务
    • 不可重复 : 一个事务读到了另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致
    • 虚读 : 一个事务读到另一个事务已经提交的insert数据,导致前一个事务多次查询结果不一致。
  • 写问题(引发两类丢失更新)
    *

8.2 读问题的解决(隔离级别)

  • 设置事务的隔离级别
  • Read uncommited : 以上问题都不解决
  • Read commited : 解决脏读,但是不可重复读和虚读都有可能发生
  • Repeatable read : 解决脏读和不可重复读,但是虚读有可能发生
  • Serializable : 解决所有读问题

8.3 Hibernate设置隔离级别

  • 在application.cfg.xml里面配置隔离级别
     <property name="hibernate.connection.isolation">4property>
  • 隔离级别分别对应
    • Read uncommited : 1
    • Read commited : 2
    • Repeatable read : 4
    • Serializable : 8

8.4 事务需要加载业务层上

银行转账

  • service中封装业务逻辑操作,service里面有个方法aa()用到了到层的dao1()和dao2()两个方法,但是dao1里面的连接(Hibernate称为Session,JDBC称为Connection)和dao2用的不是用一个连接。
  • 必须保证连接对象 是同一个
  • JDBC中的处理方法
    • 向下传递 DBUtils使用的方法
    • 使用ThreadLocal对象(绑定线程对象)
      • 将这个连接绑定到当前线程中
      • 在Dao的方法中,通过当前的线程得到连接对象

8.5 Hibernate绑定线程

  • Hibernate 框架内部已经绑定好了一个ThreadLocal

    • 在SessionFactory中提供了绑定线程的一个方法getCurrentSession();

    • 通过一个配置完成

        thread
      

9. * Hibernate的其他API

9.1 Query(HQL)

  • Query接口用于接收HQL。查询多个对象

  • HQL:Hibernate Query Language :Hibernate查询语言

  • Query的简单使用

  @Test//Querypublic void demo01(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//通过Session获得Query接口//查询所有// String hql = "from Customer";//条件查询// String hql = "from Customer where cust_name like ?";//分页查询String hql = "from Customer ";Query query = session.createQuery(hql);//设置条件问号参数//query.setParameter(0,"李%");//参数从0开始的//设置分页query.setFirstResult(0); //从第几个开始,默认从o开始query.setMaxResults(3); //返回最多少个数据List<Customer> list = query.list();for (Customer customer: list) {System.out.println(customer);}transaction.commit();}

9.2 Criteria (QBC)

QBC(Query By Criteria) : 条件查询

​ 更加面向对象的一种查询方式

@Test
//Criteria(标准)
public void demo02(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//通过session获得Criteria的对象/*Criteria criteria = session.createCriteria(Customer.class);//查询所有对象List list = criteria.list();*///条件查询Criteria criteria = session.createCriteria(Customer.class);//Restrictions(限制条件) add的方法是添加条件限制//criteria.add(Restrictions.like("cust_name","李%"));//分页criteria.setFirstResult(0);criteria.setMaxResults(3);List<Customer> list = criteria.list();for (Customer customer : list) {System.out.println(customer);}transaction.commit();
}

9.3 SQLQuery

用于接收SQL,查询条件特别复杂情况下使用

10 Hibernate的一对多关联映射

10.1 一对多关系

10.1.1 一对多的建表原则:
  • 的一方创建外键指向的一方

  • 创建对象需要注意
    • 在一的一方创建集合来存储多(Hibernate默认使用Set)
    //通过ORM方式表示:一个客户对应多个联系人//放置多的一方的集合,一个订单分类有多个订单//Hibernate默认使用的是Set集合private Set<LinkMan> linkManSet;
    
    • 在多的一方创建一的对象代替外键属性

      //通过ORM方式表示:一个联系人只能属于某一个客户//放置的是一的一方的对象//外键名称改为一的一方的private Customer customer;
      
  • 映射文件配置一对多映射关系
    • 多对一(LinkMan.hbm.xml)
      • name : 另一方在本类(LinkMan)的属性名称
      • class : 一的一方的类的全路径
      • column : 在多的一方的表里面的外键名称
          <many-to-one name="customer" class="com.gxufe.hibernate.domain.Customer" column="lkm_cust_id"/>
    • 一对多(Customer)
        <!--配置一对多的映射:放置多的一方的集合set标签:* name : 多的一方的对象在本类对应的属性名称key标签:* column : 多的一方的外键名称one-to-many标签:* class :  多的一方的类全路径        --><set name="linkManSet" ><key column="lkm_cust_id"/><one-to-many class="com.gxufe.hibernate.domain.LinkMan"/></set>
      
  • 引入映射文件

    
    
10.1.2 一对多级联操作

级联指的是:操作一个对象的时候,是否同时操作其他关联的对象

  • 级联是由方向性
    • 操作一的一方的时候,是否操作到多的一方
    • 操作多一方的时候,是否操作到一的一方
  • 级联保存或更新
    • 保存客户级联联系人
    • 保存联系人级联客户

xml设置cascde属性

       <set name="linkManSet"  cascade="save-update"><key column="lkm_cust_id"/><one-to-many class="com.gxufe.hibernate.domain.LinkMan"/>set>
<many-to-one name="customer" class="com.gxufe.hibernate.domain.Customer" column="lkm_cust_id" cascade="save-update"/>

10.1.3 一对多级联删除

  • 设置映射文件(配置的主体是需要执行被删除的项)

    • 要删除的是Customer,级联删除就会把LinkMan相对应的也删除

    添加一个级联属性值:delete


  • 测试类

        /***级联删除*  * 删除客户级联删除联系人,删除的主体的是客户,需要在Customer.hbm.xml配置*/public void  demo04(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//没有设置级联删除,默认情况下:修改了联系人的外键为null,删除客户Customer customer = session.get(Customer.class,1l);/*session.delete(customer);*///删除客户,同时删除联系人session.delete(customer);transaction.commit();}
    
10.1.3 一对多设置双向关联产生多余SQL语句

多的一方可以通过一的对象属性(外键)维护外键,一的一方可以通过Set集合去维护多的一方

  • 解决多余的SQL语句

    • 单向维护

    • 是一方放弃外键维护权

      • 一的一方放弃维护,inverse="true"

                
        
      • 一对多的关联查询的修改时候 (CRM)

  • 区分cascde 和 inverse

10.2 多对多

  • 多对多建表原则:
    • 创建中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键 例如:学生表和选课表是多对多,创建中间表为学生选课表,学生选课表最少要有两个字段分别为学生id和课程id
  • 二者关系主要通过集合来操作
    • 首先查询
    • 使用Set集合里面的add、remove方法
10.2.1 多对多的类设置集合

两个类都设置一个存放对方Set集合

例如:

 private Set roles= new HashSet() ;
private Set users = new HashSet();	
10.2.2 多对多的映射文件Set属性设置
  • setname属性是当前类里边的Set变量的名称,多对多要使用中间表table属性就是写中间表
  • **key:**里面标签的column,-当前-对象的对应中间表的外键名称
  • m-to-m:class 是对方类的全路径 column对方的对象在中间表中的外键名称



10.2.3 测试类
  • 保存:多对多建立了双向的关系必须有一方放弃外键维护,一般是被动方放弃外键维护(角色被用户选择)
 @Test/*** 保存多条记录:保存多个用户角色*/public void demo01(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//创建2个用户User user1 = new User();User user2 = new User();user1.setUser_name("迪丽热巴");user2.setUser_name("古力娜扎");//3个角色Role role1 = new Role();Role role2 = new Role();Role role3 = new Role();role1.setRole_name("研发部");role2.setRole_name("市场部");role3.setRole_name("营销部");//设置双向的关联关系:user1.getRoles().add(role1);user1.getRoles().add(role2);user2.getRoles().add(role2);user2.getRoles().add(role3);role1.getUsers().add(user1);role2.getUsers().add(user1);role2.getUsers().add(user2);role3.getUsers().add(user2);//保存:多对多建立了双向的关系必须有一方放弃外键维护//一般是被动方放弃外键维护(角色被用户选择)session.save(user1);session.save(user2);session.save(role1);session.save(role2);session.save(role3);transaction.commit();}
10.2.4 多对多的级联保存或更新
  • 配置User.hbm.xml的cascde属性

    cascade="save-update"
    
  • 保存测试

        @Test//多对多级联保存//保存用户级联保存角色,在用户的映射文件中配置public void demo02(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();User user1 = new User();user1.setUser_name("迪丽热巴");Role role1 = new Role();role1.setRole_name("研发部");user1.getRoles().add(role1);role1.getUsers().add(user1);session.save(user1);transaction.commit();}
10.2.5 多对多级联删除(基本用不上)

因为删除学生选课不能也把这个课程给删除了

10.2.6 多对多的常用其他操作

给用户选择课程,给用户改选课程,给用户删除课程

  • 添加角色
 @Test//给用户选择角色public void demo03(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//给1号用户多选2号角色//查询1号用户User user = session.get(User.class,1l);//查询2号角色Role role = session.get(Role.class,3l);//给1号用户添加3号角色user.getRoles().add(role);transaction.commit();}
  • 修改所选之一

思想:先删除后修改

   @Test//给用户改选角色public void demo04(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//给2号用户将原有的2号角色改为3号角色//查询2号用户User user = session.get(User.class,2l);//查询2 . 3号角色Role role2 = session.get(Role.class,2l);Role role3 = session.get(Role.class,3l);//给2号用户修改2号为3号角色user.getRoles().remove(role2);user.getRoles().add(role3);transaction.commit();}
  • 删除一门课
@Test//给用户删除角色public void demo05(){Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//给2号用户删除1号角色//查询2号用户User user = session.get(User.class,2l);//查询1号角色Role role = session.get(Role.class,1l);//给2号用户删除1号角色user.getRoles().remove(role);transaction.commit();}

10.3 一对一

  • 一对一建表原则:
    • 唯一外键对应
    • 主键对应

11 Hibernate查询方式

Hibernate提供了很多种查询方式。Hibernate提供了5中查询方式

11.1 OID查询

OID:Hibernate根据对象的OID(主键)进行检索

分别是:

  • 使用get方法

    User user = session.get(User.class,1);
    
  • 使用load方法

    User user = session.load(User.class,1);
    

11.2 对象导航查询

Hibernate根据一个已经查询到的对象,获得其关联对象的一中查询方式

User user = session.get(User.class,1);
Role role = user.getRole();

* 11.3 HQL查询

Hiernate Query Language,Hibernate的查询语言,是一种面向对象的查询语言,语法类似SQL。通过session.createQuery(),用于接受一个HQL进行查询方式

11.3.1 简单查询
public void demo02(){Session sesion = HibernateUtils.getCurrentSession() ;Transaction transaction = sesion.beginTransaction();//简单写法
//        Query query = sesion.createQuery("from Customer");//别名查询 select c from Customer cQuery query = sesion.createQuery("from Customer c");List<Customer> list = query.list();/*sql中支持的 * 号写法 select * from 表HQL不支持 * 写法*/for (Customer customer : list){System.out.println(customer);}transaction.commit();}
11.3.2 排序查询

@Test/*** 排序查询*/public void demo03(){Session sesion = HibernateUtils.getCurrentSession() ;Transaction transaction = sesion.beginTransaction();//排序,默认升序(asc)//设置降序(desc)Query query = sesion.createQuery("from Customer order by cust_id  desc");List<Customer> list = query.list();for (Customer customer : list){System.out.println(customer);}transaction.commit();}
11.3.3 条件查询
 @Test/*** 条件查询*/public void demo04(){Session sesion = HibernateUtils.getCurrentSession() ;Transaction transaction = sesion.beginTransaction();//条件查询//一、 按位置绑定//一个条件
//        Query query = sesion.createQuery("from Customer where  cust_name = ? ");
//        query.setParameter(0,"马尔扎哈");/*   //两个条件Query query = sesion.createQuery("from Customer where cust_name = ? and cust_source = ? ");query.setParameter(0,"马尔扎哈");query.setParameter(1,"lol");*///二、按名称绑定Query query = sesion.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");query.setParameter("aaa","lol");query.setParameter("bbb","马尔%");List<Customer> list = query.list();for (Customer customer : list){System.out.println(customer);}transaction.commit();}
11.3.4 投影查询

投影查询:查询对象的某个或某些属性