hibernate笔记(二)

1. Hibernate持久化类和对象标识符

1.1 Hibernate持久化类

1.1.1 什么是持久化类

Hibernate是持久层的ORM映射框架,专注于数据持久化工作。持久化即将内存中的数据永久存储到数据库中。持久化类就是与数据库建立映射关系的JAVA类。

1.1.2 持久化类编写规范

持久化类编写规范符合JavaBean编写规范。

JavaBean:Bean指可重用组件(一个类,一个业务层,Dao层等都可以称为组件)。JavaBean就是指java语言的可利用组件。

JavaBean编写规范:

1)类是public修饰的

2)类具有无参构造

3)类的属性是private修饰的

4)类的属性具有public修饰的getter、sertter方法

5)实现Serializable接口

JavaBean本质上还是个java类,当不含有构造器的时候,系统默认无参构造;当存在有参构造时,需要创建无参构造方法,否则系统创建无参对象时报错。在Hibernate中,底层需要使用反射机制生成类的实例,所以持久化类需要无参构造。成员变量是private修饰保证数据安全,getter、setter方法保证属性读取,且getter、setter方法可以添加操作(如权限控制)。对于Hibernate,底层会将查询到的数据进行封装,所以需要getter,setter方法。实现可序列化接口目的是将对象转换成一组byte,这样日后要用这个对象的时候,可以反序列化将这些数据恢复出来,并可以重新构建这个对象,可以跨网络传输,自动补偿操作系统的差异.这只是一个接口标记,没有任何方法实现.Bean的状态信息在设计时配置,并且保存下来,供程序启动时使用,序列化就是这个功能。

除了javabean的编写规范以外,持久化类的编写还具备以下规范:

  • 持久化类的属性尽量使用包装类的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更加清晰。例如考试零分和缺考可以用0和null表示,但是基础类型只有0。
  • 持久化类需要有一个和数据库表主键对应的对象标识符(OID)。
  • 持久化类尽量不要用final进行修饰。因为hibernate中有延迟加载机制,这个机制中会产生代理对象,该行为是采用字节码增强技术完成,其实就是产生了当前类的一个子类对象实现的。如果使用final修饰持久化类,该持久化类就不能创建子类,延迟加载机制(一种优化手段)就失效了。

1.2 Hibernate对象标识符(OID)

OID(Object Identifier),又叫做对象标识符。
虚拟机区分两个对象是根据内存地址是否一致。数据库区分两个对象是根据表的主键。Hibernate靠OID,实体类的OID映射数据库表中的主键。
在这里插入图片描述

1.3 Hibernate主键生成策略

持久化类中需要唯一的OID映射数据库表中的主键字段,而主键一般不让客户手动输入,而由程序自动生成。那么程序生成主键的方式有哪些呢?

两个概念:

自然主键:具有业务含义的字段作为主键,称为自然主键。如:把用户名字作为主键。

代理主键:不具有业务含义的字段作为主键,称为代理主键。如:id。

在这里插入图片描述

2. Hibernate一级缓存和对象状态

2.1 Hibernate一级缓存

2.1.1 Session缓存

Hibernate的一级缓存是指Session缓存。Session缓存是内存中的一块区域,用来存放一些快速访问的java对象的。当使用Hibernate进行对象查询时,程序首先根据OID在Session中寻找对应java对象 ,有则返回,没有就向数据库中寻找。找到后会将查找到的java对象存入Session缓存,以便下次读取。Session缓存的目的就是减少对数据库的访问。
Session缓存由一系列java集合构成。只要Session实例没有结束生命周期,缓存中的对象也不会结束生命周期。当调用close()方法时,Session缓存也会被清空。

2.1.2 快照机制

当Session缓存中存入数据时,该数据也会被拷贝到Hibernate快照中。当使用commit()进行提交事务时,同时会清理Session缓存,这时会使用OID判断缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存中的内容同步到数据库中,并更新快照;如果一致,则不执行update()。Hibernate快照作用是保持一级缓存中的数据和数据库一致。
在这里插入图片描述

2.2 Hibernate对象的三种状态

Hibernate将持久化类分为三种状态。

1、瞬时态(transient)=临时态=自由态。

该状态的持久化对象没有OID标识,也没有和Session建立关联,在数据库中没有记录。

2、持久态(persistent)

该状态的持久化对象存在OID标识,且加入了Session缓存中,且Session对象没有关闭,在数据库中有相应记录。

3、脱离态(detached)=离线态=游离态

该状态的持久化对象存在OID标识,与Session失去关联,在数据库中存在记录。

3. hibernate事务管理

3.1 配置session和线程绑定

除了在代码中对事务进行开启、提交、回滚之外,还可以在hibernate.cfg.xml文件中的标签中对事务进行配置。
设置事务隔离级别:

<!—
 事务隔离级别 
hibernate.connection.isolation = 4 
1—Read uncommitted isolation
2—Read committed isolation
4—Repeatable read isolation
8—Serializable isolation
-->
<property name="hibernate.connection.isolation">4</property>

