Hibernate 框架学习

Hibernate 复习

Paste_Image.png
Paste_Image.png
Paste_Image.png

基本演示:

hibernate创建的 java 工程,需要的 jar包:

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
       "-//Hibernate/Hibernate Configuration DTD//EN"
       "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
    
       <!--
       #hibernate.dialect org.hibernate.dialect.MySQLDialect
       #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
       #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
       #hibernate.connection.driver_class com.mysql.jdbc.Driver
       #hibernate.connection.url jdbc:mysql:///test
       #hibernate.connection.username gavin
       #hibernate.connection.password
        -->
       <!-- 数据库驱动 -->
       <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
       <!-- 数据库url -->
       <property name="hibernate.connection.url">jdbc:mysql:///hibernate_demo</property>
       <!-- 数据库连接用户名 -->
       <property name="hibernate.connection.username">root</property>
       <!-- 数据库连接密码 -->
       <property name="hibernate.connection.password">root</property>
       <!-- 数据库方言
           不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
           sql99标准: DDL 定义语言  库表的增删改查
                     DCL 控制语言  事务 权限
                     DML 操纵语言  增删改查
           注意: MYSQL在选择方言时,请选择最短的方言.
        -->
       <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    
    
       <!-- #hibernate.show_sql true
            #hibernate.format_sql true
       -->
       <!-- 将hibernate生成的sql语句打印到控制台 -->
       <property name="hibernate.show_sql">true</property>
       <!-- 将hibernate生成的sql语句格式化(语法缩进) -->
       <property name="hibernate.format_sql">true</property>
       <!--
       ## auto schema export  自动导出表结构. 自动建表
       #hibernate.hbm2ddl.auto create       自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
       #hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
       #hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
       #hibernate.hbm2ddl.auto validate 校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
        -->
       <property name="hibernate.hbm2ddl.auto">update</property>
       <!-- 引入orm元数据
           路径书写: 填写src下的路径
        -->
       <mapping resource="com/inke/domain/Customer.hbm.xml"/>
    
   </session-factory>
</hibernate-configuration>

Customer.java

public class Customer {

    /*
     * 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_linkman` VARCHAR(64) 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;
     */
    private Long cust_id;

    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_linkman;
    private String cust_phone;
    private String cust_mobile;

    set/get ...

    @Override
    public String toString() {
        return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
    }
}

Customer.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">
   <!-- 配置表与实体对象的关系 -->
   <!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="com.inke.domain" >
    <!-- 
        class元素: 配置实体与表的对应关系的
            name: 完整类名
            table:数据库表名
     -->
    <class name="com.inke.domain.Customer" table="cst_customer" >
        <!-- id元素:配置主键映射的属性
                name: 填写主键对应属性名
                column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
                type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
                        每个类型有三种填法: java类型|hibernate类型|数据库类型
                not-null(可选):配置该属性(列)是否不能为空. 默认值:false
                length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
         -->
        <id name="cust_id"  >
            <!-- generator:主键生成策略(明天讲) -->
            <generator class="native"></generator>
        </id>
        <!-- property元素:除id之外的普通属性映射
                name: 填写属性名
                column(可选): 填写列名
                type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
                        每个类型有三种填法: java类型|hibernate类型|数据库类型
                not-null(可选):配置该属性(列)是否不能为空. 默认值:false
                length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
         -->
        <property name="cust_name" column="cust_name" >
            <!--  <column name="cust_name" sql-type="varchar" ></column> -->
        </property>
        <property name="cust_source" column="cust_source" ></property>
        <property name="cust_industry" column="cust_industry" ></property>
        <property name="cust_level" column="cust_level" ></property>
        <property name="cust_linkman" column="cust_linkman" ></property>
        <property name="cust_phone" column="cust_phone" ></property>
        <property name="cust_mobile" column="cust_mobile" ></property>
    </class>
</hibernate-mapping>

测试

public class Test1 {
    
   private static SessionFactory sessionFactory;
    
   @Test
   public void test1() {
       Configuration configuration = new Configuration();
       configuration.configure();
       sessionFactory = configuration.buildSessionFactory();
       Session session = sessionFactory.openSession();
       Transaction transaction = session.beginTransaction();
    
       Customer customer = new Customer();
       customer.setCust_name("百度");
       session.save(customer);
    
       transaction.commit();
       sessionFactory.close();
   }
}



API 学习

Configuration对象

// Configuration功能: 配置加载类.用于加载主配置,orm元数据加载
public class Demo {

    @Test
    public void fun1(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration();
        //2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
        conf.configure();
        //3 读取指定orm元数据(扩展),如果主配置中已经引入映射配置.不需要手动加载
        //conf.addResource(resourceName);
        //conf.addClass(persistentClass);
        
        //4 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        
    }
}

SessionFactory对象

// SessionFactory功能: 用于创建操作数据库核心对象session对象的工厂.
//                   简单说功能就一个---创建session对象
//注意:1.sessionfactory 负责保存和使用所有配置信息.消耗内存资源非常大.
//    2.sessionFactory属于线程安全的对象设计.
//结论: 保证在web项目中,只创建一个sessionFactory.
public class Demo2 {

