Hibernate框架入门

Hibernate框架

一、什么是hibernate?

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

-----------360百科

  确切的说,hibernate其实就是个ORM(Object Relational Mapping)框架,程序员通过操作对象的方式来操作数据库表的记录。

二、快速入门

  1.从hibernate官网下载hibernate所需要的jar包

  2.搭建环境

      1) 将下载好的 jar包中lib equired的所有jar包导入web工程下的lib文件夹,这些是部署框架的核心jar包

   2) 导入用于连接数据库的驱动jar包

   3) 导入日志jar包(如log4j)

    
      

     

   3.编写相对应的持久化类,并生成相对应的set/get,toString方法

/**
 * javaBean+属于他的映射文件=持久化类
 * @author Administrator
 *
 */
public class Customer {
    //注意:这里的数据类型使用包装类,默认值为null
    private Long cust_id;
    private String cust_name;
    private Long cust_user_id;
    private Long cust_create_id;
    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方法

}

    4.JavaBean所在的包下创建映射的配置文件(默认放在javabean同包下)

       1)* 默认的命名规则为:实体类名.hbm.xml

       2)* 在xml配置文件中引入约束(引入的是hibernate3.0的dtd约束,不要引入4的约束)

      位置:(hibernate-core-5.0.7.Final.jarhibernate-core-5.0.7.Final.jarorg.hibernatehibernate-configuration-3.0.dtd)    

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

       3) *写相对应的映射,此是与数据库进行映射

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 配置类和表结构的映射 -->
    <class name="com.heima.domain.Customer" table="cst_customer">
        <!-- 配置主键 
             见到name属性,JavaBean的属性
             见到column属性,是表结构的字段
        -->
        <id name="cust_id" column="cust_id">
            <!-- 主键生成策略 --> 
            <generator class="native"/>
        </id>
        <!-- 配置其他的属性 -->
        <property name="cust_name" column="cust_name"/>
        <property name="cust_user_id" column="cust_user_id"/>
        <property name="cust_create_id" column="cust_create_id"/>
        <property name="cust_source" column="cust_source"/>
        <property name="cust_industry" column="cust_industry"/>
        <property name="cust_level" column="cust_level"/>
        <property name="cust_linkman" column="cust_linkman"/>
        <property name="cust_phone" column="cust_phone"/>
        <property name="cust_mobile" column="cust_mobile"/>
    </class>