Service层需要使用Session获得事务对象,DAO层需要Session对数据库进行增删改查操作。如何保证Service层和Dao层的Session对象保持一致呢?方法有二:

1.Session对象向下传递。(Service层获得Session并通过传参的方式将Session传送给DAO层)

2.将Session绑定到当前线程,DAO层通过当前线程获取Session。(多用该方式)

Hibernate5自身提供三种方式管理Session对象:
1)Session对象的生命周期和当前线程绑定。
2)Session对象的生命周期和JTA事务绑定。
3)Hibernate委托程序管理Session对象的生命周期。

1.在hibernate.cfg.xml文件中的标签中,通过标签进行Session管理方式配置。

<!--将Session绑定到当前线程中-->
<property name="hibernate.current_session_context_class">thread</property>

2.获得Session的方式。

/**
 *从当前线程获取Session
 */
public static Session getCurrentSession(){
    return sessionFactory.getCurrentSession();
}
//该方式获得的Session,当事务提交时,Session自动关闭

4.Hibernate查询对象的API

4.1 Query

Query对象代表Hibernate的一个查询操作。在Hibernate中,使用Session.createQuery()方法接收一个HQL(Hibernate Query Language)语句,然后调用Query对象的List()和uniqueResult()执行查询操作。

HQL是Hibernate面向对象查询语言,语法和SQL类似。HQL把数据库表的名称换成了类名称,字段名称换成了属性名称。例如:

SQL:select * from cst_customer where cust_name like ?;

HQL:select * from Customer where custName like ?;

其中,HQL的select * 可以省略。写为:  from Customer where custName like ?;

4.1.1 Query查询流程

Query查询的基本步骤为:

获得Hibernate的Session对象;

由Session.createQuery("HQL")创建Query对象,并输入查询语句;

如果HQL包含参数,则调用Query的setXXX方法设参;

调用List或uniqueRequest()方法得到查询结果。

4.1.2 基本查询

/**查询所有*/
public void test1(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("from Customer");
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}

4.1.3 条件查询


/**条件查询
 *Hibernate的参数占位符索引从0开始
 */
public void test2(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("from Customer where custName like ? and custLevel = ?");
    //设置query查询参数
    query.setString(0,"%集%");
    query.setString(1,"普通客户");
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}
 
 
//条件查询的另一种形式
public void test3(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("from Customer where custName like :custName and custLevel = :custLevel");
    //设置query查询参数
    query.setString("custName","%集%");
    query.setString("custLevel","普通客户");
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}

4.1.4 分页查询

/**
 *分页查询
 *SQL通过limit关键字进行分页查询,limit有两个参数:查询开始的起始索引,查询条数
 *Hibernate通过两个方法进行分页查询,参数类似
 *    setFistResult(int fist);设置其实查询位置
 *    setMaxResults(int max);设置每次查询的条数
 */
public void test4(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("from Customer");
    //设置query查询参数
    query.setFirstResult(2);
    query.setMaxResults(10);
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}

4.1.5 排序查询

/**
 *排序查询
 *使用关键字:order by
 *    升序:asc(默认值)
 *    降序:desc    
 */
public void test5(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("from Customer order by custId desc");
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}

4.1.6 统计查询

/**
 *统计查询(利用聚合函数)
 *    聚合函数:count sum avg max min 
 *    在SQL语句时:
 * 	    select count(*) from table		它是统计所有字段,效率没有只统计主键字段高
 * 		select count(主键) from table	它和第一个的结果是一样的,但是效率更高
 * 		select count(非主键) from table	只统计不为null的字段 
 *    
 */
public void test6(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("select count(custId) from Customer");
    //调用查询
    Long total = (Long)query.uniqueResult();
    //分析结果
    System.out.println(total);
}

4.1.7 投影查询

/**
 *投影查询:
 *    投影:将实体类的部分信息映射成完整的实体类对象,叫做对象的投影
 *    QBC也能实现投影查询,不如HQL好用
 *HQL的语法:
 *    select new Customer() from Customer
 *    注意:1.如果工程中该类(被投影类)唯一,可以不写全限定类名,否则要写全限定类名、
 *          (例如:Hibernate内部存在一个Order类,但是工程中也有一个Order订单类,对订单类不写全限定类名,hibernate会报错)
 *         2.要求该类(被投影类)必须存在一个相同参数类表的构造方法
 *           (原因:hibernate通过构造方法进行投影)
 */
public void test5(){
    //获得session
    Session s = HibernateUtil.openSession();
    //得到Query
    Query query = s.createQuery("select new cn.itcast.domain.Customer(custId,custName) from Customer");
    
    //调用查询
    List list = query.list();
    //分析结果
    for(Object o : list){
        System.out.println(o);
    }
}
 
 
 
/******************实体类*********************/
/**
 * 客户的实体类
*/
public class Customer implements Serializable {
 
	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custAddress;
	private String custPhone;
	
	public Customer(){
		
	}
	//提供对应参数列表的构造函数
 	public Customer(Long custId, String custName) {
		this.custId = custId;
		this.custName = custName;
	}
 