    @Test
    public void fun1(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration();
        //2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
        conf.configure();
        //3 读取指定orm元数据(扩展),如果主配置中已经引入映射配置.不需要手动加载
        //conf.addResource(resourceName);
        //conf.addClass(persistentClass);
        
        //4 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //--------------------------------------------------
        //5 获得session
        //打开一个新的session对象
        sf.openSession();
        //获得一个与线程绑定的session对象(明天讲解)
        sf.getCurrentSession();
    }
}

Session对象

//session对象功能: 表达hibernate框架与数据库之间的连接(会话).
//session类似于JDBC年代的connection对象. 还可以完成对数据库中数据的增删改查操作.
//session是hibernate操作数据库的核心对象
public class Demo3 {

    @Test
    //事务操作
    public void fun1(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration().configure();
        //2 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //3 获得session
        Session session = sf.openSession();
        //4 session获得操作事务的Transaction对象
        //获得操作事务的tx对象
        //Transaction tx = session.getTransaction();
        //开启事务并获得操作事务的tx对象(建议使用)
        Transaction tx2 = session.beginTransaction();
        //----------------------------------------------
        
        
        //----------------------------------------------
        tx2.commit();//提交事务
        tx2.rollback();//回滚事务
        session.close();//释放资源
        sf.close();//释放资源
    }
    
    @Test
    //session的新增
    public void fun2(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration().configure();
        //2 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //3 获得session
        Session session = sf.openSession();
        //4 session获得操作事务的Transaction对象
        //获得操作事务的tx对象
        //Transaction tx = session.getTransaction();
        //开启事务并获得操作事务的tx对象(建议使用)
        Transaction tx2 = session.beginTransaction();
        //----------------------------------------------
        Customer c = new Customer();
        c.setCust_name("谷歌");
        
        session.save(c);
        //----------------------------------------------
        tx2.commit();//提交事务
        session.close();//释放资源
        sf.close();//释放资源
    }
    
    @Test
    //session的查询
    //查询id为1的customer对象
    public void fun3(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration().configure();
        //2 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //3 获得session
        Session session = sf.openSession();
        //4 session获得操作事务的Transaction对象
        //获得操作事务的tx对象
        //Transaction tx = session.getTransaction();
        //开启事务并获得操作事务的tx对象(建议使用)
        Transaction tx2 = session.beginTransaction();
        //----------------------------------------------
        
        Customer customer = session.get(Customer.class, 1l);
        
        System.out.println(customer);
        //----------------------------------------------
        tx2.commit();//提交事务
        session.close();//释放资源
        sf.close();//释放资源
    }
    
    @Test
    //session的修改
    //修改id为1的customer对象的name属性为脸书
    public void fun4(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration().configure();
        //2 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //3 获得session
        Session session = sf.openSession();
        //4 session获得操作事务的Transaction对象
        //获得操作事务的tx对象
        //Transaction tx = session.getTransaction();
        //开启事务并获得操作事务的tx对象(建议使用)
        Transaction tx2 = session.beginTransaction();
        //----------------------------------------------
        //1 获得要修改的对象
        Customer c = session.get(Customer.class, 1l);
        //2 修改
        c.setCust_name("脸书");
        //3 执行update
        session.update(c);
        //----------------------------------------------
        tx2.commit();//提交事务
        session.close();//释放资源
        sf.close();//释放资源
    }
    
    @Test
    //session的删除
    //删除id为1的customer对象
    public void fun5(){
        //1 创建,调用空参构造
        Configuration conf = new Configuration().configure();
        //2 根据配置信息,创建 SessionFactory对象
        SessionFactory sf = conf.buildSessionFactory();
        //3 获得session
        Session session = sf.openSession();
        //4 session获得操作事务的Transaction对象
        //获得操作事务的tx对象
        Transaction tx = session.getTransaction();
        tx.begin();
        //开启事务并获得操作事务的tx对象(建议使用)
        Transaction tx2 = session.beginTransaction();
        //----------------------------------------------
        //1 获得要修改的对象
        Customer c = session.get(Customer.class, 1l);
        //2 调用delete删除对象
        session.delete(c);
        //----------------------------------------------
        tx2.commit();//提交事务
        session.close();//释放资源
        sf.close();//释放资源
    }
}



hibernate实体规则

实体类创建的注意事项

  1. 持久化类提供无参数构造
  2. 成员变量私有,提供共有get/set方法访问.需提供属性
  3. 持久化类中的属性,应尽量使用包装类型(数据库 null 无法给 基本类型赋值)
  4. 持久化类需要提供主键.与数据库中的主键列对应,没有主键不能映射到 hibernate。
  5. 不要用final修饰class
    • hibernate使用cglib代理生成代理对象.代理对象是继承被代理对象.如果被final修饰.将无法生成代理.



主键类型

自然主键(少见)

表的业务列中,有某业务列符合,必须有,并且不重复的特征时,该列可以作为主键使用,例如身份证号,但是不推荐.

代理主键(常见)

表的业务列中,没有某业务列符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键,例如:id,uuid等,推荐



主键生成策略

代理主键

  • identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键.
    • sequence: Oracle中的主键生成策略.

    • increment(了解): 主键自增.由hibernate来维护.每次插入前会先查询表中id最大值.+1作为新主键值,具有线程安全问题.

    • hilo(了解): 高低位算法.主键自增.由hibernate来维护.开发时不使用.

    • native(推荐):hilo+sequence+identity 自动三选一策略.

    • uuid(推荐): 产生随机字符串作为主键. 主键类型必须为string 类型.