</hibernate-mapping>

    5.编写Hibernate核心的配置文件

       1) 在src目录下,创建名称为hibernate.cfg.xml的配置文件

       2)XML中引入DTD约束,位置:(在hibernate-core-5.0.7.Final.jarhibernate-core-5.0.7.Final.jarorg.hibernatehibernate-configuration-3.0.dtd<?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>
    <!-- 记住:先配置sessionFactory标签,一个数据库对应一个sessionFactory标签-->
    <session-factory>
        <!-- 必须配置的参数,4大参数,数据库的方言 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://192.168.174.130:3306/hibernate_day01</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!-- 数据库的方言 -->
        <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>
        <!-- 开启绑定本地的session -->
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- 生成数据库的表结构
        慎用create:会先删除原有的表结构,然后再生成一个新的
           update:有则再原有基础上增加数据,没有则先创建再添加数据
        -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 映射配置文件 ,需要映入映射的配置文件-->
        <mapping resource="com/heima/domain/Customer.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
 

     6.编写测试

/**
 * 测试Hibernate框架
 * @author Administrator
 *
 */
public class Demo1 {
    /**
     * 测试保存用户
     */
    @Test
    public void testSave1(){
        /**
         * 1.先加载配置文件
         * 2.创建sessionFactory对象,生成Session对象(会话)
         * 3.开启事务
         * 5.编写保存的代码
         * 6.提交事务
         * 7.释放资源
         */
        //1.先加载配置文件
        Configuration config=new Configuration();
        //默认加载src目录下hibenate.cfg.xml的配置文件
        config.configure();
        //创建sessionFactory对象
        SessionFactory factory=config.buildSessionFactory();
        //创建session对象
        Session session=factory.openSession();
        //开启事务
        Transaction tr=session.beginTransaction();
        //编写保存的代码
        Customer c=new Customer();
        //c.setCust_id(cust_id);  主键是自动递增,不需要自己设置
        c.setCust_name("测试3");
        c.setCust_level("2");
        c.setCust_phone("110");
        //保存数据,操作对象就相当于操作数据库的表结构
        session.save(c);
        //提交事务
        tr.commit();
        //释放资源
        session.close();
        factory.close();
        
   }
}

   其中:

     1. Configuration类

      * Configuration对象用于配置并且启动Hibernate。

      * Hibernate应用通过该对象来获得对象-关系映射文件中的元数据,以及动态配置Hibernate的属性,然后创建SessionFactory对象。

   2.SessionFactory

    *它是工厂类,是生成Session对象的工厂类

   *SessionFactory对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存。

三、代码优化

    1.基于每次进行数据处理时都需要调用session,可以将它抽取出来,作为一个公共类

       绑定本地的Session

      1.现在的Hibernate框架中,使用session对象开启事务,所以需要来传递session对象,框架提供了ThreadLocal的方式

      * 需要在hibernate.cfg.xml的配置文件中提供配置

* <property name="hibernate.current_session_context_class">thread</property>   <!--(注意:放在mapping标签之前)-->

       * 使用SessionFactory的getCurrentSession()方法,获取当前的Session对象。并且该Session对象不用手动关闭,线程结束了,会自动关闭

  public static Session getCurrentSession(){

            return factory.getCurrentSession();

        }

    * 注意:想使用getCurrentSession()方法,必须要先配置才能使用。

package com.itheima.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Hibernate框架的工具类
 * @author Mr_佳先森
 *
 */
public class HibernateUtils {
    //ctrl+shift+x将小写字母变成大写,用于常量
    private static final Configuration CONFIG;
    private static final SessionFactory FACTORY;
    static{
        CONFIG=new Configuration().configure();
        FACTORY=CONFIG.buildSessionFactory();
    }
    /**
     * 从构造工厂中获取sesson对象
     * openSession:作为一级缓存,可以提升查询数据效率,但是当session生命周期
     * 结束,程序不可从缓存中获取数据
     */
    public static Session getSession(){
        return FACTORY.openSession();
    }
    /**
     * getCurrentSession():将session封装ThreadLocal中,每个线程调用线程不受
     * 其他线程的影响,即达到线程安全,又避免了悲观锁的效率低下的问题(即使用乐观锁)
     * 需要在核心配置文件中添加
     * @return
     */
    public static Session getCurrentSession(){
        return FACTORY.getCurrentSession();
    }
    public static void main(String[] args) {
        getSession();
    }
}

   其中session接口

    1.Session是在Hibernate中使用最频繁的接口。也被称之为持久化管理器。它提供了和持久化有关的操作,比如添加、修改、删除、加载和查询实体对象

     2.Session是线程不安全的

    3.Session有一个缓存,被称之为Hibernate的一级缓存。每个Session实例都有自己的缓存

    4.session常用的方法:   

save()     delete()  get()  update()  save()  createQuery()

  2.调用工具类   

/**
 * 测试Hibernate框架
 * @author Administrator
 *
 */
public class Demo1 {
    /**
     * 测试工具类
     */
    @Test
    public void testSave2(){
        Session session=HibernateUtils.getSession();
        //开启事务
        Transaction tr=session.beginTransaction();
        //编写保存的代码
        Customer c=new Customer();
        //c.setCust_id(cust_id);  主键是自动递增,不需要自己设置
        c.setCust_name("美美");
        c.setCust_level("2");
        c.setCust_phone("120");
        //保存数据,操作对象就相当于操作数据库的表结构
        session.save(c);
        //提交事务
        tr.commit();
        //释放资源
        session.close();
    }
    /**
     * 测试查询方法,通过主键来查询一条记录
     */
    @Test
    public void testGet(){
        Session session=HibernateUtils.getSession();
        //这里因为是查询事务,所以无需要是事务
        //Transaction tr=session.beginTransaction();
        //这里因为主键是Long类型,所以数字后面要加个L
        Customer coustomer=session.get(Customer.class, 2L);
        System.out.println(coustomer);
        //tr.commit();
        session.close();
    }
    /**
     * 测试删除的方法
     * 注意:删除或者修改之前,要先查询在删除或者修改
     */
    @Test
    public void testDel(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        Customer c=session.get(Customer.class,2L);
        session.delete(c);
        tr.commit();
        session.close();
    }
    /**
     * 测试修改的方法
     */
    @Test
    public void testUpdate(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        Customer c=session.get(Customer.class,3L);
        c.setCust_name("小苍");
        c.setCust_level("3");
        session.update(c);
        tr.commit();
        session.close();
    }
    /**
     *添加或者修改
     */
    @Test
    public void testSaveOrUpdate(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        //Customer c=new Customer();
        //注意:这里的id值不能自己设置,否则会报错,因为他是由框架管理
        //c.setCust_id(4L);
        //注意:查询的id必须存在,否则会报空指针异常
        Customer c=session.get(Customer.class,3L);
        c.setCust_name("小菜");
        session.saveOrUpdate(c);
        tr.commit();
        session.close();
    }
    /**
     * 测试一个查询的方法
     */
    @Test
    public void testSel(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        //创建一个查询的接口
        Query query=session.createQuery("from Customer");
        //查询所有的数据select * from 表名
        List<Customer> list=query.list();
        for(Customer c:list){
            System.out.println(c);
        }
        tr.commit();
        session.close();
        
    }
    /**
     * 测试Hibernate框架正规写法
     */
    @Test
    public void testSave3(){
        Session session=null;
        Transaction tr=null;
        try{
            session=HibernateUtils.getSession();
            tr=session.beginTransaction();
            Customer c=new Customer();
            c.setCust_name("小强");
            session.save(c);
            tr.commit();
        }catch(Exception e){
            tr.rollback();
            e.printStackTrace();
        }finally{
            session.close();
        }
    }
}

四、Hibernate的缓存   

     1.Hibernate框架提供了两种缓存

         * 一级缓存  -- 自带的不可卸载的.一级缓存的生命周期与session一致.一级缓存称为session级别的缓存.

              * 二级缓存  -- 默认没有开启,需要手动配置才可以使用的.二级缓存可以在多个session中共享数据,二级缓存称为是sessionFactory级别的缓存.

       2.Session对象的缓存概述

          * Session接口中,有一系列的java的集合,这些java集合构成了Session级别的缓存(一级缓存).将对象存入到一级缓存中,session没有结束生命周期,那么对象在session中存放                   着

       * 内存中包含Session实例 --> Session的缓存(一些集合) --> 集合中包含的是缓存对象!

    3.测试一级缓存存在

/**
     * 证明一级缓存存在
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getSession();
        Transaction tr=session.beginTransaction();
        User user=new User();
        user.setName("小明");
        user.setAge(20);
        //保存用户
        Serializable id=session.save(user);
        System.out.println(id);
        //获取对象,不会看到Sql语句
        User user2=session.get(User.class,id);
        System.out.println(user2.getName());
        
        tr.commit();
        session.close();
    }

  

五、Hibernate之事务

     1.什么是事务

      事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.

    2. 事务的特性

        * 原子性   -- 事务不可分割.

        * 一致性   -- 事务执行的前后数据的完整性保持一致.

        * 隔离性   -- 一个事务执行的过程中,不应该受到其他的事务的干扰.

        * 持久性   -- 事务一旦提交,数据就永久保持到数据库中.

    3.关于解决数据丢失更新问题

       数据当涉及到并发访问时,第一想到的是添加锁机制,java中Thread 有添加synchronized关键字,数据库中也有添加锁的机制

     1)悲观锁

      即在数据库语句中添加"for update"字句。A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的,只有当A事务提交后,锁释放了,其他                        事务才能操作该条记录

     2)乐观锁

      在表结构中添加version字段(属性),默认值为0。A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时                        会更新版本号version=1;B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误。

     3)锁使用方法

       悲观锁:   

session.get(Customer.class, 1,LockMode.UPGRADE);

      乐观锁:

      1)) 持久化类

public class User {
    private Integer id;
    private String name;
    private Integer age;
    //在javabean中添加属性(乐观锁)
    private Integer version;
    
        //省略set/get toString()方法
    
}
    

       2)) 持久化类映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="com.itheima.domain.User" table="t_user">
            <id name="id" column="id">
            <!-- increment:获取主键的最大值,进行+1,作为主键
                          缺点:不适合并发访问
            -->
                <generator class="increment"></generator>
            </id>
            <!-- 乐观锁 ,就添加乐观锁的机制-->
            <version name="version"/>
            <property name="name" column="name" length="30"/>
            <property name="age" column="age"/>
        </class>
    </hibernate-mapping>

      3)) 此时可以写两个测试查询的方法,进行debug调试

      关于version,当左边更改数据时,发现自己的版本(0)与数据库的版本(1)不一致,说明自己不是最新的版本,会放弃此次操作 

六、hibernate的几种查询方式(简述)   

/**
 * 测试查询
 * @author Administrator
 *
 */
public class Demo4 {
    /**
     * 测试Query的查询接口
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询方式
        Query query=session.createQuery("from User");
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    /**
     * 添加查询条件
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询方式HQL(是Hibernate的独有的,操作的是对象)
        Query query=session.createQuery("from User where age>?");
        //写法二:Query query=session.createQuery("from User where age> :aa");
        //设置值:注意:这里区别于JDBC(下标为1)
        query.setInteger(0,15);
        //query.setInteger("aa",15);
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询方式HQL(是Hibernate的独有的,操作的是对象)
        Query query=session.createQuery("from User where name like ?");
        query.setString(0,"%k%");
        List<User> list=query.list();
        for(User user:list){
            System.out.println(user);
        }
        tr.commit();
        session.close();
    }
    /**
     * Criteria接口:条件查询,非常适合
     * 完全面对对象,没有太多sql语句
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先获取到Criteria接口
        Criteria criteria=session.createCriteria(User.class);
        //没有条件,查询所有的数据
        List<User> list=criteria.list();
        System.out.println(list);
        tr.commit();
        session.close();
    }
    /**
     * 按条件查询
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先获取到Criteria接口
        Criteria criteria=session.createCriteria(User.class);
        //添加查询条件
        //Criterion是Hibnernate提供的条件查询的对象,向传入条件使用的工具类
        //Restrictions提供的静态方法,拼接查询条件
        criteria.add(Restrictions.gt("age",18));//gt为大于
        //继续添加条件
        criteria.add(Restrictions.like("name","%s%"));
        //没有条件,查询所有的数据a
        List<User> list=criteria.list();
        System.out.println(list);
        tr.commit();
        session.close();
    }
    
}    

七、hibernate之级联处理数据

     需求:假设一个客户对应多个联系人,每个客户信息的处理都会牵扯到相对应的联系人;相反,每一个联系人的处理也会牵扯到相对应的客户

    1.创建持久化类

     1)在客户中添加set集合关联联系人

// 一个客户对应多个联系人:放的是联系人的集合.(Hibernate默认使用的集合是Set集合.集合必须要自己手动初始化)
    private Set<LinkMan> linkMans = new HashSet<LinkMan>();

     2)在联系人中添加客户属性用于关联客户

 // 联系人关联的客户对象://这里不要写客户的外键,要编写一个对象,而这个对象千万不能自己new,框架会帮你new
    private Customer customer;// ORM框架 Object 

    2.创建相对应的映射文件

     1)在客户映射文件中配置关联联系人的标签set

<!-- 配置关联对象 -->
        <!-- 
            set标签:
                * name属性:多的一方的集合的属性名称.
         -->
        <set name="linkMans">
            <!-- 
                key标签 :
                    * column属性:多的一方的外键的名称.
            -->
            <key column="lkm_cust_id"></key>
            <!-- 
                one-to-many标签:
                    * class属性:多的一方的类全路径
             -->
             <one-to-many class="com.clj.domain.LinkMan"/>
        </set>

     2) 在联系人映射文件中添加<many-to-one>标签关联客户

<!-- 配置关联对象: -->
        <!-- 
            many-to-one:标签.代表多对一.
                * name        :一的一方的对象的名称.
                * class        :一的一方的类的全路径.
                * column    :表中的外键的名称.
         -->
        <many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id"/>

   3.编写测试类

@Test
    // 向客户 和 联系人中同时保存数据:
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 创建一个客户
        Customer customer = new Customer();
        customer.setCust_name("张总");
        
        // 创建两个联系人:
        LinkMan linkMan1 = new LinkMan();
        linkMan1.setLkm_name("秦助理");
        
        LinkMan linkMan2 = new LinkMan();
        linkMan2.setLkm_name("胡助理");
        
        // 建立关系:
        customer.getLinkMans().add(linkMan1);
        customer.getLinkMans().add(linkMan2);
        
        linkMan1.setCustomer(customer);
        linkMan2.setCustomer(customer);
        
        session.save(customer);
        session.save(linkMan1);
        session.save(linkMan2);
        
        tx.commit();
    }

八、级联保存

    1.保存一个客户的同时保存相对应的联系人

     1)在客户映射文件中的<set>标签中添加cascade=save-update属性

<set name="linkmans" cascade="save-update">
            <!-- 需要出现子标签 -->
            <key column="lkm_cust_id"/>
            <one-to-many class="com.clj.domain.Linkman"/>
        </set>

     2)添加测试类

级联是有方向性:
* 保存客户的时候级联保存联系人.
    @Test
    /**
     * 测试级联保存:
     * * 保存客户 同时 级联保存联系人.
      * 在set集合上配置cascade=”save-update”
     */
    public void demo3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 保存客户:
        Customer customer = new Customer();
        customer.setCust_name("陈总");
        // 保存联系人:
        LinkMan man1 = new LinkMan();
        man1.setLkm_name("小花");

        // 建立关系:
        customer.getLinkMans().add(man1);
        man1.setCustomer(customer);
        
        // 执行保存操作:
        session.save(customer); // TransientObjectException:customer变为持久态对象,man 还是瞬时态对象.
        // session.save(man1);
        
        tx.commit();
    }

    2.保存联系人的同时保存相对应的客户

     1)在联系人映射文件的<one-to-many>标签中添加cascade=save-update属性