    .......

4.2 Criteria

Criteria是Hibernate核心查询对象。Criteria是完全面向对象的,可扩展的条件查询API。Criteria查询和Query查询不同,Criteria完全不必关心数据库底层实现和SQL,HQL语句。通过对Criteria对象的add(“Criterion条件对象”)方法进行条件设定,list()或uniqueResult()方法进行查询。

使用Criteria进行查询步骤如下:

通过Hibernate获得Session对象

通过Session.createCriteria()获得Criteria对象。

通过使用Restriction的静态方法创建Criterion条件对象。Restriction类提供一系列静态方法设定查询条件,这些方法都会返回Criterion条件对象。每一个Criterion实例都是一个查询条件对象。

Criteria对象通过add()方法进行添加Criterion对象。

执行list()或uniqueResult()获得查询结果。

4.2.1 基本查询

/**
 *查询所有
 *
 */
public void test1(){
    //获得Session对象
    Session s = HibernateUtil.openSession();
    //获得Criteria对象
    Criteria c = s.createCriteria(Customer.class);//相当于from Customer
    //通过Restriction对象的静态方法设置查询条件,返回Criterion对象
 
    //添加条件对象
 
    //完成查询
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
}

4.2.2 条件查询

/**
 *条件查询
 *
 */
public void test2(){
    //获得Session对象
    Session s = HibernateUtil.openSession();
    //获得Criteria对象
    Criteria c = s.createCriteria(Customer.class);//相当于from Customer
 
    //通过Restriction对象的静态方法设置查询条件,返回Criterion对象
    //添加条件对象
    c.add(Restriction.like("custName","集"));
    c.add(Restriction.eq("custLevel","普通客户"));
 
    //完成查询
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
}

4.2.3 分页查询

/**
 *分页查询(和HQL一模一样)
 *
 */
public void test3(){
    //获得Session对象
    Session s = HibernateUtil.openSession();
    //获得Criteria对象
    Criteria c = s.createCriteria(Customer.class);//相当于from Customer
 
    //设置查询条件
    c.setFirstResult(2);
    c.setMaxResults(2);
 
    //完成查询
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
}

4.2.4 排序查询

/**
 *排序查询
 *
 */
public void test4(){
    //获得Session对象
    Session s = HibernateUtil.openSession();
    //获得Criteria对象
    Criteria c = s.createCriteria(Customer.class);//相当于from Customer
 
    //设置排序
    c.addOrder(Order.desc("custId"));
 
    //完成查询
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
}

4.2.5 统计查询,投影查询

/**
  * QBC使用聚合函数
  * 		统计查询
  * 涉及的对象:
  * 	Criteria
  * 涉及的方法:
  * 	setProjection(Projection p);
  * 参数的含义
  * 	 Projection:要添加的查询投影
  */
 
public void test5(){
    //获得Session对象
    Session s = HibernateUtil.openSession();
    //获得Criteria对象
    Criteria c = s.createCriteria(Customer.class);//相当于from Customer
 
    //设置统计查询条件
    c.setProjection(Projections.count("custId"));
 
    //投影查询的例子如下
    /*
     *c.setProjection(Projections.projectionList()
     *  .add(Projections.property("custId"))
     *  .add(Projections.property("custName")));
     */
 
    //完成查询
    Long long = c.uniqueResult();
    System.out.println(long);
}

4.3 离线查询

三层架构中,Hibernate的Seesion应该出现在Dao层,在Web层和Service层都不应该出现。但当使用QBC查询时,我们需要在WEB或者Service层调用Session,创建Criteria对象,这就造成了矛盾。解决矛盾的方法有二:1、将参数向下传递(不可取,参数多的时候不好处理)。2、使用Criteria离线查询。

在WEB层和Service层可以使用DetachedCriteria对象来设置查询条件。该对象的获取不需要Session对象,可后期与Criteria对象进行转换,被称为离线对象。

获得该对象的方式:DetachedCriteria dCriteria = DetachedCriteria.forClass(“要查询的实体类字节码”);

public void test3(){
	//模拟一次web操作: 浏览器发送请求——调用servlet——调用service——调用dao——拿到结果到jsp上展示
	List list = servletFindAllCustomer();
	for(Object o : list){
		System.out.println(o);
	}
}
	
//模拟servlet
public List<Customer> servletFindAllCustomer(){
	//离线对象
	DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
	//设置条件:和Criteria是一样的
	dCriteria.add(Restrictions.like("custName","%集%"));
	return serviceFindAllCustomer(dCriteria);
}
 
public List<Customer> serviceFindAllCustomer(DetachedCriteria dCriteria) {
	 return daoFindAllCustomer(dCriteria);
}
 
public List<Customer> daoFindAllCustomer(DetachedCriteria dCriteria) {
	Session s = HibernateUtil.getCurrentSession();
	Transaction tx = s.beginTransaction();
	//把离线对象使用可用Session激活
	Criteria c = dCriteria.getExecutableCriteria(s);
	List<Customer> list = c.list();
	tx.commit();
	return list;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值