<?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 package="cn.itheima.domain" >
    <class name="Customer" table="cst_customer" >
        <id name="cust_id"  >
            <!-- generator:主键生成策略.就是每条记录录入时,主键的生成规则.(7个)
                    identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键.
                    sequence: Oracle中的主键生成策略.
                    increment(了解): 主键自增.由hibernate来维护.每次插入前会先查询表中id最大值.+1作为新主键值.            
                    hilo(了解): 高低位算法.主键自增.由hibernate来维护.开发时不使用.
                    native:hilo+sequence+identity 自动三选一策略.
                    uuid: 产生随机字符串作为主键. 主键类型必须为string 类型.
                    assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.
                    
             -->
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name" ></property>
        <property name="cust_source" column="cust_source" ></property>
        <property name="cust_industry" column="cust_industry" ></property>
        <property name="cust_level" column="cust_level" ></property>
        <property name="cust_linkman" column="cust_linkman" ></property>
        <property name="cust_phone" column="cust_phone" ></property>
        <property name="cust_mobile" column="cust_mobile" ></property>
    </class>
</hibernate-mapping>

自然主键

  • assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.



hibernate中的对象状态

对象分为三种状态

  • 瞬时状态
    • 没有id,没有在session缓存中
  • 持久化状态
    • 有id,在session缓存中
  • 游离|托管状态
    • 有id,没有在session缓存中
//测试对象的三种状态
public class Demo {

    @Test
    //查看三种状态
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        Customer c = new Customer(); // 没有id, 没有与session关联 => 瞬时状态
        
        c.setCust_name("联想"); // 瞬时状态
        
        session.save(c); // 持久化状态, 有id,有关联
        
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }
    
    @Test
    //三种状态特点
    //save方法: 其实不能理解成保存.理解成将瞬时状态转换成持久状态的方法
    //主键自增 : 执行save方法时,为了将对象转换为持久化状态.必须生成id值.所以需要执行insert语句生成.
    //increment: 执行save方法,为了生成id.会执行查询id最大值的sql语句.
    public void fun2(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        Customer c = new Customer(); // 没有id, 没有与session关联 => 瞬时状态
        
        c.setCust_name("联想"); // 瞬时状态
        
        session.save(c); // 持久化状态, 有id,有关联
        
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }
    
    @Test
    //三种状态特点
    // 持久化状态特点: 持久化状态对象的任何变化都会自动同步到数据库中.
    public void fun3(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        
        Customer c = session.get(Customer.class, 1l);//持久化状态对象
        
        c.setCust_name("微软公司");
        
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }
}



hibernate进阶-一级缓存

缓存:提高效率.hibernate中的一级缓存也是为了提高操作数据库的效率.

提高效率手段1:提高查询效率


提高效率手段2:减少不必要的修改语句发送




hibernate中的事务

事务特性

a 原子性(像物理原子一样,最小而不可分隔,全成功或全失败)
c 一致性(例如,转账 相加总量不变)
i 隔离性(隔离级别)
d 持久性(数据写到硬盘等持久化的物质上)

事务并发问题

1.脏读(查询正在操作还没有提交的数据)
2.不可重复度(两次查询数据不一致,中间可能别人操作了数据)
3.幻|虚读(删除记录的同时,别人又插入记录了,产生幻觉了)

事务的隔离级别

(表示上面的并发问题代表的1,2,3)

读未提交- 123
读已提交 - 23
可重复读(mysql默认级别)-3
串行化 - 没有问题,效率太低,不考虑。

在hibernate中指定数据库的隔离级别

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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>
    
        <!-- 
        #hibernate.dialect org.hibernate.dialect.MySQLDialect
        #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
        #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
        #hibernate.connection.driver_class com.mysql.jdbc.Driver
        #hibernate.connection.url jdbc:mysql:///test
        #hibernate.connection.username gavin
        #hibernate.connection.password
         -->
         <!-- 数据库驱动 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <!-- 数据库url -->
        <property name="hibernate.connection.url">jdbc:mysql:///hibernate_32</property>
         <!-- 数据库连接用户名 -->
        <property name="hibernate.connection.username">root</property>
         <!-- 数据库连接密码 -->
        <property name="hibernate.connection.password">1234</property>
        <!-- 数据库方言
            不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
            sql99标准: DDL 定义语言  库表的增删改查
                      DCL 控制语言  事务 权限
                      DML 操纵语言  增删改查
            注意: MYSQL在选择方言时,请选择最短的方言.
         -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        
        
        <!-- #hibernate.show_sql true 
             #hibernate.format_sql true
        -->
        <!-- 将hibernate生成的sql语句打印到控制台 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 将hibernate生成的sql语句格式化(语法缩进) -->
        <property name="hibernate.format_sql">true</property>
        <!-- 
        ## auto schema export  自动导出表结构. 自动建表
        #hibernate.hbm2ddl.auto create      自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
        #hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
        #hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
        #hibernate.hbm2ddl.auto validate    校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
         -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 引入orm元数据
            路径书写: 填写src下的路径
         -->
         <!-- 指定hibernate操作数据库时的隔离级别 
            #hibernate.connection.isolation 1|2|4|8     
            0001    1   读未提交
            0010    2   读已提交
            0100    4   可重复读
            1000    8   串行化
         -->
         <property name="hibernate.connection.isolation">4</property>
         <!-- 指定session与当前线程绑定 -->
         <property name="hibernate.current_session_context_class">thread</property>
         
        <mapping resource="cn/itheima/domain/Customer.hbm.xml" />
        
    </session-factory>