<many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id" cascade=”save-update”/>

     2) 编写相对应的测试类

    @Test
    /**
     * 测试级联保存:
     * * 保存联系人 级联 保存客户.
      * 在many-to-one上配置cascade=”save-update”
     */
    public void demo4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        // 保存客户:
        Customer customer = new Customer();
        customer.setCust_name("肖总");
        // 保存联系人:
        LinkMan man1 = new LinkMan();
        man1.setLkm_name("小娇");

        // 建立关系:
        customer.getLinkMans().add(man1);
        man1.setCustomer(customer);
        
        // 执行保存操作:
        // session.save(customer); // TransientObjectException:customer变为持久态对象,man 还是瞬时态对象.
        session.save(man1);
        
        tx.commit();
    }

九、级联删除

     需求:删除客户的时候同时删除客户的联系人

     1)在客户映射文件下的<set>标签中配置cascade=delete属性

        2 )  编写相对应的测试类 

@Test
    /**
     * 测试级联删除
     * 删除客户的时候 删除联系人:
     * 需要在Customer.hbm.xml中set标签上配置cascade="delete"
     */
    public void demo6(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        Customer customer = session.get(Customer.class, 1l);
        session.delete(customer);
        
        // 不能级联删除的.
        /*Customer customer = new Customer();
        customer.setCust_id(1l);
        
        session.delete(customer);*/
        tx.commit();
    }

    需求:删除联系人的时候同时删除客户

     1)在联系人映射文件下的<one-to-many>标签中配置cascade=delete属性

        2)编写测试类

