美文网首页
day35 hibernate深入

day35 hibernate深入

作者: 路人爱早茶 | 来源:发表于2017-11-10 18:50 被阅读0次
    • 有id对应的(在数据库)瞬时态对象是游离状态,没有id对应就算有id属性也是瞬时状态。
      ------------练习
    • request跳转不需要加项目名称(会自动加?)
    • response重定向需要加项目名称(不必须)因为内部跳转可能找不到,图片地址也如此
      ------------批量查询
    • hql多表简单查询,criteria单表查询,原生sql多表复杂查
    • 问号索引是从0开始的,而jdbc是从1开始
    @Test
        public void fun1(){
            //1 获得session
            Session session = HibernateUtils.openSession();
            //2 控制事务
            Transaction tx = session.beginTransaction();
            //3执行操作
            //-------------------------------------------
    --------------基本查询  将sql封装到query中   Customer 如果唯一可只写类名,如果不唯一需要全路径名称;sql语句中是类名和属性名称不可以出现表名和字段名
          //1> 书写HQL语句
            String hql = " from Customer where cust_id = 1 "; // 查询所有Customer对象
            //2> 根据HQL语句创建查询对象
            Query query = session.createQuery(hql);
            //3> 根据查询对象获得查询结果
            Customer c = (Customer) query.uniqueResult();       
            System.out.println(c);
    ------------------问号占位符从0开始.setLong选择对应属性也可以setParameter综合;
    还可以String hql = " from Customer where cust_id = :cust_id ";  :cust_id 以冒号为占位符后面名称随意和query.setParameter("cust_id", 1l);搭配
    //1> 书写HQL语句
            String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
            //2> 根据HQL语句创建查询对象
            Query query = session.createQuery(hql);
            //设置参数
            //query.setLong(0, 1l);
            query.setParameter(0, 1l);
            //3> 根据查询对象获得查询结果
            Customer c = (Customer) query.uniqueResult();
    ------------------分页查询没有limit而是setFirstResult和setMaxResults设置初始和最大
    String hql = " from Customer  "; // 查询所有Customer对象
            //2> 根据HQL语句创建查询对象
            Query query = session.createQuery(hql);
            //设置分页信息 limit ?,?
            query.setFirstResult(1);
            query.setMaxResults(1);
            //-------------------------------------------
            //4提交事务.关闭资源
            tx.commit();
            session.close();// 游离|托管 状态, 有id , 没有关联
    }
    -------------------------------------------Criteria查询,先创建Criteria 对象,之后以调用属性来完成sql的条件
    -----------------------基本
    //查询所有的Customer对象
            Criteria criteria = session.createCriteria(Customer.class);     
            List<Customer> list = criteria.list();      
            System.out.println(list);       
    //      Customer c = (Customer) criteria.uniqueResult();        
    -----------------------//条件查询
        //HQL语句中,不可能出现任何数据库相关的信息的
        // >                gt
        // >=               ge
        // <                lt
        // <=               le
        // ==               eq
        // !=               ne
        // in               in
        // between and      between
        // like             like
        // is not null      isNotNull
        // is null          isNull
        // or               or
        // and              and
    //创建criteria查询对象
            Criteria criteria = session.createCriteria(Customer.class);
            //添加查询参数 => 查询cust_id为1的Customer对象
            criteria.add(Restrictions.eq("cust_id", 1l));
            //执行查询获得结果
            Customer c = (Customer) criteria.uniqueResult();
            System.out.println(c);
    -----------------------分页查询 
    //创建criteria查询对象
            Criteria criteria = session.createCriteria(Customer.class);
            //设置分页信息 limit ?,?
            criteria.setFirstResult(1);
            criteria.setMaxResults(2);
            //执行查询
            List<Customer> list = criteria.list();      
            System.out.println(list);
    --------------------//查询总记录数
    //创建criteria查询对象
            Criteria criteria = session.createCriteria(Customer.class);
            //设置查询的聚合函数 => 总行数
            criteria.setProjection(Projections.rowCount());
            //执行查询
            Long count = (Long) criteria.uniqueResult();        
            System.out.println(count);
    ----------------------------------原生sql
    -------------------基本
                  String sql = "select * from cst_customer";        
            //2 创建sql查询对象
            SQLQuery query = session.createSQLQuery(sql);       
            //3 调用方法查询结果
            List<Object[]> list = query.list();
            //query.uniqueResult();     
            for(Object[] objs : list){
                System.out.println(Arrays.toString(objs));
            }
    或者
    //指定将结果集封装到哪个对象中
            query.addEntity(Customer.class);        
            //3 调用方法查询结果
            List<Customer> list = query.list();
    ------------------条件查询
        String sql = "select * from cst_customer where cust_id = ? ";       
            //2 创建sql查询对象
            SQLQuery query = session.createSQLQuery(sql);       
            query.setParameter(0, 1l);
            //指定将结果集封装到哪个对象中
            query.addEntity(Customer.class);        
            //3 调用方法查询结果
            List<Customer> list = query.list();
    ------------------问号占位符
    String sql = "select * from cst_customer  limit ?,? ";      
            //2 创建sql查询对象
            SQLQuery query = session.createSQLQuery(sql);       
            query.setParameter(0, 0);
            query.setParameter(1, 1);
            //指定将结果集封装到哪个对象中
            query.addEntity(Customer.class);        
            //3 调用方法查询结果
            List<Customer> list = query.list();
    

    ------------事务

    • 注意使用currentsession必须要在主配置恩建中自己配
    -----原则
    -业务开始之前打开事务,业务执行之后提交事务. 执行过程中出现异常.回滚事务.
    -在dao层操作数据库需要用到session对象.在service控制事务也是使用-session对象完成. 确保dao层和service层使用的使用同一个session对象
    -在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了. 我们只需要调用sf.getCurrentSession()方法即可获得与当前线程绑定的session对象
    - 注意1: 调用getCurrentSession方法必须配合主配置中的一段配置
    - 注意2:通过getCurrentSession方法获得的session对象.当事务提交时,session会自动关闭.不要手动调用close关闭.(否则报错)
    -------配置<!-- 指定session与当前线程绑定 -->
             <property name="hibernate.current_session_context_class">thread</property>
    ---------service
    public class customerServiceImpl implements CustomerService {
    
        private CustomerDao customerDao=new CustomerDaoImpl();
    
        @Override
        public void save(Customer customer) {
            Session sess = HibernateUtils.getCurrentSesson();
            Transaction tx = sess.beginTransaction();
            try {
                customerDao.save(customer);         
            } catch (Exception e) {
                e.printStackTrace();
                tx.rollback();
            }
            tx.commit();
            }
    -------------dao
    public void save(Customer customer) {
            // 获得session
            Session sess = HibernateUtils.getCurrentSesson();
            // 保存对象
            sess.save(customer);
        }
    
    • acid(原子性:最小单位要么全成功要么全失败;一致性:原子性衍生,总量不变;隔离性:提供隔离级别解决并发问题;持久性:保证提交后写在硬盘)
    • 并发问题
      脏读:读到未提交数据
      不可重复读:两次读取数据不一致
      幻|虚读
    <!-- 引入orm元数据
                路径书写: 填写src下的路径
             -->
             <!-- 指定hibernate操作数据库时的隔离级别 
                #hibernate.connection.isolation 1|2|4|8     
                0001    1   读未提交
                0010    2   读已提交
                0100    4   可重复读
                1000    8   串行化
             -->
             <property name="hibernate.connection.isolation">4</property>
    

    -------------一级缓存

    • 所以持久化对象就是放在缓存中的对象
    ----new 对象是瞬时,setid变成游离,update放入session缓存中变成持久化,但是session中没有快照,所以在commit会存入数据库调用一次sql
    @Test
        //持久化状态对象其实就是放入session缓存中的对象
        public void fun3(){
            //1 获得session
            Session session = HibernateUtils.openSession();
            //2 控制事务
            Transaction tx = session.beginTransaction();
            //3执行操作     
            Customer c1 = new Customer();
            c1.setCust_id(1l);//托管|游离       
            session.update(c1);//c1被放入session缓存了            
            Customer c2 = session.get(Customer.class, 1l);      
            //4提交事务.关闭资源
            tx.commit();
            session.close();// 游离|托管 状态, 有id , 没有关联     
        }
    
    • 提高效率手段:缓存的快照
    • 查询先看session缓存中有没有(以id为标志)有就直接返回,没有继续。查找好的对象在hibernate中会有两份,一份缓存,一分快照,修改对象属性提交事务之后会比对快照和缓存是否相同。


      1.png

    -------------生成策略(状态)

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

    -------------创建表注意

    -----线程安全问题
    <id name="cust_id"  >
                <!-- generator:主键生成策略.就是每条记录录入时,主键的生成规则.(7个)
                        identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键.
                        sequence: Oracle中的主键生成策略.
                        increment(了解): 主键自增.由hibernate来维护.每次插入前会先查询表中id最大值.+1作为新主键值.            
                        hilo(了解): 高低位算法.主键自增.由hibernate来维护.开发时不使用.
                        native:hilo+sequence+identity 自动三选一策略.
                        uuid: 产生随机字符串作为主键. 主键类型必须为string 类型.
                        assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.
                        
                 -->
                <generator class="increment"></generator>
            </id>
    

    -------------实体对象创建注意

    • hibernate创建实体走的是反射new instance,默认是空参方法
    • 属性仅仅指getset方法
    • 尽量使用基本类型的包装类型(long-Long)包装类型可以有null表达,但是基本类型没有null,如果数据库为空实体对象是基本类型,关联就会报错
    • 没有主键无法映射到hibernate

    相关文章

      网友评论

          本文标题:day35 hibernate深入

          本文链接:https://www.haomeiwen.com/subject/blxmmxtx.html