</hibernate-configuration>

在项目中如何管理事务

业务开始之前打开事务,业务执行之后提交事务. 执行过程中出现异常.回滚事务.

dao层操作数据库需要用到session对象.
service控制事务也是使用session对象完成.
我们要确保dao层和service层使用的使用同一个session对象

在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了. 我们开发人员只需要调用sf.getCurrentSession()方法即可获得与当前线程绑定的session对象,底层还是 ThreadLocal

注意1:

调用getCurrentSession方法必须配置

<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
注意2:

通过getCurrentSession方法获得的session对象.当事务提交时,session会自动关闭.不要手动调用close关闭,手动 close 会报异常。



hibernate中的批量查询(概述)

HQL查询-hibernate Query Language

(多表查询,但不复杂时使用)
Hibernate独家查询语言,属于面向对象的查询语言

基本查询

//测试HQL语句
public class Demo {

    @Test
    //基本查询
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        //-------------------------------------------
        //1> 书写HQL语句
//      String hql = " from cn.itheima.domain.Customer ";
//      只有一个类名的话,那么可以不写包名。
        String hql = " from Customer "; // 查询所有Customer对象
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //3> 根据查询对象获得查询结果
        List<Customer> list = query.list(); // 返回list结果
        //query.uniqueResult();//接收唯一的查询结果
        
        System.out.println(list);
        //-------------------------------------------
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }
}

条件查询

@Test
    //条件查询
    //HQL语句中,不可能出现任何数据库相关的信息的
    public void fun2(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        //-------------------------------------------
        //1> 书写HQL语句
        String hql = " from Customer where cust_id = 1 "; // 查询所有Customer对象
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //3> 根据查询对象获得查询结果
        Customer c = (Customer) query.uniqueResult();
        
        System.out.println(c);
        //-------------------------------------------
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }

排序查询

@Test
    //排序
    public void fun2(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql1 = " from  cn.itcast.domain.Customer order by cust_id asc ";//完整写法
        String hql2 = " from  cn.itcast.domain.Customer order by cust_id desc ";//完整写法
        
        Query query = session.createQuery(hql2);
        
        List list = query.list();
        
        System.out.println(list);
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }
?号占位符
@Test
//条件查询
//问号占位符
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1> 书写HQL语句
    String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
    //2> 根据HQL语句创建查询对象
    Query query = session.createQuery(hql);
    //设置参数
    //query.setLong(0, 1l);
    query.setParameter(0, 1l);
    //3> 根据查询对象获得查询结果
    Customer c = (Customer) query.uniqueResult();
    
    System.out.println(c);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联 
}
命名占位符
@Test
    //条件查询
    //命名占位符
    public void fun4(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        //-------------------------------------------
        //1> 书写HQL语句
        String hql = " from Customer where cust_id = :cust_id "; // 查询所有Customer对象
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置参数
        query.setParameter("cust_id", 1l);
        //3> 根据查询对象获得查询结果
        Customer c = (Customer) query.uniqueResult();
        
        System.out.println(c);
        //-------------------------------------------
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }

分页查询

@Test
    //分页查询
    public void fun5(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        //-------------------------------------------
        //1> 书写HQL语句
        String hql = " from Customer  "; // 查询所有Customer对象
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置分页信息 limit ?,?
        query.setFirstResult(1);
        query.setMaxResults(1);
        //3> 根据查询对象获得查询结果
        List<Customer> list =  query.list();
        
        System.out.println(list);
        //-------------------------------------------
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }

统计查询