@Test
    /**
     * 测试级联删除
     * 删除联系人 同时删除 客户:
     * 需要在LinkMan.hbm.xml中many-to-one标签上配置cascade="delete"
     */
    public void demo7(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        LinkMan linkman = session.get(LinkMan.class, 1l);
        
        session.delete(linkman);
        
        tx.commit();
    }

    补充:

    级联操作时,时常会因为双向关联会产生许多冗余的数据,因为快照机制,在数据处理时进行数据的比对。

    此时得用到inverse="true"属性   

@Test
    /**
     * 更改联系人所属的客户
     * * 双向关联 会产生多余的SQL:
     */
    public void demo8(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        
        LinkMan linkman = session.get(LinkMan.class, 5l);
        
        Customer customer = session.get(Customer.class, 4l);
        // 双向关联:
        linkman.setCustomer(customer);
        customer.getLinkMans().add(linkman);
        
        tx.commit();
    }

   此时,在客户映射文件中添加inverse="trues"属性,就可避免数据冗余(一的一方放弃主键维护)

<set name="linkmans" cascade="save-update" inverse="true">
            <!-- 需要出现子标签 -->
            <key column="lkm_cust_id"/>
            <one-to-many class="com.clj.domain.Linkman"/>
        </set>

十、Hibernate框架查询方式

     1.OID检索方式(通过唯一主键进行查询)

      语法:session.get(对象名.class,主键Id);

