zoukankan      html  css  js  c++  java
  • Hibernate第二天——实体类 与缓存机制

    第二天,我们先来了解一下框架里的一个重要概念:实体类

      实体类:把数据表或其它持久化数据的格式映射成的类,就是实体类。

      实体类的编写规则:由于对应的是javabean,因而也遵循javabean的一些规范
        定义私有的成员变量
        通过set/get方法对成员变量进行读写操作
        实体类独有的特性:有属性值作为唯一值(一般为id)
        建议不要使用基本数据类型而是使用它们的包装类,理由是例如要区分0分与没有参加考试,int类型难以区分,
        而包装类Integer可以使用0与Null进行区分

        讲到实体类,我们再对第一天中的配置文件主键生成策略稍作细入  

          实体类的主键生成策略(请使用程序生成主键而非人为输入!):
          主要我们知道两个:
          <id name="uid" column="uid">
          <!-- 设置id增长策略 -->
           <generator class="native"></generator>
          </id>
          一个是我们第一天使用的native
          native :自动选择identity等,自动根据底层
          uuid :32为十六进制字符串,自动利用UUID的算法生成32位的唯一

           increment:(存在线程安全问题),可以为 int long ,甚至是 string
          使用UUID生成策略时,id类型必须为String类型,配置生成策略:
          <generator class="uuid"></generator>

          这里推荐一篇不错的主键生成策略讲解:http://www.cnblogs.com/hoobey/p/5508992.html

          更新简明版:http://blog.csdn.net/caiwenfeng_for_23/article/details/43644573/

          这里提取出一句小结:

          Hibernate中唯一一种最简单通用的主键生成器就是uuid。虽然是个32位难读的长字符串,但是它没有跨数据库的问题,

          将来切换数据库极其简单方便,推荐使用!

          接下来,我们来实际操作一下CRUD操作:

    对实体类的操作:(CRUD操作)
      添加操作:day01已做

        数据库添加操作会返回id值Serilizable id
      查询操作:根据id进行查询
       调用get()方法查询(结果一条记录(即一个对象))

    @Test
        public void testGet(){
            //都是先查后该
            //得到工厂
                    SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                    //得到session
                    Session session = sessionFactory.openSession();
                    //开启事务
                    Transaction tx = session.beginTransaction();
                    
                    //进行操作,第一个参数为.class对象,第二个为主键值
                    User user = session.get(User.class, 1);
                    System.out.println(user);
                    
                    //提交事务
                    tx.commit();
                    //关闭资源
                    session.close();
                    sessionFactory.close();
        }

      修改记录:修改都是先查再改
      调用update()方法进行修改

    @Test
        public void testUpdate(){
            //得到工厂
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            //得到session
            Session session = sessionFactory.openSession();
            //开启事务
            Transaction tx = session.beginTransaction();
            
            //进行操作
            User user = session.get(User.class, 2);
            user.setUsername("LuLu");
            session.update(user);
            System.out.println(user);
            
            //提交事务
            tx.commit();
            //关闭资源
            session.close();
            sessionFactory.close();
        }

      删除记录:调用delete()方法
      可以先根据id查询到该条记录,再传入对象进行删除

    @Test
        public void testDelete(){
                //都是先查后该
                 //得到工厂
                    SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                    //得到session
                    Session session = sessionFactory.openSession();
                    //开启事务
                    Transaction tx = session.beginTransaction();
                    
                    //进行操作
                    User user = session.get(User.class, 2);
                    session.delete(user);
                    
                    //提交事务
                    tx.commit();
                    //关闭资源
                    session.close();
                    sessionFactory.close();
        }

      做完了基本的CRUD操作,我们试着再引入实体类状态的概念:


    实体类的状态(作了解)

    1.瞬时态(Transient):对象里面没有id值,和session也没有关联,例如添加之前的状态,故瞬时态一般
    用来保存,即这个对象只是一个保存临时数据的内存区域,与数据库没有任何关系

      例如:

       User u=new User();

            u.setName("z");

    2.持久态(Persistent:对象里面有id值,和session有关联,例如通过id查询出来的值(session查出来的又有id)

              持久态对象的实例在数据库中有对应的记录,并拥有一个持久化标识(ID)

      例如:

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

    3.脱管态(游离态)(Detached,也就是离线的意思了):对象有id值,但是和sessio没有关联(用的少),

              实体对象从持久态变成游离态,对象虽然拥有持久和与数据库对应记录一致的标识值,

              但是因为对象已经从会话中清除掉,对象不在持久化管理之内,所以处于游离态(也叫脱管态)。

              游离态的对象与临时状态对象是十分相似的,只是它还含有持久化标识。

      例如:

      User u=new User();

      u.setId(1);

    这里就引出一个方法:

    saveOrUpdate()方法:根据不同的状态来执行不同的操作。
        1状态时执行 插入操作 insert
        2状态时执行 修改操作 update
        3状态时执行 修改操作 update

      到这里,有必要引入稍微标准一点的事务写法了,之后后面的例子都将使用尽量标准的写法

    /**
         * 事务的标准写法(无本地线程的绑定)
         * 单元测试时可以使用,不然session一直不关闭的状态
         */
        public void Demo01(){
            //请将声明放在try之外
                    SessionFactory sessionFactory = null;
                    Session session = null;
                    Transaction tx = null;
                    try{
                        //得到工厂
                        sessionFactory = HibernateUtils.getSessionFactory();
                        //得到session
                        session = sessionFactory.openSession();
                        //开启事务
                        tx = session.beginTransaction();
                        
                        //开始CRUD等操作
                        User user = new User();
                        user.setUsername("小李");
                        user.setPassword("10000");
                        user.setAddress("上海");
                        //调用session方法,也可以使用saveOrUpdate()
                        session.save(user);
                        
                        //提交事务
                        tx.commit();
                        
                    }catch(Exception e){
                        e.printStackTrace();
                        //事务回滚
                        tx.rollback();
                    }finally{
                        //关闭资源
                        session.close();//使用openSession()需要手动关闭
                        sessionFactory.close();
                    }
        }

      处理多线程的场景时,我们可以使用与本地线程绑定的 session

        /**
         * 使用与本地线程绑定的session的区别
         */
        public void Demo02(){
            //请将声明放在try之外
            //SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            try{
                //得到工厂
                //sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = HibernateUtils.getSessionObject();
                //开启事务
                tx = session.beginTransaction();
                
                //开始CRUD等操作
                User user = new User();
                user.setUsername("小李");
                user.setPassword("10000");
                user.setAddress("上海");
                //调用session方法,也可以使用saveOrUpdate()
                session.save(user);
                
                //提交事务
                tx.commit();
                
            }catch(Exception e){
                e.printStackTrace();
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                //与本地线程绑定的session不需要手动关闭
                //session.close();
                //sessionFactory.close();
            }
        }

     于是,我们引出与本地线程绑定的HibernateUtils的更新

    package cn.utils;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateUtils {
    
        private static final Configuration cfg ;
        private static final SessionFactory sessionFactory;
        //静态代码块实现
        static {
            cfg = new Configuration();
            cfg.configure();
            sessionFactory = cfg.buildSessionFactory();
        }
        //提供静态方法返回sessionFactory
        public static SessionFactory getSessionFactory(){
            return sessionFactory;
        }
        //返回本地线程绑定的session
        public static Session getSessionObject(){
            return sessionFactory.getCurrentSession();
        }
    }

    接下来我们来引入持久化框架的一个重要优化机制:缓存机制

    我们先来看看网络上对缓存的概述:

      Hibernate是一个持久层框架,经常访问物理数据库。

      为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。

      缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据

      也就是说,把数据存到内存中,叫缓存。

    Hibernate中存在两种缓存:

      一级缓存:
        三个特点:
          默认是打开的
          使用的范围是session的范围,也就是session的开启到关闭之间 =====故也被称为 session 的缓存
          存储的数据必须是持久态的数据
      二级缓存:已经不使用了,而是使用替代技术:redis
          默认不是打开的
          使用范围是整个的项目的范围(sessionFactory的范围,也就是类似servletContext) =====故也被称为 sesssionFactory 的缓存

    接下来先来验证一级缓存的存在再来概述一级缓存的执行过程:

        验证出一级缓存的存在:
          1.第一次查id=1,返回一个对象
          2.再次查id=1,就不去查数据库,而是查以及缓存

      

    /**
         * 验证一级缓存的存在
         *
         */
        @Test
        public void testCache(){
        
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            
            //使用工厂创建session
            Session session = sessionFactory.openSession();
            
            //开启事务
            Transaction tx = session.beginTransaction();
            
            //完成CRUD操作,验证一级缓存的,看看查询了几次
            User user1 = session.get(User.class, 1);
            System.out.println(user1);
            User user2 = session.get(User.class, 1);
            System.out.println(user2);
            
            //提交事务
            tx.commit();
            
            //关闭资源
            session.close();
            sessionFactory.close();
        }

    可以看到,两次相同的查询,只发送了一次SQL语句去查询.

      接下来大致执行过程

      一级缓存的大致执行过程:
        接到查询代码,先去查一级缓存,发现里面没有数据,
        再去查数据库,返回一个持久态的对象user1,再把持久态的user1放到一级缓存中
        第二次发现一级缓存里面有,就直接拿了。

      一级缓存里面存的不是整个对象,而是存对象里面的一些值(比如 id = 1,username = "张三")
          第二次查到的user2其实和user1不是同一个对象,而是把一级缓存的一些值拿过来组成user2

      一级缓存特性:持久态会更新数据库
        例子:
        User user = session.get(User.class, 2);
        user.setUsername("LuLu");
        //session.update(user);
        其中user为持久态的数据,所以update()方法可以省略
        持久态的数据会自动更新

      特点:创建session时,会创建一级缓存,同时还会出现一个
      快照区(也就是副本)

      执行user.setUsername("LuLu");时,修改一级缓存中的值
      但不会修改快照区的值
      提交事务的时候,Hibernate会比较一级缓存的内容和快照区的内容相同
      不相同则更新一级缓存内容到数据库,相同则不用更新到数据库

    在正式引入查询之前,先引入几个查询的API,进行简单的查询,具体的操作会在第四天作详细的介绍

      Hibernate API
        查询的对象:
          Query 对象
            不需要写SQL语句,但需要些HQL(Hibernate查询语言)
            HQL与SQL很相似;
            不同点:
              SQL操作的是数据库的表和字段
              HQL操作的是实体类和属性

            查询所有:
              from 实体类类名

    /**
         * 使用Query对象
         */
        @Test
        public void Demo01(){
            //请将声明放在try之外
                    SessionFactory sessionFactory = null;
                    Session session = null;
                    Transaction tx = null;
                    try{
                        //得到工厂
                        sessionFactory = HibernateUtils.getSessionFactory();
                        //得到session
                        session = sessionFactory.openSession();
                        //开启事务
                        tx = session.beginTransaction();
                        
                        //得到Query对象
                        Query query = session.createQuery("from User");
                        //得到结果集
                        List<User> list = query.list();
                        //遍历结果集
                        for (User user : list) {
                            System.out.println(user);
                        }
                        //提交事务
                        tx.commit();
                        
                    }catch(Exception e){
                        e.printStackTrace();
                        //事务回滚
                        tx.rollback();
                    }finally{
                        //关闭资源
                        session.close();//使用openSession()需要手动关闭
                        sessionFactory.close();
                    }
        }


         Criteria 对象
          步骤差不多,详见代码

      

    /**
         * 使用Criteria对象
         */
        @Test
        public void Demo02(){
            //请将声明放在try之外
                    SessionFactory sessionFactory = null;
                    Session session = null;
                    Transaction tx = null;
                    try{
                        //得到工厂
                        sessionFactory = HibernateUtils.getSessionFactory();
                        //得到session
                        session = sessionFactory.openSession();
                        //开启事务
                        tx = session.beginTransaction();
                        
                        //得到Criteria对象
                        Criteria criteria = session.createCriteria(User.class);
                        //调用方法,得到list结果集
                        List<User> list = criteria.list();
                        for (User user : list) {
                            System.out.println(user);
                        }
                        
                        //提交事务
                        tx.commit();
                        
                    }catch(Exception e){
                        e.printStackTrace();
                        //事务回滚
                        tx.rollback();
                    }finally{
                        //关闭资源
                        session.close();//使用openSession()需要手动关闭
                        sessionFactory.close();
                    }
        }


         SQLQuery 对象(使用较少)
            可以调用底层SQL(用的不多)
            步骤都是创建对象
            调用方法

    /**
         * 使用SQLQuery对象
         */
        @Test
        public void Demo03(){
            //请将声明放在try之外
                    SessionFactory sessionFactory = null;
                    Session session = null;
                    Transaction tx = null;
                    try{
                        //得到工厂
                        sessionFactory = HibernateUtils.getSessionFactory();
                        //得到session
                        session = sessionFactory.openSession();
                        //开启事务
                        tx = session.beginTransaction();
                        
                        //得到SQLQuery对象
                        SQLQuery sqlQuery = session.createSQLQuery("select * from t_user2");
                        //List<Object[]> list = sqlQuery.list();
                        //list中每部分是个数组
                        /*for (Object[] objects : list) {
                            System.out.println(Arrays.toString(objects));
                        }*/
                        //设置数据放到实体类
                        sqlQuery.addEntity(User.class);
                        //这样list中每部分都是User
                        List<User> list = sqlQuery.list();
                        //提交事务
                        tx.commit();
                        
                    }catch(Exception e){
                        e.printStackTrace();
                        //事务回滚
                        tx.rollback();
                    }finally{
                        //关闭资源
                        session.close();//使用openSession()需要手动关闭
                        sessionFactory.close();
                    }
        }

    以上都是查询所有的简单Demo,基本的过程都差不多,得到相关的对象后进行相应的操作

    可能是版本迭代问题,出现较多过时的地方,待解决!

     

     

     

     

      detachedcriteria离线的criteria

      其中离线的criteria待更新!

  • 相关阅读:
    base64和Blob的相互转换
    限制文件上传的大小和尺寸
    git将本地项目提交到github
    vue-cli3创建项目时报错
    运行项目是node-sass报错的解决方法
    classList的使用
    将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
    移动端的图片放大
    js获取url中的参数
    HTML5-canvas
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6735866.html
Copyright © 2011-2022 走看看