@Test
//统计查询
//count 计数
//sum   求和
//avg   平均数
//max
//min
public void fun5(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    //----------------------------------------------------
    String hql1 = " select count(*) from  cn.itcast.domain.Customer  ";//完整写法
    String hql2 = " select sum(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql3 = " select avg(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql4 = " select max(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql5 = " select min(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    
    Query query = session.createQuery(hql5);
    
    Number number  = (Number) query.uniqueResult();
    
    System.out.println(number);
    //----------------------------------------------------
    tx.commit();
    session.close();
    
}

投影查询

就是查询默写字段名字,不是全部* 。

@Test
//投影查询
public void fun6(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    //----------------------------------------------------
    String hql1 = " select cust_name from  cn.itcast.domain.Customer  ";
    // 字段查询到自动封装Object[] 中
    String hql2 = " select cust_name,cust_id from  cn.itcast.domain.Customer  ";
    // 字段查询到自动封装到 Model中,同时Customer需要创建2个参数的构造函数。
    String hql3 = " select new Customer(cust_id,cust_name) from  cn.itcast.domain.Customer  ";
    
    Query query = session.createQuery(hql3);
    
    List list = query.list();
    
    System.out.println(list);
    
    //----------------------------------------------------
    tx.commit();
    session.close();
    
}

多表查询

//学习HQL语法(不常用) - 多表查询语法
public class Demo2 {
    //回顾-原生SQL
    // 交叉连接-笛卡尔积(避免)
//      select * from A,B 
    // 内连接
//      |-隐式内连接
//          select * from A,B  where b.aid = a.id
//      |-显式内连接
//          select * from A inner join B on b.aid = a.id
    // 外连接
//      |- 左外
//          select * from A left [outer] join B on b.aid = a.id
//      |- 右外
//          select * from A right [outer] join B on b.aid = a.id
//---------------------------------------------------------------------
//HQL的多表查询
        //内连接(迫切)
        //外连接
//          |-左外(迫切)
//          |-右外(迫切)
    
    @Test
    //HQL 内连接 => 将连接的两端对象分别返回.放到数组中.
    public void fun1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c inner join c.linkMens ";
        
        Query query = session.createQuery(hql);
        
        List<Object[]> list = query.list();
        
        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }
    
    @Test
    //HQL 迫切内连接 => 帮我们进行封装.返回值就是一个对象
    public void fun2(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c inner join fetch c.linkMens ";
        
        Query query = session.createQuery(hql);
        
        List<Customer> list = query.list();
        
        System.out.println(list);
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }
    
    @Test
    //HQL 左外连接 => 将连接的两端对象分别返回.放到数组中.
    public void fun3(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c left join c.linkMens ";
        
        Query query = session.createQuery(hql);
        
        List<Object[]> list = query.list();
        
        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }
    @Test
    //HQL 右外连接 => 将连接的两端对象分别返回.放到数组中.
    public void fun4(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c right join c.linkMens ";
        
        Query query = session.createQuery(hql);
        
        List<Object[]> list = query.list();
        
        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }   
}

Criteria查询

(单表条件查询)
Hibernate自创的无语句面向对象查询

基本查询

//测试Criteria查询
public class Demo {

    @Test
    //基本查询
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 控制事务
        Transaction tx = session.beginTransaction();
        //3执行操作
        //-------------------------------------------
        
        //查询所有的Customer对象
        Criteria criteria = session.createCriteria(Customer.class);
        
        List<Customer> list = criteria.list();
        
        System.out.println(list);
        
//      Customer c = (Customer) criteria.uniqueResult();
        
        //-------------------------------------------
        //4提交事务.关闭资源
        tx.commit();
        session.close();// 游离|托管 状态, 有id , 没有关联
    }
}

条件查询