/**
     * OId的方式查询与对象导航的方式(两者特点:只能查询到一条数据)
     * 查询客户
     */
    @Test
    public void run1(){
        //先查询1号客户
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询1:通过OId的方式查询客户(通过主键查询)
        //先是有OID的方式查询客户
        Customer c=session.get(Customer.class,1L);
        System.out.println("===================");
        //查看该客户联系人的集合
        //查询2:对象导航的方式
        System.out.println(c.getLinkmans().size());
        tr.commit();
    }

     2.对象导航方式

       语法:new User().getRole().getRname()

/**
     * OId的方式查询与对象导航的方式
     * 查询联系人,属于某个客户
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Linkman man=session.get(Linkman.class,5L);
        System.out.println("====================");
        System.out.println(man.getCustomer().getCust_name());
        tr.commit();
    }

     3.HQL的查询方式

     1) HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似

      2)HQL 查询语句是面向对象的,Hibernate负责解析HQL查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句.

/**
 * HQL的检索方式
 * @author Administrator
 *
 */
public class Demo2 {
    /**
     * 基本演示
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建查询接口
        Query query=session.createQuery("from Customer");
        //调用list()方法,查询
        List<Customer> list=query.list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 支持方法链的编程风格
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建HQL的查询接口
        List<Customer> list=session.createQuery("from Customer").list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 使用别名的方式
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建HQL的查询接口
        //注意:这里不能用select * from Customer框架中没有这个语法
        List<Customer> list=session.createQuery("select c from Customer c").list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
    }
    /**
     * 排序查询
     * SQL:order by 字段 asc/desc;
     * HQL:关键字是一样的,都是有order by 属性
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询联系人
        //注意:这里是order by+属性(不是字段)
        List<Linkman> list=session.createQuery("from Linkman w order by w.km_id desc").list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * HQL分页查询的两个方法
     * setFirstResult(a)  --从哪条记录开始,如果查询是从第一条开始,值是0
     * setMaxResults(b)      --没页查询的记录条数
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("from Linkman");
        //分页查询,调用方法,查询第一页的数据1-3条
        /*query.setFirstResult(0);
        query.setMaxResults(3);*/
        //查询第二页的数据
        query.setFirstResult(3);//计算公式:(当前页-1)*pageSize=3
        query.setMaxResults(3);
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 按条件进行查询
     */
    @Test
    public void run6(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Query query=session.createQuery("from Linkman l where l.lkm_gender=?");
        Query query=session.createQuery("from Linkman l where l.lkm_id>? and l.lkm_gender=?");
        //传入
        //query.setString(0,"男");
        //通用符setParameter(Interger,object)无须考虑问号的参数类型
        query.setParameter(0,3L);
        query.setParameter(1,"女");
        
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 按条件进行查询
     * 占位符的方式
     */
    @Test
    public void run7(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("from Linkman l where l.lkm_gender=:gender");
        //传入
        query.setString("gender","女");
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 指定字段查询
     */
    @Test
    public void run8(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("select lkm_name,lkm_gender from Linkman");
        List<Object[]> list=query.list();
        for(Object[] objects:list){
            System.out.println(Arrays.toString(objects));
        }
        tr.commit();
    }
    /**
     * 投影查询:只查询几个字段,不是所有的字段
     * 第一步:需要在JavaBean类提供对应的构造方法(指定的有参和无参)
     * 第二步:HQL语句发生变化
     */
    @Test
    public void run9(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        Query query=session.createQuery("select new Linkman(lkm_name,lkm_gender) from Linkman");
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 聚合函数:count() avg() max() min()
     */
    @Test
    public void run10(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询所有的联系人的数量
        //Number是所有数值类型的父类
        List<Number> list=session.createQuery("select count(w) from Linkman w").list();
        //通过下标值进行取值
        Long count=list.get(0).longValue();//转为long类型
        System.out.println("数量为:"+count);
        
        tr.commit();
    }
    /**
     * 聚合函数:求数量
     * sum(属性必须为数值类型)
     */
    @Test
    public void run11(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //查询所有的联系人的数量
        //Number是所有数值类型的父类
        List<Number> list=session.createQuery("select sum(lkm_id) from Linkman").list();
        //通过下标值进行取值
        Long count=list.get(0).longValue();//转为long类型
        System.out.println("数量为:"+count);
        
        tr.commit();
    }
    
}

      4.QBC检索方式

        1)QBC:Query By Criteria  按条件进行查询

       2)条件查询的方法:

