• 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();
        }
    }

        

     

  • 相关阅读:
    最大最小值得判断代码
    等腰三角形的代码及各类代码
    Java ArrayList和Vector、LinkedList与ArrayList、数组(Array)和列表集合(ArrayList)的区别
    Java 集合类的特性
    Java 用程序给出随便大小的10 个数,序号为1-10,按从小到大顺序输出,并输出相应的序号?
    List、Map、Set三个接口,存取元素时,各有什么特点?
    Java 清除数组相同元素
    eclipse导入项目出现叹号处理方法:
    初学者-PHP笔记
    java 对象输入输出流
  • 原文地址:https://www.cnblogs.com/cailijia52o/p/8661295.html
Copyright © 2020-2023  润新知