@Test
//条件查询
//HQL语句中,不可能出现任何数据库相关的信息的
// >                gt
// >=               ge
// <                lt
// <=               le
// ==               eq
// !=               ne
// in               in
// between and      between
// like             like
// is not null      isNotNull
// is null          isNull
// or               or
// and              and
public void fun2(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //添加查询参数 => 查询cust_id为1的Customer对象
    criteria.add(Restrictions.eq("cust_id", 1l));
    //执行查询获得结果
    Customer c = (Customer) criteria.uniqueResult();
    System.out.println(c);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

分页 查询

@Test
//分页查询
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //设置分页信息 limit ?,?
    criteria.setFirstResult(1);
    criteria.setMaxResults(2);
    //执行查询
    List<Customer> list = criteria.list();
    
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

设置查询总记录数

@Test
//查询总记录数
public void fun4(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //创建criteria查询对象
    Criteria criteria = session.createCriteria(Customer.class);
    //设置查询的聚合函数 => 总行数
    criteria.setProjection(Projections.rowCount());
    //执行查询
    Long count = (Long) criteria.uniqueResult();
    
    System.out.println(count);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

排序

@Test
//排序语法 
public void fun4(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    //----------------------------------------------------
    
    Criteria c = session.createCriteria(Customer.class);
    
    c.addOrder(Order.asc("cust_id"));
    //c.addOrder(Order.desc("cust_id"));
    
    List<Customer> list = c.list();
    
    System.out.println(list);
    
    //----------------------------------------------------
    tx.commit();
    session.close();
    
}

离线查询

区别就是创建的时候是否需要 session

非离线
离线
//学习离线Criteria
public class Demo2 {
    
    @Test
    public void fun1(){
        //Service/web层
        DetachedCriteria dc  = DetachedCriteria.forClass(Customer.class);
        
        dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致)
        
        //----------------------------------------------------
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        Criteria c = dc.getExecutableCriteria(session);
        
        List list = c.list();
        
        System.out.println(list);
        //----------------------------------------------------
        tx.commit();
        session.close();
        
    }
    
}
演示

原生SQL查询

(复杂的业务查询)

基本查询

返回数组List
@Test
//基本查询
public void fun1(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer";
    
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
    
    //3 调用方法查询结果
    List<Object[]> list = query.list();
    //query.uniqueResult();
    
    for(Object[] objs : list){
        System.out.println(Arrays.toString(objs));
    }
    
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
    
    
}
返回对象List
@Test
//基本查询
public void fun2(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer";
    
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
    
    //3 调用方法查询结果
    List<Customer> list = query.list();
    
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

条件查询

@Test
//条件查询
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer where cust_id = ? ";
    
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
    
    query.setParameter(0, 1l);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
    
    //3 调用方法查询结果
    List<Customer> list = query.list();
    
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
}

分页查询

@Test
//分页查询
public void fun4(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 控制事务
    Transaction tx = session.beginTransaction();
    //3执行操作
    //-------------------------------------------
    //1 书写sql语句
    String sql = "select * from cst_customer  limit ?,? ";
    
    //2 创建sql查询对象
    SQLQuery query = session.createSQLQuery(sql);
    
    query.setParameter(0, 0);
    query.setParameter(1, 1);
    //指定将结果集封装到哪个对象中
    query.addEntity(Customer.class);
    
    //3 调用方法查询结果
    List<Customer> list = query.list();
    
    System.out.println(list);
    //-------------------------------------------
    //4提交事务.关闭资源
    tx.commit();
    session.close();// 游离|托管 状态, 有id , 没有关联
    
    
}



多表查询

一对多|多对一

关系表达

表中的表达
表中的表达
实体中的表达
orm元数据中表达
一对多

Customer.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 package="cn.itcast.domain" >
    <class name="Customer" table="cst_customer" >
        <id name="cust_id"  >
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name" ></property>
        <property name="cust_source" column="cust_source" ></property>
        <property name="cust_industry" column="cust_industry" ></property>
        <property name="cust_level" column="cust_level" ></property>
        <property name="cust_linkman" column="cust_linkman" ></property>
        <property name="cust_phone" column="cust_phone" ></property>
        <property name="cust_mobile" column="cust_mobile" ></property>
    
        <!-- 集合,一对多关系,在配置文件中配置 -->
        <!-- 
            name属性:集合属性名
            column属性: 外键列名(多方存一方的外键列名)
            class属性: 与我关联的对象完整类名
         -->
         <!-- 
            级联操作:   cascade
                save-update: 级联保存更新
                delete:级联删除
                all:save-update+delete
            级联操作: 简化操作.目的就是为了少些两行代码.
          -->
          <!-- inverse属性: 外键配置关系是否维护. 
                true: customer不维护关系
                false(默认值): customer维护关系
                
            inverse属性: 性能优化.提高关系维护的性能.
            原则: 无论怎么放弃,总有一方必须要维护关系.
            一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
          -->
        <set name="linkMens" inverse="true" cascade="save-update"  >
            <key column="lkm_cust_id" ></key>
            <one-to-many class="LinkMan" />
        </set>
        
    
    </class>
</hibernate-mapping>
多对一

LinkMan.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 package="cn.itcast.domain" >
    <class name="LinkMan" table="cst_linkman" >
        <id name="lkm_id"  >
            <generator class="native"></generator>
        </id>
        <property name="lkm_gender"  ></property>
        <property name="lkm_name"  ></property>
        <property name="lkm_phone"  ></property>
        <property name="lkm_email"  ></property>
        <property name="lkm_qq"  ></property>
        <property name="lkm_mobile"  ></property>
        <property name="lkm_memo"  ></property>
        <property name="lkm_position"  ></property>
        
        <!-- 多对一 -->
        <!-- 
            name属性:引用属性名
            column属性: 外键列名(多方存一方的外键列名)
            class属性: 与我关联的对象完整类名
         -->
          <!-- 
            级联操作:   cascade
                save-update: 级联保存更新
                delete:级联删除
                all:save-update+delete
            级联操作: 简化操作.目的就是为了少些两行代码.
          -->
          <!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方.  -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
        </many-to-one>
    </class>
</hibernate-mapping>

操作

操作关联属性

使用级联操作

//一对多|多对一关系操作
public class Demo {
    @Test
    //保存客户 以及客户 下的联系人
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        Customer c = new Customer();
        c.setCust_name("百度公司");
        
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("李彦宏");
        
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("小度");
        
        //表达一对多,客户下有多个联系人
        c.getLinkMens().add(lm1);
        c.getLinkMens().add(lm2);
        
        //表达对对对,联系人属于哪个客户
        lm1.setCustomer(c);
        lm2.setCustomer(c);
        
        
        session.save(c);
//      使用级联操作,不用互相保存
//      session.save(lm1);
//      session.save(lm2);
        
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
    
    @Test
    //为客户增加联系人
    public void fun2(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        //1> 获得要操作的客户对象
        Customer c = session.get(Customer.class,1l);
        //2> 创建联系人
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("郝强勇");
        //3> 将联系人添加到客户,将客户设置到联系人中
        c.getLinkMens().add(lm1);
        lm1.setCustomer(c);
        //4> 执行保存
        session.save(lm1);
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
    
    @Test
    //为客户删除联系人
    public void fun3(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        //1> 获得要操作的客户对象
        Customer c = session.get(Customer.class,1l);
        //2> 获得要移除的联系人
        LinkMan lm = session.get(LinkMan.class, 3l);
        //3> 将联系人从客户集合中移除
        c.getLinkMens().remove(lm);
        lm.setCustomer(null);
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
        
}
<!-- 
级联操作:   cascade
    save-update: 级联保存更新
    delete:级联删除
    all:save-update+delete
级联操作: 简化操作.目的就是为了少些两行代码.
-->
<!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方.  -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
</many-to-one>
        
        

//测试级联操作
public class Demo2 {
    @Test
    //保存客户 以及客户 下的联系人
    //cascade:save-update
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        Customer c = new Customer();
        c.setCust_name("百度公司");
        
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("李彦宏");
        
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("小度");
        
        //表达一对多,客户下有多个联系人
        c.getLinkMens().add(lm1);
        c.getLinkMens().add(lm2);
        
        //表达对对对,联系人属于哪个客户
        lm1.setCustomer(c);
        lm2.setCustomer(c);
        
        
        session.save(c);
//      session.save(lm1);
//      session.save(lm2);
        
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
    
    @Test
    //测试删除客户时,级联删除客户下的联系人
    //cascade:delete
    public void fun2(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        //1> 获得要操作的客户对象
        Customer c = session.get(Customer.class,1l);
        //2>调用delete删除客户
        session.delete(c);
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
    
    @Test
    //保存联系人以及联系人对应的客户
    //cascade:save-update
    public void fun3(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        Customer c = new Customer();
        c.setCust_name("北大青鸟");
        
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("刘总");
        
        //表达一对多,客户下有多个联系人
        c.getLinkMens().add(lm1);
        
        //表达多对一,联系人属于哪个客户
        lm1.setCustomer(c);
        
        
        session.save(lm1);
        
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }       
}



进阶操作

结论:

简化操作.一定要用:save-update,不建议使用delete,delete 会把外键关联的记录也删除,太危险了.

关系维护

inverse属性: 性能优化,提高关系维护的性能。
原则: 无论怎么放弃,总有一方必须要维护主键关系。
inverse="true"放弃维护。

一对多关系中: 一的一方放弃,也只能一的一方放弃。
多的一方不能放弃,外键在多方的表中。

<set name="linkMens" inverse="true" cascade="save-update"  >
  <key column="lkm_cust_id" ></key>
  <one-to-many class="LinkMan" />
</set>
//操作进阶--关系维护属性
public class Demo3 {
    @Test
    //保存客户 以及客户 下的联系人
    public void fun1(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        Customer c = new Customer();
        c.setCust_name("百度");
        
        LinkMan lm1 = new LinkMan();
        lm1.setLkm_name("李彦宏");
        
        LinkMan lm2 = new LinkMan();
        lm2.setLkm_name("小度");
        
        //表达一对多,客户下有多个联系人. 
        // 如果客户放弃维护与联系人的关系. 维护关系的代码可以省略
        //c.getLinkMens().add(lm1);
        //c.getLinkMens().add(lm2);
        
        //表达多对一,联系人属于哪个客户
        lm1.setCustomer(c);
        lm2.setCustomer(c);
        
        
        session.save(c);
        session.save(lm1);
        session.save(lm2);
        
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }   
}
删除客户

因为联系人表外键了客户表,所以不能直接删除客户。

  • 方式一:级联:cascade="delete" ,删除客户表同时也会删除联系人表。
  • 方式二:外键关系:inverse="false" ,删除客户表,同时联系人表外键变为 null。
@Test
//删除客户
public void fun2(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 开启事务
    Transaction tx = session.beginTransaction();
    //-------------------------------------------------
    //3操作
    Customer customer = session.get(Customer.class, 1l);
    
    session.delete(customer);
    //-------------------------------------------------
    //4提交事务
    tx.commit();
    //5关闭资源
    session.close();
}



多对多

关系表达

表中
对象中
orm元数据

Role.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 package="cn.itcast.domain" >
    <class name="Role" table="sys_role" >
        <id name="role_id"  >
            <generator class="native"></generator>
        </id>
        <property name="role_name"  ></property>
        <property name="role_memo"  ></property>

    <!-- 使用inverse属性
            true: 放弃维护外键关系
            false(默认值):维护关系
            
        结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
             一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
             那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
         -->        
        <set name="users" table="sys_user_role" inverse="true" >
            <key column="role_id" ></key>
            <many-to-many class="User" column="user_id" ></many-to-many>
        </set>
    </class>
</hibernate-mapping>

User.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 package="cn.itcast.domain" >
    <class name="User" table="sys_user" >
        <id name="user_id"  >
            <generator class="native"></generator>
        </id>
        <property name="user_code"  ></property>
        <property name="user_name"  ></property>
        <property name="user_password"  ></property>
        <property name="user_state"  ></property>
    
        <!-- 多对多关系表达 -->
        <!-- 
            name: 集合属性名
            table: 配置中间表名
            key
             |-column:外键,别人引用"我"的外键列名
             class: 我与哪个类是多对多关系
             column:外键.我引用比人的外键列名
         -->
         <!-- cascade级联操作:
                    save-update: 级联保存更新
                    delete:级联删除
                    all:级联保存更新+级联删除
            结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
                 如果使用delete操作太过危险.尤其在多对多中.不建议使用.
                     -->
        <set name="roles" table="sys_user_role" cascade="save-update" >
            <key column="user_id" ></key>
            <many-to-many class="Role" column="role_id" ></many-to-many>
        </set>
    
    </class>
</hibernate-mapping>
注意:

中间表报错,必须只能一方维护外键关系,如果双方都维护外键关系,那么中间表会插入练体能一样的记录,造成中间表的主键重复。

结论:

将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护.

操作

操作关联属性

//多对多关系操作
public class Demo {

    //为郝强勇解除一个角色
    @Test
    public void fun4(){
        //1 获得session
        Session session = HibernateUtils.openSession();
        //2 开启事务
        Transaction tx = session.beginTransaction();
        //-------------------------------------------------
        //3操作
        //1> 获得郝强勇用户
        User user = session.get(User.class, 1l);
        //2> 获得要操作的角色对象(保洁,保安)
        Role r1 = session.get(Role.class, 1l);
        Role r2 = session.get(Role.class, 2l);
        //3> 将角色从用户的角色集合中移除
        user.getRoles().remove(r1);
        user.getRoles().remove(r2);
        
        //-------------------------------------------------
        //4提交事务
        tx.commit();
        //5关闭资源
        session.close();
    }
}
操作进阶
inverse属性
  • true: 放弃维护外键关系
  • false(默认值):维护关系
//保存员工以及角色
@Test
public void fun1(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 开启事务
    Transaction tx = session.beginTransaction();
    //-------------------------------------------------
    //3操作
    //1> 创建两个 User
    User u1 = new User();
    u1.setUser_name("郝强勇");
    
    User u2 = new User();
    u2.setUser_name("金家德");
    
    //2> 创建两个 Role
    Role r1 = new Role();
    r1.setRole_name("保洁");
    
    Role r2 = new Role();
    r2.setRole_name("保安");
    //3> 用户表达关系
    u1.getRoles().add(r1);
    u1.getRoles().add(r2);
    
    u2.getRoles().add(r1);
    u2.getRoles().add(r2);
    
    //4> 角色表达关系
    r1.getUsers().add(u1);
    r1.getUsers().add(u2);
    
    r2.getUsers().add(u1);
    r2.getUsers().add(u2);
    
    //5> 调用Save方法一次保存
    session.save(u1);
    session.save(u2);
    session.save(r1);
    session.save(r2);
    //-------------------------------------------------
    //4提交事务
    tx.commit();
    //5关闭资源
    session.close();
}

注意:
中间表报错,必须只能一方维护外键关系,如果双方都维护外键关系,那么中间表会插入练体能一样的记录,造成中间表的主键重复


cascade属性
  • cascade级联操作:
  • save-update: 级联保存更新
  • delete:级联删除
  • all:级联保存更新+级联删除
//为郝强勇新增一个角色
@Test
public void fun3(){
    //1 获得session
    Session session = HibernateUtils.openSession();
    //2 开启事务
    Transaction tx = session.beginTransaction();
    //-------------------------------------------------
    //3操作
    //1> 获得郝强勇用户
    User user = session.get(User.class, 1l);
    //2> 创建公关角色
    Role r = new Role();
    r.setRole_name("男公关");
    //3> 将角色添加到用户中
    user.getRoles().add(r);
    //4> 将角色转换为持久化
    //session.save(r);//增加级联操作可以省略这一行
    //-------------------------------------------------
    //4提交事务
    tx.commit();
    //5关闭资源
    session.close();
}

结论: cascade简化代码书写.该属性使不使用无所谓.
建议要用只用save-update.
如果使用delete操作太过危险.尤其在多对多中.不建议使用.



查询优化

类级别查询

  • get方法:没有任何策略.调用即立即查询数据库加载数据.

  • load方法: 应用类级别的加载策略

    • lazy="true"(默认值), 查询类时,会返回代理对象。会在使用属性时,根据关联的session查询数据库.加载数据.

    • lazy="false"。load方法会与get方法没有任何区别.调用时即加载数据.
      结论:为了提高效率.建议使用延迟加载(懒加载)

      • 注意:使用懒加载时要确保,调用属性加载数据时,session还是打开的.不然会抛出异常

Customer.hbm.xml 属性:lazy="false"

<?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 package="cn.itcast.domain" >
    <class name="Customer" table="cst_customer" lazy="false" >
        <id name="cust_id"  >
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name" ></property>
        <property name="cust_source" column="cust_source" ></property>
        <property name="cust_industry" column="cust_industry" ></property>
        <property name="cust_level" column="cust_level" ></property>
        <property name="cust_linkman" column="cust_linkman" ></property>
        <property name="cust_phone" column="cust_phone" ></property>
        <property name="cust_mobile" column="cust_mobile" ></property>
    
    <!-- 
        lazy属性: 决定是否延迟加载
            true(默认值): 延迟加载,懒加载
            false: 立即加载
            extra: 极其懒惰
        fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据
            select(默认值): 单表查询加载
            join: 使用多表查询加载集合
            subselect:使用子查询加载集合
     -->
     <!-- batch-size: 抓取集合的数量为3.
            抓取客户的集合时,一次抓取几个客户的联系人集合.
      -->
        <set name="linkMens" batch-size="3" fetch="join" lazy="proxy" >
            <key column="lkm_cust_id" ></key>
            <one-to-many class="LinkMan" />
        </set>
        
    
    </class>
</hibernate-mapping>

关联级别查询

集合策略

关联属性策略

结论:

为了提高效率.fetch的选择上应选择select. lazy的取值应选择 true. 全部使用默认值.

批量抓取

<!-- batch-size: 抓取集合的数量为3.
     抓取客户的集合时,一次抓取几个客户的联系人集合.
-->



参考自某某培训机构。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容