 *    * Restrictions.eq           -- 相等
        * Restrictions.gt           -- 大于号
        * Restrictions.ge           -- 大于等于
        * Restrictions.lt           -- 小于
        * Restrictions.le           -- 小于等于
        * Restrictions.between      -- 在之间
        * Restrictions.like         -- 模糊查询
        * Restrictions.in           -- 范围
        * Restrictions.and          -- 并且
        * Restrictions.or           -- 或者

       3)测试代码 

/**
 * QBC的查询(条件查询)
 * @author Administrator
 *
 */
public class Demo3 {
    /**
     * QBC的基本入门查询
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Customer.class);
        List<Customer> list=criteria.list();
        for(Customer customer:list){
            System.out.println(customer);
        }
        tr.commit();
        
    }
    /**
     * QBC的基本查询
     * 排序查询,调用的方法
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //调用排序的方法,addOrder(),这里演示降序排序
        criteria.addOrder(Order.desc("lkm_id"));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * QBC分页的方法和HQL分页的方法一样的
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //调用排序的方法,addOrder(),这里演示降序排序
        criteria.addOrder(Order.desc("lkm_id"));
        //设置分页的方法
        criteria.setFirstResult(0);
        criteria.setMaxResults(3);
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * QBC的条件查询
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //使用方法添加条件
        criteria.add(Restrictions.eq("lkm_gender","男"));
        //ge大于等于
        criteria.add(Restrictions.ge("lkm_id",3L));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
        
    }
    /**
     * in查询
     */
    @Test
    public void run5(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        List<Long> params=new ArrayList<Long>();
        params.add(1L);
        params.add(2L);
        params.add(3L);
        //使用in,方法查询(当然,这里不一定弄过集合,可以整个数组也行)
        criteria.add(Restrictions.in("lkm_id",params));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * or查询
     */
    @Test
    public void run6(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        criteria.add(Restrictions.or(Restrictions.eq("lkm_gender", "女"),Restrictions.gt("lkm_id",3L)));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 判断值是否为空
     */
    @Test
    public void run7(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //找所有的lkm_email是空的值
        //注意:isEmpty是判断集合是否为空
        criteria.add(Restrictions.isNull("lkm_email"));
        List<Linkman> list=criteria.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 聚合函数的查询
     */
    @Test
    public void run8(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //设置聚合函数的查询方式
        List<Number> list=criteria.setProjection(Projections.count("lkm_id")).list();
        Long count=list.get(0).longValue();
        System.out.println("数量为:"+count);
        tr.commit();
    }
    /**
     * 强调问题:select count(*) from 表,又想查select * from 表,存在问题
     */
    @Test
    public void run9(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建QBC查询接口
        Criteria criteria=session.createCriteria(Linkman.class);
        //设置聚合函数的查询方式
        criteria.setProjection(Projections.count("lkm_id"));
        List<Number> list=criteria.list();
        Long count=list.get(0).longValue();
        System.out.println("数量为:"+count);
        //再设置一遍setprojection方法
        criteria.setProjection(null);
        List<Linkman> mans=criteria.list();
        for(Linkman linkman:mans){
            System.out.println(linkman);
        }
        tr.commit();
    }
    /**
     * 演示离线条件对象
     * 创建条件查询时不需要session
     * 只有真正涉及到查询数据,调用数据库时才需要用到session
     */
    @Test
    public void run10(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建离线条件查询的对象
        DetachedCriteria criteria=DetachedCriteria.forClass(Linkman.class);
        //去添加查询条件了
        criteria.add(Restrictions.eq("lkm_gender","女"));
        //查询
        List<Linkman> list=criteria.getExecutableCriteria(session).list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
}

    5.SQL查询方式

public class Demo4 {
    /**
     * 测试SQL语句的查询
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建的是SQL的查询的接口
        SQLQuery query=session.createSQLQuery("select * from cst_linkman");
        //查询数据(注意:这里泛型是Object,不是对象,因为这里返回的数据时表的数据,不是对象)
        List<Object[]> list=query.list();
        for(Object[] object:list){
            System.out.println(Arrays.toString(object));
        }
        tr.commit();
    }
    /**
     * 把数据封装到对象中
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //创建的是SQL的查询的接口
        SQLQuery query=session.createSQLQuery("select * from cst_linkman");
        //通过方法设置
        query.addEntity(Linkman.class);
        List<Linkman> list=query.list();
        for(Linkman linkman:list){
            System.out.println(linkman);
        }
        tr.commit();
    }
}

    6.HQL多表查询

/**
 * HQL的多表查询
 * @author Administrator
 *
 */
public class Demo5 {
    /**
     * 查询的客户,客户和联系人有关联
     * select * from cst_customer c,cst_linkman l when c.id=l.id;
     */
     @Test
     public void run1(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //内连接的查询
         //这里的linkmans关联的是Customer类中集合属性名
         Query query=session.createQuery("from Customer c inner join c.linkmans");
         //这里默认放回值是数组
         List<Object[]> list=query.list(); 
         for(Object[] obj:list){
             System.out.println(Arrays.toString(obj));
         }
         tr.commit();
     }
     /**
      * 数据默认返回的数组,把数据封装到对象中
      * 提供关键字:fetch 迫切连接
      * 缺点:数据有冗余,有重复数据
      */
     @Test
     public void run2(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //内连接的查询
         //这里的linkmans关联的是Customer类中集合属性名
         Query query=session.createQuery("from Customer c inner join fetch c.linkmans");
         //这里默认放回值是数组
         List<Customer> list=query.list(); 
         for(Customer customer:list){
             System.out.println(customer);
         }
         tr.commit();
     }
    /**
     * 解决数据的重复的问题
     */
     @Test
     public void run3(){
         Session session=HibernateUtils.getCurrentSession();
         Transaction tr=session.beginTransaction();
         //内连接的查询
         Query query=session.createQuery("from Customer c inner join fetch c.linkmans");
         List<Customer> list=query.list(); 
         //手动解决,编程中都是用这种方式解决重复的问题
         Set<Customer> set=new HashSet<Customer>(list);
         for(Customer customer:set){
             System.out.println(customer);
         }
         tr.commit();
     }
}

十一、Hibernate之延迟加载

     1.什么是延迟加载?

       延迟加载先获取到代理对象,当真正使用到该对象中的属性的时候,才会发送SQL语句,是Hibernate框架提升性能的方式

    2.Session对象的load方法默认就是延迟加载

    3.hibernate框架默认形式就是延迟加载,如果想取消此功能,需添加lazy="false"属性

/**
 * 演示的延迟加载,提升程序的性能
 * 即当真正需要数据时才进入数据库查询
 * @author Administrator
 *
 */
public class Demo6 {
    /**
     * 类级别的延迟加载
     * 需要使用session.load()默认情况使用的延迟加载
     * 只有当查询对象的属性时才调用数据库进行数据的查询
     * 默认情况下配置文件中的延迟加载默认值为true(即lazy="true")
     */
    @Test
    public void run1(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Customer c1=session.get(Customer.class,1L);//原始在此时就调用数据库
        Customer c1=session.load(Customer.class,1L);
        System.out.println("=====================");
        System.out.println(c1.getCust_name());//此时才调用数据库查询数据
        tr.commit();
    }
    /**
     * 在调用load方法情况下怎么取消延迟加载
     * 1.在配置文件中设置lazy="false"
     * 2.重新初始化对象
     */
    @Test
    public void run2(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //Customer c1=session.get(Customer.class,1L);//原始在此时就调用数据库
        Customer c1=session.load(Customer.class,1L);
        //把c1对象初始化
        Hibernate.initialize(c1);
        System.out.println("=====================");
        System.out.println(c1.getCust_name());//此时才调用数据库查询数据
        tr.commit();
    }
    /**
     * 关联级别的延迟加载
     * 说的是客户下的联系人的集合
     */
    @Test
    public void run3(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        //先查询1号客户
        Customer c1=session.get(Customer.class,1L);//默认情况下是延迟加载,此时只查询客户,不会查询联系人
        System.out.println("=================");
        //看客户下所有的联系人
        System.out.println("联系人"+c1.getLinkmans().size());
        tr.commit();
    }
    /**
     * fetch属性能解决的问题
     */
    @Test
    public void run4(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction tr=session.beginTransaction();
        List<Customer> list=session.createQuery("from Customer").list();
        int count=0;
        for(Customer customer:list){
            count++;
            System.out.println("客户"+count+"的联系人数量为"+customer.getLinkmans().size());
        }
        tr.commit();
    }
}

    

 

原文地址:https://www.cnblogs.com/cailijia52o/p/8661295.html