Hibernate学习笔记(黑马)--第二天

目录

 

第四章:Hibernate持久化类和对象标识符

4.1 Hibernate持久化类

4.1.1 什么是持久化类

4.1.2 持久化类编写规范

4.2 Hibernate对象标识符(OID)

4.3 Hibernate主键生成策略

第五章:Hibernate一级缓存和对象状态

5.1 Hibernate一级缓存

5.1.1 Session缓存

5.1.2 快照机制

5.2 Hibernate对象的三种状态

第六章:Hibernate事务控制

6.1 配置Session和线程绑定

第七章:Hibernate查询对象的API

7.1 Query

7.2 常用查询(Query)

7.2.1 基本查询

7.2.2 条件查询

7.2.3 分页查询

7.2.4 排序查询

7.2.5 统计查询

7.2.6 投影查询

7.3 Criteria

7.4 常用查询(Criteria)

7.4.1 基本查询

7.4.2 条件查询

7.4.3 分页查询

7.4.4 排序查询

7.4.5 统计查询,投影查询

7.4.6 离线查询

附录:QBC(Query By Criteria)常用查询条件说明


第四章:Hibernate持久化类和对象标识符

4.1 Hibernate持久化类

4.1.1 什么是持久化类

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

4.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的编写规范以外,持久化类的编写还具备以下规范:

  1. 持久化类的属性尽量使用包装类的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更加清晰。例如考试零分和缺考可以用0和null表示,但是基础类型只有0。

  2. 持久化类需要有一个和数据库表主键对应的对象标识符(OID)。

  3. 持久化类尽量不要用final进行修饰。因为hibernate中有延迟加载机制,这个机制中会产生代理对象,该行为是采用字节码增强技术完成,其实就是产生了当前类的一个子类对象实现的。如果使用final修饰持久化类,该持久化类就不能创建子类,延迟加载机制(一种优化手段)就失效了。

4.2 Hibernate对象标识符(OID)

OID(Object Identifier),又叫做对象标识符。

虚拟机区分两个对象是根据内存地址是否一致。数据库区分两个对象是根据表的主键。Hibernate靠OID,实体类的OID映射数据库表中的主键。

4.3 Hibernate主键生成策略

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

两个概念:

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

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

第五章:Hibernate一级缓存和对象状态

5.1 Hibernate一级缓存

5.1.1 Session缓存

Hibernate的一级缓存是指Session缓存。Session缓存是内存中的一块区域,用来存放一些快速访问的java对象的。当使用Hibernate进行对象查询时,程序首先根据OID在Session中寻找对应java对象 ,有则返回,没有就向数据库中寻找。找到后会将查找到的java对象存入Session缓存,以便下次读取。Session缓存的目的就是减少对数据库的访问。

Session缓存由一系列java集合构成。只要Session实例没有结束生命周期,缓存中的对象也不会结束生命周期。当调用close()方法时,Session缓存也会被清空。

5.1.2 快照机制

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

5.2 Hibernate对象的三种状态

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

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

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

2、持久态(persistent)

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

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

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

第六章:Hibernate事务控制

6.1 配置Session和线程绑定

除了在代码中对事务进行开启、提交、回滚之外,还可以在hibernate.cfg.xml文件中的<Session-Factory/>标签中对事务进行配置。

设置事务隔离级别:

<!—
 事务隔离级别 
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层,业务逻辑如下图所示:

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-Factory>标签中,通过<property>标签进行Session管理方式配置。

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

2.获得Session的方式。

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

第七章:Hibernate查询对象的API

7.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 ?;

7.2 常用查询(Query)

Query查询的基本步骤为:

  1. 获得Hibernate的Session对象;

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

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

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

7.2.1 基本查询

/**查询所有*/
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);
    }
}

7.2.2 条件查询

/**条件查询
 *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);
    }
}

7.2.3 分页查询

/**
 *分页查询
 *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);
    }
}

7.2.4 排序查询

/**
 *排序查询
 *使用关键字: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);
    }
}

7.2.5 统计查询

/**
 *统计查询(利用聚合函数)
 *    聚合函数: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);
}

7.2.6 投影查询

/**
 *投影查询:
 *    投影:将实体类的部分信息映射成完整的实体类对象,叫做对象的投影
 *    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;
	}

    .......

7.3 Criteria

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

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

  1. 通过Hibernate获得Session对象

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

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

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

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

7.4 常用查询(Criteria)

7.4.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);
    }
}

7.4.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);
    }
}

7.4.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);
    }
}

7.4.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);
    }
}

7.4.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);
}

7.4.6 离线查询

三层架构中,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;
}				

附录:QBC(Query By Criteria)常用查询条件说明

短语

含义

Restrictions.eq

等于=

Restrictions.allEq

使用Map,使用key/value进行多个等于的判断

Restrictions.gt

大于>

Restrictions.ge

大于等于>=

Restrictions.lt

小于<

Restrictions.le

小于等于<=

Restrictions.between

对应sql的between子句

Restrictions.like

对应sql的like子句

Restrictions.in

对应sql的in子句

Restrictions.and

and 关系

Restrictions.or

or关系

Restrictions.sqlRestriction

Sql限定查询

Restrictions.asc()

根据传入的字段进行升序排序

Restrictions.desc()

根据传入的字段进行降序排序

运算类型

HQL运算符

QBC运算方法

比较运算

=

Restrictions.eq()

<>

Restrictions.not(Restrictions.eq())

>=

Restrictions.ge()

<

Restrictions.lt()

<=

Restrictions.le()

is null

Restrictions.isNull()

is not null

Restrictions.isNotNull()

范围运算符

in

Restrictions.in()

not in

Restrictions.not(Restrictions.in())

between

Restrictions.between()

not between

Restrictions.not(Restrictions.between())

 

运算类型

HQL运算符

QBC运算方法

字符串模式匹配

like

Restrictions.like()

逻辑

and

Restrictions.and()|

Restrictions.conjunction()

or

Restrictions.or()|

Restrictions.disjunction()

not

Restrictions.not()

  

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值