java框架复习——hibernate

目录

概述

Hibernate是一种基于Java的轻量级的ORM框架

hibernate特点

在这里插入图片描述
方便开发大大减少代码量,性能稍高,跨数据库平台

其中Mapping把Object类型的数据映射到关系型数据库中,这样就可以让我们只操作对象,不需要操作数据库。
在这里插入图片描述

hibernate作用

java程序通过JDBC+SQL来操作数据库

Hibernate的出现简化了开发者手工进行数据库连接与操作数据库的步骤,帮助开发者创建数据库连接并为用户生成对应的SQL语句,降低了手工进行Java操作数据过程中的风险,一定程度上缩短了用户使用JDBC+SQL进行操作数据库的开发时间,但是底层仍然是JDBC+SQL,所以速度方面略慢。

Hibernate是一种数据层解决方案
在这里插入图片描述

hibernate系统架构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • Transient Object(瞬时对象)
  • Persistent Object(持久对象)
  • session:hibernate的会话
  • SessionFactory:会话工厂,这是一个进程级别的对象,重量级的
  • Transaction:本地事务
  • TransactionFactory:事务工厂
  • ConnectionProvider:使用第三方的数据源,如:c3p0,dbcp
  • JNDI:java naming Directory interface,提供的就是资源的目录
  • JDBC:操作数据库的api
  • JTA:跨数据库的事务
    在这里插入图片描述

hibernate环境搭建

下载网址:http://hibernate.org/orm/downloads/
在这里插入图片描述
搭建环境步骤:

  1. 建立一个java项目
  2. 导包
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. 创建hibernate.cfg.xml

默认位置在classpath下,默认名称hibernate.cfg.xml

<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接设置 -->
        <property name="connection.driver_class">com.jdbc.mysql.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hiber01</property>
        <property name="connection.username">root</property>

        <property name="connection.password">root</property>

        <!-- 设置数据库连接池的初始化连接数 -->
        <property name="connection.pool_size">1</property>
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="show_sql">true</property>
        <mapping resource=""/>
    </session-factory>
</hibernate-configuration>

4.创建实体类(model)

public class User {
	
	private int userId;
	
	private String uname;
	
	private int gender;
	
	private Date birthday;

	public int getUserId() {
		return userId;
	}

	public void setUserId(int userId) {
		this.userId = userId;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

	public int getGender() {
		return gender;
	}

	public void setGender(int gender) {
		this.gender = gender;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
}

hibernate.cfg.xml剖析

  • 数据库连接配置
  • 可选配置
  • 资源注册
  • 二级缓存(后期)
  • 查询缓存(后期)

Hibernate.cfg.xml是默认的文件名称,可以随便起名xxx.xml,建议使用hibernate.cfg.xml

数据库连接配置

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hiber01</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>

可选配置

  • Hibernate默认使用的数据库的连接池,connection.pool_size是连接池的连接数量
<property name="connection.pool_size">1</property>
  • 数据库的方言

Hibernate可以支持多种数据库,不同数据库的sql会有差别,hibernate可以根据不同的数据库来生成不同的sql,每一种数据库hibernate为我们定义了一种方言

<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
  • 是否输出sql

是否在控制台输出sql语句

<property name="show_sql">true</property>
  • 第三方的数据库连接池的配置(c3p0)
<!-- 数据库连接最小连接数 -->
<property name="c3p0.min_size">10</property>
<!-- 数据库最大连接数 -->
<property name="c3p0.max_size">100</property>
<!-- 连接数据库超时时间 -->
<property name="c3p0.timeout">3000</property>
  • 建表策略
<property name="hbm2ddl.auto">none</property>

总共有四个值:

  1. None:不做任何事
  2. Create:每次执行hibernate的操作时都删表建表
  3. Create-drop:每次执行hibernate操作时都建表删表,SessionFactory关闭就删表
  4. Validate:每次执行hibernate操作就验证数据库的表和mapping的关系是否正确

我们默认选择none或者不配置就ok了

资源注册(注册映射文件)

注意包名用/分隔

<mapping resource="com/rl/hiber/model/User.hbm.xml"/>

模型类的规范

  1. 必须要有默认构造方法:查询时把数据表中的一条数据映射成一个对象时需要使用默认构造器来创建对象。
  2. 必须提供一个OID,作为对象的主键

Hibernate中使用OID区分对象是否相同,Hibernate认为每一个不同的对象应该具有一个唯一的标识,称这个标识为OID。

Java对象中可以使用任意属性作为OID。

自然主键:具有业务含义

例如个人信息中的身份证号,不仅是唯一的,而且还具有业务含义,这种属性虽然可以做为OID,但是其具有一定的业务含义。选择OID尽量避免使用具有业务含义的属性。

代理主键:不具有业务含义

声明一个不具有任何业务含义的属性,仅用于区分对象,这种属性即便暴漏给最终用户查看,也不具有安全隐患

OID选择应尽量避免使用自然主键,改用代理主键

  1. 属性的私有化封装,提供set和get方法
  2. 不要使用final来修饰模型类中成员,如果是final类型后续延迟加载无法实现
  3. 最好使用包装类

基本数据有一个默认值的特点,特性在对象数据封装时存在着数据隐患,一旦基本数据类型取值为默认值,开发者将无法区分该值是用户输入数据还是未输入数据由系统默认给出

封装类数据类型可以使用是否为null来判定该数据是来自于用户输入还是未输入。

映射文件配置

每一个model都有一个相对于的映射文件,命名规范:模型类.hbm.xml,位置可以任意但是建议放在model的同级包下。

Class元素映射

	<class name="User" table="t_user">

class:映射类

属性:

  • name:要映射的model的全路径
  • table:model映射到数据库的表名
    在这里插入图片描述

属性的映射

<property name="uname"></property>
<property name="gender"></property>
<property name="birthday"></property>

Property:属性的映射

属性:

  • Name:模型类的属性名
  • Column:映射都表中的列名
  • Type:hibernate提供的数据类型,可以由java的数据类型转换成数据库中的数据类型
  • Length:映射到数据库中的字段的长度
  • not-null:是否可以为空
  • unique-key:唯一约束的键名

主键映射

<!—id
	是主键映射配置
 -->
<id name="userId" column="user_id">
	<!-- 
		generator:主键的映射策略
	 -->
	<generator class="assigned"></generator>
</id>

映射策略如下:

  • Assigned:手动指定id,在实际项目中基本不用
  • Increment:通过获得当前的id的最大值的方式然后在最大值上加1来指定主键,在实际项目中不去使用因为有危险
Hibernate: select max(user_id) from t_user
Hibernate: insert into t_user (uname, gender, birthday, user_id) values (?, ?, ?, ?)

下图如果A先插入数据库中的主键最大值就是2,B这时来插入就出现了主键重复
Increment方式有并发问题,所以不用。
在这里插入图片描述

  • Identity:使用mysql的自增,前提是model类的oid是数值类型,映射column也是数值类型
create table t_user (
        user_id integer not null auto_increment,
        uname varchar(255),
        gender integer,
        birthday datetime,
        primary key (user_id)
    )

输出

Hibernate: insert into t_user (uname, gender, birthday) values (?, ?, ?)

这种自增没有并发问题,因为主键的自增策略由数据库管理(有锁机制)

  • Sequence:是Oracle数据库的自增策略
  • Native:是智能的自增策略,会根据数据库的方言来翻译identify/sequence
  • Uuid:通过hibernate生成一个32位的不重复的字符串,要求是oid是字符串类型,相应的数据库的id也是varchar,这种策略在实际项目中大量使用

在这里插入图片描述
建议使用uuid,性能高些

环境初始化

  • Configuration:创建hibernate配置对象,读取hibernate.cfg.xml文件初始化环境
  • ServiceRegistry:注册hibernate属性信息
  • SessionFactory:Session工程类,这个类是一个重量级的对象,线程安全的,负责创建Session,这个对象在服务器启动的时候创建一个即可。
  • Session:是一次和数据库的会话,但是不一定是一次连接,Session给我们提供很多操作数据库的方法,操作的是对象,影响的是数据库。
  • Transaction:事务对象,控制我们Session对象数据库操作的事务。
@Test
public void test() {
	//创建hibernate配置对象
	Configuration cfg = new Configuration();
	//配置hibernate的核心文件的位置
	cfg.configure("hibernate.cfg.xml");
	//注册配置属性信息
	ServiceRegistry sr = new StandardServiceRegistryBuilder()
						.applySettings(cfg.getProperties()).build();
	//创建SessionFactory
	SessionFactory factory = cfg.buildSessionFactory(sr);
	//创建Session
	Session session = factory.openSession();
	//开启事务
	Transaction tx = session.beginTransaction();
	//创建对象
	User user = new User();
	//user.setUserId(2);
	user.setUname("renliang");
	user.setGender(1);
	user.setBirthday(new Date());
	//通过Session保存对象
	session.save(user);
	//提交事务
	tx.commit();
	session.close();
	factory.close();
}

hibernate的对象的三种状态及其转换

三种对象概念

  • 瞬时对象(transientObjects):由我们自己创建出来,数据库中没有相应的记录,也没有被hibernate的Session管理起来,这样的对象可以被jvm回收的。
  • 持久化对象(persistentObjects):这个对象在数据库中有相应的记录,这个对象被Session管理起来。
  • 脱管对象(detachObjects):数据库中有相应的记录,但是没有被Session管理
    在这里插入图片描述
    三种对象的转换示意图如下:
    在这里插入图片描述

瞬时对象转换成持久对象

在这里插入图片描述
对持久对象的修改

@Test
	public void test2(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//创建对象,这时是瞬时对象
			User user = new User();
			user.setUname("任亮");
			user.setGender(1);
			user.setBirthday(new Date());
			//发出sql语句,把user对象纳入到Session的管理,并且保存到数据库,持久状态
			session.save(user);
			//设置持久对象的属性,Session会把修改后的持久
			//对象的属性值和没有修改时的做对比,如果有变化就发出update,没有就不发
			user.setUname("任亮");
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

持久对象和脱管对象的转换

@Test
	public void test4(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		User user = new User();
		try {
			user.setUname("任亮");
			user.setGender(1);
			user.setBirthday(new Date());
			session.save(user);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			//Session关闭,那么user由持久对象变成脱管对象
			HibernateUtils.closeSession(session);
		}
		
		Session session1 = HibernateUtils.getSession();
		Transaction tx1 = session1.beginTransaction();
		try {
			user.setUname("亮亮");
			//Session1接纳了user,立即把user变成持久对象
			session1.update(user);
			tx1.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx1.rollback();
		}finally{
			HibernateUtils.closeResource(session1);
		}
	}

通过get和load和iterator查询出来的对象是持久状态

@Test
	public void test5(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//通过get方法查询的对象既在Session管理中,在数据库中也有记录所以user是持久对象
			User user = (User) session.get(User.class, 5);
			System.out.println(user);
			user.setUname("liangliang");
			//发出update语句,证明是持久对象
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}
	
	@Test
	public void test6(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//通过get方法查询的对象既在Session管理中,在数据库中也有记录所以user是持久对象
			User user = (User) session.load(User.class, 5);
			System.out.println(user);
			user.setUname("任亮");
			//发出update语句,证明是持久对象
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}

持久和脱管对象转换瞬时对象

通过delete把数据库中的数据删除,而且清掉Session中的对象,那么这个对象就变成了瞬时对象

@Test
	public void test7(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//通过get方法查询的对象既在Session管理中,在数据库中也有记录所以user是持久对象
			User user = (User) session.get(User.class, 5);
			System.out.println(user);
			//session的删除会把数据库中的记录删掉,同时清掉Session的user对象
			session.delete(user);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}

Session的flush方法剖析

数据库的事务的隔离级别

隔离级别脏读不可重复读幻读
Read uncommittedYYY
Read commitedNYY
Repeatable readNNY
SerializableNNN

查询mysql的数据库事务的隔离级别
在这里插入图片描述

Session的flush

使用uuid主键生成策略来测试flush
@Test
	public void test1(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			User user = new User();
			user.setUname("任亮");
			user.setGender(1);
			user.setBirthday(new Date());
			//因为是uuid方式生成的主键,由Session给生成,把user对象存储在Session的临时存储区
			session.save(user);
			//发出sql语句,清理临时存储区,把dirty变成false
			session.flush();
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
使用native主键生成策略来测试flush
@Test
	public void test3(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			User user = new User();
			user.setUname("任亮");
			user.setGender(1);
			user.setBirthday(new Date());
			//因为是使用native方式生成主键,所以save的时候要发出sql来产生主键,持久区有数据,dirty是true
			session.save(user);
			//把dirty变成false
			session.flush();
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
逐出user
@Test
	public void test4(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			User user = new User();
			user.setUname("任亮");
			user.setGender(1);
			user.setBirthday(new Date());
			//因为是使用native方式生成主键,所以save的时候要发出sql来产生主键,持久区有数据,dirty是true
			session.save(user);
			//把user逐出Session
			session.evict(user);
			//Session中没有数据flush没有意义
			session.flush();
			//但是commit依然会把数据提交到数据库,因为sql已经发出了
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

Session的flush完成大量数据入库的功能

@Test
	public void test5(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			for(int i = 0; i < 100009; i++){
				User user = new User();
				user.setUname("任亮");
				user.setGender(1);
				user.setBirthday(new Date());
				session.save(user);
				if(i%100 == 0){
					session.flush();
				}
			}
			session.flush();
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

各种关系映射

多对一的关联映射

例如球队和队员的关系如下,注意这里是站在多的一端来操作的
在这里插入图片描述

创建模型

多的一端
在这里插入图片描述
一的一端
在这里插入图片描述

配置映射文件

多的一端

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Emp" table="t_emp">
 		<id name="empNo" column="emp_no">
 			<generator class="native"></generator>
 		</id>
 		<property name="ename"></property>
 		<property name="birthday"></property>
 		<property name="gender"></property>
 		<property name="address"></property>
 		<!-- 
 			指定多对一的关系
 			name:多的一端(emp)的类中的一的类(team)的属性名
 			column:建表后多的一端(t_emp)中的外键
 		 -->
 		<many-to-one name="team" column="t_id"></many-to-one>
 	</class>

一的一端

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Team" table="t_team">
 		<id name="tId" column="t_id">
 			<generator class="native"></generator>
 		</id>
 		<property name="tName" column="t_name"></property>
 		<property name="loc"></property>
 	</class>
 </hibernate-mapping>

Hibernate的映射文件创建后要注册到我们的hibernate.cfg.xml中,然后导出数据库即可

测试多对一
保存
@Test
	public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			//创建一支球队
			Team t = new Team();
			t.settName("公牛");
			t.setLoc("芝加哥");
			//保存球队
			session.save(t);
			
			//创建员工
			Emp emp = new Emp();
			emp.setEname("乔丹");
			emp.setGender(1);
			emp.setBirthday(new Date());
			emp.setAddress("芝加哥");
			
			Emp emp1 = new Emp();
			emp1.setEname("菲尔");
			emp1.setGender(1);
			emp1.setBirthday(new Date());
			emp1.setAddress("芝加哥");
			//设置员工和球队的关系
			emp.setTeam(t);
			emp1.setTeam(t);
			//保存员工
			session.save(emp);
			session.save(emp1);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

注意:在保存多的一端的时候一定要先保存一的一端,如果一的一端是瞬时对象就会报错
在这里插入图片描述
正确的输出

Hibernate: insert into t_team (t_name, loc) values (?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)

保存多对一的关系的时候也可以使用级联的方式

<!-- 
 			指定多对一的关系
 			name:多的一端(emp)的类中的一的类(team)的属性名
 			column:建表后多的一端(t_emp)中的外键
 			cascade:delete切记不要使用
 					save-update级联保存或更新
 					all包含了以上两种
 					none不使用级联(默认的)
 		 -->
 		<many-to-one name="team" column="t_id" cascade="save-update"></many-to-one>

使用级联的保存就不需要单独保存一的一端了

查询

使用get和load来查询

@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		
		try {
			//调用get方法来查询指定要查询的类和id
			Emp emp = (Emp) session.get(Emp.class, 5);
			System.out.println(emp);
			System.out.println(emp.getTeam());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
	
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			Emp emp = (Emp) session.load(Emp.class, 5);
			System.out.println(emp);
			System.out.println(emp.getTeam());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

一对一的关联映射

例如员工和身份证的关系如下,注意这里是站在其中一个一的一端来操作的
在这里插入图片描述

创建模型

这里主要是身份证的模型类,员工的之前也已经创建过了

一的一端
在这里插入图片描述

配置映射文件

这里主要是身份证的映射文件,员工的之前也已经创建过了

一的一端

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="IDCard" table="t_id_card">
 		<!-- 指定主键名称,建议使用emp端的主键名称 -->
 		<id name="cardId" column="emp_no">
 			<!-- 使用外键的方式来生成主键 -->
 			<generator class="foreign">
 				<!-- 指定idCard这一端的emp属性 -->
 				<param name="property">emp</param>
 			</generator>
 		</id>
 		<property name="cardNo" column="card_no"></property>
 		<!-- 
 			指定一对一的关系
 			name:当前端的的另一个一的一端的属性名称emp
 			constrained:建表时带有外键约束
 		 -->
 		<one-to-one name="emp" constrained="true"></one-to-one>
 	</class>
 </hibernate-mapping>

一对一单端测试
保存
public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//创建员工
			Emp emp = new Emp();
			emp.setEname("任亮");
			emp.setAddress("吉林");
			emp.setGender(1);
			emp.setBirthday(new Date());
			//创建身份证
			IDCard ic = new IDCard();
			ic.setCardNo("1234567890");
			//指定一对一的关系
			ic.setEmp(emp);
			//保存ic的时候自动的保存了emp,因为ic的主键是emp的主键,
			//如果emp不保存主键就不会返回,所以在ic保存之前必须先保存emp
			session.save(ic);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

查询
@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		try {
			IDCard card = (IDCard) session.get(IDCard.class, 1);
			System.out.println(card);
			System.out.println(card.getEmp());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select idcard0_.emp_no as emp_no1_1_0_, idcard0_.card_no as card_no2_1_0_ from t_id_card idcard0_ where idcard0_.emp_no=?
IDCard [cardId=1, cardNo=1234567890]
Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_ from t_emp emp0_ where emp0_.emp_no=?
Emp [empNo=1, ename=任亮, birthday=2015-09-15 22:29:17.0, gender=1, address=吉林]
一对一的双向关联映射

修改emp的模型,加入idcard这一端的属性
在这里插入图片描述
在emp.hbm.xml中的配置

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Emp" table="t_emp">
 		<id name="empNo" column="emp_no">
 			<generator class="native"></generator>
 		</id>
 		<property name="ename"></property>
 		<property name="birthday"></property>
 		<property name="gender"></property>
 		<property name="address"></property>
 		<!-- 
 			双向关联映射的一对一,从数据库模型的箭头指向方向来看
 			name:指定箭头背向端的model属性
 		 -->
 		<one-to-one name="card"></one-to-one>
 	</class>
 	
 </hibernate-mapping>
保存
@Test
	public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//创建员工
			Emp emp = new Emp();
			emp.setEname("任亮");
			emp.setAddress("吉林");
			emp.setGender(1);
			emp.setBirthday(new Date());
			//创建身份证
			IDCard ic = new IDCard();
			ic.setCardNo("1234567890");
			//设置员工和身份证的关系,由于是双向映射需要指定双向的关系
			emp.setCard(ic);
			ic.setEmp(emp);
			//先保存emp
			session.save(emp);
			//保存ic
			session.save(ic);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

使用级联方式
在这里插入图片描述

@Test
	public void testAdd1(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try {
			//创建员工
			Emp emp = new Emp();
			emp.setEname("任亮");
			emp.setAddress("吉林");
			emp.setGender(1);
			emp.setBirthday(new Date());
			//创建身份证
			IDCard ic = new IDCard();
			ic.setCardNo("1234567890");
			//设置员工和身份证的关系,由于是双向映射需要指定双向的关系
			emp.setCard(ic);
			ic.setEmp(emp);
			//先保存emp
			session.save(emp);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
查询
@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		try {
			Emp emp = (Emp) session.get(Emp.class, 3);
			System.out.println(emp);
			System.out.println(emp.getCard());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

从箭头指向的方向查询会使用连接查询

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, idcard1_.emp_no as emp_no1_1_1_, idcard1_.card_no as card_no2_1_1_ from t_emp emp0_ left outer join t_id_card idcard1_ on emp0_.emp_no=idcard1_.emp_no where emp0_.emp_no=?
Emp [empNo=3, ename=任亮, birthday=2015-09-15 22:51:19.0, gender=1, address=吉林]
IDCard [cardId=3, cardNo=1234567890]

一对多的关联映射

在这里插入图片描述

创建model对象

在这里插入图片描述

配置映射文件

在一的一端来配置

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Team" table="t_team">
 		<id name="tId" column="t_id">
 			<generator class="native"></generator>
 		</id>
 		<property name="tName" column="t_name"></property>
 		<property name="loc"></property>
 		<!-- 
 			set指定一对多的关系配置
 			name:在一的一端的模型类中集合的属性名
 		 -->
 		<set name="set">
 			<!-- 
 				key:在多的一端的表中要产生的外键
 				column:外键名称
 			 -->
 			<key column="t_id"></key>
 			<!-- 
 				one-to-many:指定多的一端的类
 				class:多的一端的类
 			 -->
 			<one-to-many class="Emp"/>
 		</set>
 	</class>
 </hibernate-mapping>
测试一对多
保存
@Test
	public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			//创建员工
			Emp emp = new Emp();
			emp.setEname("乔丹");
			emp.setAddress("芝加哥");
			emp.setBirthday(new Date());
			emp.setGender(1);
			//保存员工
			session.save(emp);
			Emp emp1 = new Emp();
			emp1.setEname("菲尔");
			emp1.setAddress("芝加哥");
			emp1.setBirthday(new Date());
			emp1.setGender(1);
			session.save(emp1);
			//创建球队
			Team team = new Team();
			team.settName("公牛队");
			team.setLoc("芝加哥");
			
			//把两个员工加入到集合中
			Set<Emp> set = new HashSet<Emp>();
			set.add(emp);
			set.add(emp1);
			//指定球队和员工一对多的关系
			team.setSet(set);
			//保存球队
			session.save(team);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: insert into t_emp (ename, birthday, gender, address) values (?, ?, ?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address) values (?, ?, ?, ?)
Hibernate: insert into t_team (t_name, loc) values (?, ?)
Hibernate: update t_emp set t_id=? where emp_no=?
Hibernate: update t_emp set t_id=? where emp_no=?

从输出上可以看出来在保存员工时先插入员工的基本字段,外键t_id是空的,再插入球队最后根据生成的球队的t_id来修改两个员工的球队外键t_id。

缺点是如果员工表中外键为非空插入员工时就会报错。

查询
@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		try{
			Team team = (Team) session.get(Team.class, 3);
			System.out.println(team);
			Set<Emp> set = team.getSet();
			for(Emp emp : set){
				System.out.println(emp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Team [tId=3, tName=小牛队, loc=达拉斯]
Hibernate: select set0_.t_id as t_id6_1_0_, set0_.emp_no as emp_no1_0_0_, set0_.emp_no as emp_no1_0_1_, set0_.ename as ename2_0_1_, set0_.birthday as birthday3_0_1_, set0_.gender as gender4_0_1_, set0_.address as address5_0_1_ from t_emp set0_ where set0_.t_id=?
Emp [empNo=4, ename=诺维斯基, birthday=2015-09-16 10:29:00.0, gender=1, address=达拉斯]
Emp [empNo=3, ename=库班, birthday=2015-09-16 10:29:00.0, gender=1, address=达拉斯]
一对多的双向关联

一对多是有缺陷的,保存的时候如果多的一端的外键是非空,一对多的保存就不成立

创建模型

在这里插入图片描述

修改配置

修改多的一端的配置

<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Emp" table="t_emp">
 		<id name="empNo" column="emp_no">
 			<generator class="native"></generator>
 		</id>
 		<property name="ename"></property>
 		<property name="birthday"></property>
 		<property name="gender"></property>
 		<property name="address"></property>
 		<!-- 
 			指定多对一的关系:
 			name:一的一端属性名
 			column:多的一端的表中要产生的外键字段,注意在team.hbm.xml中已经配置了这个外键,
 			现在要求我们配置的这个外键要和team.hbm.xml中配置的多的一端外键名称相同,
 			因为这两个配置指的是同一个列
 		 -->
 		<many-to-one name="team" column="t_id"></many-to-one>
 	</class>
保存

保存一对多的,要把操作给多的一端去操作

@Test
	public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			
			//创建球队
			Team team = new Team();
			team.settName("公牛队");
			team.setLoc("芝加哥");
			//保存球队
			session.save(team);
			
			//创建员工
			Emp emp = new Emp();
			emp.setEname("乔丹");
			emp.setAddress("芝加哥");
			emp.setBirthday(new Date());
			emp.setGender(1);
			//指定员工和球队的关系
			emp.setTeam(team);
			//保存员工
			session.save(emp);
			Emp emp1 = new Emp();
			emp1.setEname("菲尔");
			emp1.setAddress("芝加哥");
			emp1.setBirthday(new Date());
			emp1.setGender(1);
			
			emp1.setTeam(team);
			session.save(emp1);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: insert into t_team (t_name, loc) values (?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)

如果有需求必须要在一的一端来进行保存,我们设置控制反转,我们可以在一的一端操作,然后实际是在多的一端保存

配置:
在这里插入图片描述
保存:

@Test
	public void testAdd1(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			
			//创建球队
			Team team = new Team();
			team.settName("公牛队");
			team.setLoc("芝加哥");
			
			//创建员工
			Emp emp = new Emp();
			emp.setEname("乔丹");
			emp.setAddress("芝加哥");
			emp.setBirthday(new Date());
			emp.setGender(1);
			//指定员工和球队的关系
			emp.setTeam(team);
			
			
			Emp emp1 = new Emp();
			emp1.setEname("菲尔");
			emp1.setAddress("芝加哥");
			emp1.setBirthday(new Date());
			emp1.setGender(1);
			emp1.setTeam(team);
			
			Set<Emp> set = new HashSet<Emp>();
			set.add(emp1);
			set.add(emp);
			team.setSet(set);
			
			//保存球队
			session.save(team);
			
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: insert into t_team (t_name, loc) values (?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address, t_id) values (?, ?, ?, ?, ?)

多对多关联映射

员工和角色是多对多的关系,一个员工可以分配多个角色,一个角色可以分配给多个员工
在这里插入图片描述

创建model对象

在这里插入图片描述

单端配置多对多
<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Emp" table="t_emp">
 		<id name="empNo" column="emp_no">
 			<generator class="native"></generator>
 		</id>
 		<property name="ename"></property>
 		<property name="birthday"></property>
 		<property name="gender"></property>
 		<property name="address"></property>
 		<!-- 
 			set:设置多对多的单端集合
 			name:在emp中集合属性名称
 			table:要产生的中间表的名称
 		 -->
 		<set name="roles" table="emp_role">
 			<!-- 
 				把emp表的主键给中间表作为外键
 				column:当前emp表的主键名称
 			 -->
 			<key column="emp_no"></key>
 			<!-- 
 				指定emp对面端的
 				class:指定多的一端的类
 				column:指定多的一端的要给中间表的字段名称(role表的主键)
 			 -->
 			<many-to-many class="Role" column="role_id"></many-to-many>
 		</set>
 	</class>
 </hibernate-mapping>
测试单端多对多
保存
@Test
	public void testAdd(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			//创建员工
			Emp emp = new Emp();
			emp.setEname("任亮");
			emp.setGender(1);
			emp.setAddress("长春");
			emp.setBirthday(new Date());
			
			//创建角色
			Role role = new Role();
			role.setRoleName("老师");
			role.setRoleDesc("讲课");
			//保存角色
			session.save(role);
			
			Role role1 = new Role();
			role1.setRoleName("总监");
			role1.setRoleDesc("管理");
			//保存角色
			session.save(role1);
			//指定当前员工和角色的关系
			Set<Role> set = new HashSet<Role>();
			set.add(role);
			set.add(role1);
			emp.setRoles(set);
			//保存员工
			session.save(emp);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}	
	}

输出:

Hibernate: insert into t_role (role_name, role_desc) values (?, ?)
Hibernate: insert into t_role (role_name, role_desc) values (?, ?)
Hibernate: insert into t_emp (ename, birthday, gender, address) values (?, ?, ?, ?)
Hibernate: insert into emp_role (emp_no, role_id) values (?, ?)
Hibernate: insert into emp_role (emp_no, role_id) values (?, ?)
查询
@Test
	public void queryTest(){
		Session session = HibernateUtils.getSession();
		try{
			Emp emp = (Emp) session.get(Emp.class, 1);
			System.out.println(emp);
			for(Role role : emp.getRoles()){
				System.out.println(role);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}	
	}
多对多双向管理映射

在这里插入图片描述

修改模型

在这里插入图片描述

修改配置
<hibernate-mapping package="com.rl.hiber.model">
 	<class name="Role" table="t_role">
 		<id name="roleId" column="role_id">
 			<generator class="native"></generator>
 		</id>
 		<property name="roleName" column="role_name"></property>
 		<property name="roleDesc" column="role_desc"></property>
 		<set name="emps" table="emp_role" cascade="save-update">
 			<key column="role_id"></key>
 			<many-to-many class="Emp" column="emp_no"></many-to-many>
 		</set>
 	</class>
 </hibernate-mapping>

延迟加载

class上的延迟加载

我们通过get和load来查询,get默认不使用延迟加载,load使用延迟加载,延迟加载必须在同一个Session范围内。

Get方法
@Test
	public void testQueryWGet(){
		Session session = HibernateUtils.getSession();
		
		try {
			//get方法不使用延迟加载,发出sql的
			User user = (User) session.get(User.class, "297e045d4fd4ddbc014fd4ddbe100000");
			System.out.println(user.getUname());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
Load方法
@Test
	public void testQueryWLoad(){
		Session session = HibernateUtils.getSession();
		
		try {
			//load方法默认使用延迟加载,不发出sql的
			User user = (User) session.load(User.class, "297e045d4fd4ddbc014fd4ddbe100000");
			//使用到对象的成员时来发出sql
			System.out.println(user.getUname());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
延迟加载必须在同一个Session内
/**
	 * 类上的延迟加载要在同一个Session之内
	 */
	@Test
	public void testQueryWLoad1(){
		Session session = HibernateUtils.getSession();
		User user = null;
		try {
			//load方法默认使用延迟加载,不发出sql的
			user = (User) session.load(User.class, "297e045d4fd4ddbc014fd4ddbe100000");
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
		//Session关闭了就不会有延迟加载,不发sql
		System.out.println(user.getUname());
	}

在这里插入图片描述

集合的延迟加载

集合的延迟加载是在一对多和多对多,默认情况集合是有延迟加载的

@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		
		try {
			Team team = (Team) session.load(Team.class, 1);
			//发出查询team的sql
			System.out.println(team);
			Set<Emp> emps = team.getSet();
			//发出根据t_id查询员工的sql
			System.out.println(emps);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出

Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Team [tId=1, tName=公牛队, loc=芝加哥]
Hibernate: select set0_.t_id as t_id6_1_0_, set0_.emp_no as emp_no1_0_0_, set0_.emp_no as emp_no1_0_1_, set0_.ename as ename2_0_1_, set0_.birthday as birthday3_0_1_, set0_.gender as gender4_0_1_, set0_.address as address5_0_1_, set0_.t_id as t_id6_0_1_ from t_emp set0_ where set0_.t_id=?
[Emp [empNo=1, ename=乔丹, birthday=2015-09-16 15:01:36.0, gender=1, address=芝加哥], Emp [empNo=2, ename=菲尔, birthday=2015-09-16 15:01:36.0, gender=1, address=芝加哥]]

如果set上的lazy=false
在这里插入图片描述
输出:

Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Hibernate: select set0_.t_id as t_id6_1_0_, set0_.emp_no as emp_no1_0_0_, set0_.emp_no as emp_no1_0_1_, set0_.ename as ename2_0_1_, set0_.birthday as birthday3_0_1_, set0_.gender as gender4_0_1_, set0_.address as address5_0_1_, set0_.t_id as t_id6_0_1_ from t_emp set0_ where set0_.t_id=?
Team [tId=1, tName=公牛队, loc=芝加哥]
[Emp [empNo=2, ename=菲尔, birthday=2015-09-16 15:01:36.0, gender=1, address=芝加哥], Emp [empNo=1, ename=乔丹, birthday=2015-09-16 15:01:36.0, gender=1, address=芝加哥]]

当lazy=true的时候,如果查询集合的数量时,效率低下,我们需要把lazy=extra,效率比较高

/**
	 * lazy=extra
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		
		try {
			Team team = (Team) session.load(Team.class, 1);
			//发出查询team的sql
			System.out.println(team);
			Set<Emp> emps = team.getSet();
			//发出一条智能高效的sql
			System.out.println(emps.size());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Team [tId=1, tName=公牛队, loc=芝加哥]
Hibernate: select count(emp_no) from t_emp where t_id =?
2

注意:集合的延迟加载效果不受类上的延迟加载影响。

单端延迟加载

针对多对一和一对一的延迟加载,默认情况lazy=proxy使用延迟加载

/**
	 * 默认情况many-to-one=proxy
	 */
	@Test
	public void testQuery(){
		Session session = HibernateUtils.getSession();
		try {
			//不发sql
			Emp emp = (Emp) session.load(Emp.class, 1);
			//发出一条根据emp_no查询员工的sql
			System.out.println(emp);
			//不发
			Team team = emp.getTeam();
			//发出一条根据t_id查询球队的sql
			System.out.println(team);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, emp0_.t_id as t_id6_0_0_ from t_emp emp0_ where emp0_.emp_no=?
Emp [empNo=1, ename=乔丹, birthday=2015-09-16 16:05:14.0, gender=1, address=芝加哥]
Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Team [tId=1, tName=公牛队, loc=芝加哥]
Lazy=false
/**
	 * lazy=false
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		try {
			//不发sql
			Emp emp = (Emp) session.load(Emp.class, 1);
			//发出一条根据emp_no查询员工的sql,发出一条根据t_id查询球队的sql
			System.out.println(emp);
			//不发
			Team team = emp.getTeam();
			//不发
			System.out.println(team);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, emp0_.t_id as t_id6_0_0_ from t_emp emp0_ where emp0_.emp_no=?
Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Emp [empNo=1, ename=乔丹, birthday=2015-09-16 16:05:14.0, gender=1, address=芝加哥]
Team [tId=1, tName=公牛队, loc=芝加哥]

如果Team类的延迟加载被禁用,many-to-one lazy=proxy

/**
	 * 如果Team类的延迟加载被禁用,many-to-one lazy=proxy
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		try {
			//不发sql
			Emp emp = (Emp) session.load(Emp.class, 1);
			//发出一条根据emp_no查询员工和球队的连接查询的sql
			System.out.println(emp);
			//不发
			Team team = emp.getTeam();
			//不发
			System.out.println(team.gettName());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, emp0_.t_id as t_id6_0_0_, team1_.t_id as t_id1_1_1_, team1_.t_name as t_name2_1_1_, team1_.loc as loc3_1_1_ from t_emp emp0_ left outer join t_team team1_ on emp0_.t_id=team1_.t_id where emp0_.emp_no=?
Emp [empNo=1, ename=乔丹, birthday=2015-09-16 16:05:14.0, gender=1, address=芝加哥]
公牛队

hibernate查询

HQL查询

HQL(Hibernate Query Language),hibernate的专属语言,可以跨数据库,根据不同数据库方言翻译成不同sql,跟SQL很相似。

基本查询

查询所有的数据的写法

String hql = "from User";
String hql = "select u from User u";//hql中没有*的写法
@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			//查询所有的user类的对象
			String hql = "from User";
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//查询列表
			List<User> userList = query.list();
			for(User user: userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.user_id as user_id1_0_, user0_.uname as uname2_0_, user0_.gender as gender3_0_, user0_.birthday as birthday4_0_ from t_user user0_
User [userId=1, uname=任亮0, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=2, uname=任亮1, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=3, uname=任亮2, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=4, uname=任亮3, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=5, uname=任亮4, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=6, uname=任亮5, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=7, uname=任亮6, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=8, uname=任亮7, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=9, uname=任亮8, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=10, uname=任亮9, gender=2, birthday=2015-09-16 22:19:02.0]

对象的单个属性查询

/**
	 * 查询对象的属性
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		
		try {
			//查询所有的user类的对象
			//String hql = "from User";
			String hql = "select u.uname from User u";//hql中没有*的写法
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//查询列表
			List<String> nameList = query.list();
			for(String name: nameList){
				System.out.println(name);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.uname as col_0_0_ from t_user user0_
任亮0
任亮1
任亮2
任亮3
任亮4
任亮5
任亮6
任亮7
任亮8
任亮9

多个属性的查询

/**
	 * 查询对象的多个属性
	 */
	@Test
	public void testQuery3(){
		Session session = HibernateUtils.getSession();
		try {
			//查询所有的user类的对象
			//String hql = "from User";
			String hql = "select u.uname, u.gender from User u";//hql中没有*的写法
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//查询列表,多个属性的查询要使用Object[]来做接收
			List<Object[]> objArrList = query.list();
			for(Object[] objArr: objArrList){
				System.out.println("姓名:"+objArr[0]+"   性别:"+objArr[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.uname as col_0_0_, user0_.gender as col_1_0_ from t_user user0_
姓名:任亮0   性别:1
姓名:任亮1   性别:2
姓名:任亮2   性别:1
姓名:任亮3   性别:2
姓名:任亮4   性别:1
姓名:任亮5   性别:2
姓名:任亮6   性别:1
姓名:任亮7   性别:2
姓名:任亮8   性别:1
姓名:任亮9   性别:2
分页查询
setFirstResult(m)
etMaxResults(n)
m表示起始的索引
n表示每页的记录数
@Test
	public void testQuery5(){
		Session session = HibernateUtils.getSession();
		try {
			//查询所有的user类的对象
			//String hql = "from User";
			String hql = "select u from User u";//hql中没有*的写法
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//从前台传递过来的是页码PageNo,  startNum = (pageNo - 1)*pageSize
			
			//查询列表
			List<User> userList = query.setFirstResult(5)
										.setMaxResults(5)
										.list();
			for(User user: userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.user_id as user_id1_0_, user0_.uname as uname2_0_, user0_.gender as gender3_0_, user0_.birthday as birthday4_0_ from t_user user0_ limit ?, ?
User [userId=6, uname=任亮5, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=7, uname=任亮6, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=8, uname=任亮7, gender=2, birthday=2015-09-16 22:19:02.0]
User [userId=9, uname=任亮8, gender=1, birthday=2015-09-16 22:19:02.0]
User [userId=10, uname=任亮9, gender=2, birthday=2015-09-16 22:19:02.0]
限定查询

限定查询第一种方式

/**
	 * 限定查询
	 */
	@Test
	public void testQuery5(){
		Session session = HibernateUtils.getSession();
		try {
		
			String hql = "select u from User u where u.gender = ? and u.uname = ?";//hql中没有*的写法
			Query query = session.createQuery(hql);
			//设置第一个参数的值,和JDBC不同,预编译的索引从0开始
			query.setParameter(0, 2);
			query.setParameter(1, "任亮5");
			List<User> userList = query.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.user_id as user_id1_0_, user0_.uname as uname2_0_, user0_.gender as gender3_0_, user0_.birthday as birthday4_0_ from t_user user0_ where user0_.gender=? and user0_.uname=?
User [userId=6, uname=任亮5, gender=2, birthday=2015-09-16 22:19:02.0]

限定查询第二种方式

/**
	 * 限定查询
	 */
	@Test
	public void testQuery6(){
		Session session = HibernateUtils.getSession();
		try {
			//传参的语法		:[自定义名称]
			String hql = "select u from User u where u.gender = :gender and u.uname = :uname";//hql中没有*的写法
			Query query = session.createQuery(hql);
			//给自定义的参数赋值
			query.setParameter("gender", 1);
			query.setParameter("uname", "任亮8");
			List<User> userList = query.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
统计查询
/**
	 * 统计查询
	 */
	@Test
	public void testQuery5(){
		Session session = HibernateUtils.getSession();
		try {
			//查询记录数
			//String hql = "select count(u.userId) from User u";
			//查询最大值
			//String hql = "select max(u.userId) from User u";
			//查询最小值
			//String hql = "select min(u.userId) from User u";
			//查询平均值
			//String hql = "select avg(u.userId) from User u";
			//统计求和
			String hql = "select sum(u.userId) from User u";
			Query query = session.createQuery(hql);
			//查询唯一的结果
			Object obj = query.uniqueResult();
			System.out.println(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
分组统计查询
@Test
	public void testQuery6(){
		Session session = HibernateUtils.getSession();
		try {
			
			//统计求和
			String hql = "select avg(u.salary), u.gender from User u group by u.gender having avg(u.salary) > 1400";
			Query query = session.createQuery(hql);
			//查询唯一的结果
			List<Object[]> objArrList = query.list();
			for(Object[] objArr : objArrList){
				System.out.println("平均工资:" + objArr[0]+ "  性别:"+objArr[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
投影查询
/**
	 * 投影查询
	 */
	@Test
	public void testQuery7(){
		Session session = HibernateUtils.getSession();
		try {
			
			//我们可以创建一个业务Bean,在Bean提供有参数的构造器来接收sql返回的值,创建出对象语法 在select后面new com.rl.hiber.model.EmpBean(max(u.salary), u.gender)
			String hql = "select new com.rl.hiber.model.EmpBean(max(u.salary), u.gender) from User u group by u.gender having avg(u.salary) > 1400";
			Query query = session.createQuery(hql);
			//查询唯一的结果
			List<EmpBean> objArrList = query.list();
			for(EmpBean objArr : objArrList){
				System.out.println(objArr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
排序查询
/**
	 * 按着工资排序
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		try {
			//查询所有的user类的对象
			//String hql = "from User";
			String hql = "select u from User u order by u.salary desc";//hql中没有*的写法
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//查询列表
			List<User> userList = query.list();
			for(User user: userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
模糊查询
/**
	 * 模糊查询
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		try {
			//String hql = "select u from User u where u.uname like '%亮%'";//hql中没有*的写法
			//模糊查询和sql中的语法一致
			String hql = "select u from User u where u.uname like '%亮_'";//hql中没有*的写法
			//根据hql语句创建查询对象
			Query query = session.createQuery(hql);
			//查询列表
			List<User> userList = query.list();
			for(User user: userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

HQL提取到配置文件中
<hibernate-mapping package="com.rl.hiber.model">
	<!-- 
		lazy:当前类是否使用延迟加载,默认是true使用,false不使用
	 -->
	<class name="User" table="t_user">
		<!-- id
			是主键映射配置
		 -->
		<id name="userId" column="user_id">
			<!-- 
				generator:主键的映射策略
			 -->
			<generator class="native"></generator>
		</id>
		<property name="uname"></property>
		<property name="salary"></property>
		<property name="gender"></property>
		<property name="birthday"></property>
	</class>
	<!-- 
		query:定义hql语句
		name:查询的名字,唯一
	 -->
	<query name="getUserAll">
		<![CDATA[
			from User u where u.salary > :salary
		]]>
	</query>
</hibernate-mapping>

查询:

@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		try {
			//从映射文件中获得hql语句创建query对象
			Query query = session.getNamedQuery("getUserAll");
			query.setParameter("salary", 1500);
			//查询列表
			List<User> userList = query.list();
			for(User user: userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select user0_.user_id as user_id1_0_, user0_.uname as uname2_0_, user0_.salary as salary3_0_, user0_.gender as gender4_0_, user0_.birthday as birthday5_0_ from t_user user0_ where user0_.salary>?
User [userId=7, uname=任亮6, gender=1, salary=1600, birthday=2015-09-16 23:06:25.0]
User [userId=8, uname=任亮7, gender=2, salary=1700, birthday=2015-09-16 23:06:25.0]
User [userId=9, uname=任亮8, gender=1, salary=1800, birthday=2015-09-16 23:06:25.0]
User [userId=10, uname=任亮9, gender=2, salary=1900, birthday=2015-09-16 23:06:25.0]

QBC查询

QBC(Query By Criteria)是hibernate提供的一套查询API,跨数据库。

基本查询

查询User的对象

/**
	 * QBC的对象全量查询
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

单个属性的查询

/**
	 * 查询单个属性
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//获得具体要查询的属性
			PropertyProjection  pp  = Projections.property("uname");
			//设置具体要查询的列
			c.setProjection(pp);
			//查询User类对象的列表
			List<String> unames = c.list();
			for(String name : unames){
				System.out.println(name);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.uname as y0_ from t_user this_

User对象多个属性的查询

@Test
	public void testQuery3(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//创建要查询的列的集合
			ProjectionList pl = Projections.projectionList();
			//获得具体要查询的属性
			PropertyProjection  pp  = Projections.property("uname");
			PropertyProjection  pp1  = Projections.property("gender");
			//把要查询的属性加入到集合中
			pl.add(pp);
			pl.add(pp1);
			//设置具体要查询的列
			c.setProjection(pl);
			//查询User类对象的列表
			List<Object[]> objArrList = c.list();
			for(Object[] objArr : objArrList){
				System.out.println("姓名:"+objArr[0]+ "  性别:"+objArr[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.uname as y0_, this_.gender as y1_ from t_user this_
姓名:任亮0  性别:1
姓名:任亮1  性别:2
姓名:任亮2  性别:1
统计查询
/**
	 * QBC统计查询
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//设置要查询的项
			c.setProjection(Projections.rowCount());
			Object obj = c.uniqueResult();
			System.out.println("总记录数:"+obj);
			
			//设置要查询薪水的最大值
			c.setProjection(Projections.max("salary"));
			Object obj1 = c.uniqueResult();
			System.out.println("最高薪水:"+obj1);
			
			//设置要查询薪水的最小值
			c.setProjection(Projections.min("salary"));
			Object obj2 = c.uniqueResult();
			System.out.println("最低薪水:"+obj2);
			
			//设置要查询薪水的平均值
			c.setProjection(Projections.avg("salary"));
			Object obj3 = c.uniqueResult();
			System.out.println("平均薪水:"+obj3);
			
			//设置要查询薪水的平均值
			c.setProjection(Projections.sum("salary"));
			Object obj4 = c.uniqueResult();
			System.out.println("员工薪水总和:"+obj4);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select count(*) as y0_ from t_user this_
总记录数:10
Hibernate: select max(this_.salary) as y0_ from t_user this_
最高薪水:1900
Hibernate: select min(this_.salary) as y0_ from t_user this_
最低薪水:1000
Hibernate: select avg(this_.salary) as y0_ from t_user this_
平均薪水:1450.0
Hibernate: select sum(this_.salary) as y0_ from t_user this_
员工薪水总和:14500
分组统计查询
/**
	 * 分组统计查询
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//创建查询项的集合
			ProjectionList pl = Projections.projectionList();
			//创建查询项
			PropertyProjection pp = Projections.property("gender");
			//创建统计项
			AggregateProjection ap = Projections.max("salary");
			//设置按着哪一项分组
			PropertyProjection pp1 = Projections.groupProperty("gender");
			//把要查询的项加入到集合
			pl.add(pp);
			pl.add(ap);
			pl.add(pp1);
			//把查询集合设置给qbc接口
			c.setProjection(pl);
			List<Object[]> objArrList = c.list();
			for(Object[] objArr : objArrList){
				System.out.println("性别:"+objArr[0]+ "   最高的工资是:"+objArr[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.gender as y0_, max(this_.salary) as y1_, this_.gender as y2_ from t_user this_ group by this_.gender
性别:1   最高的工资是:1800
性别:2   最高的工资是:1900
排序
/**
	 * QBC的排序
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//设置排序字段
			c.addOrder(Order.desc("salary"));
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
分页查询
/**
	 * QBC分页查询
	 */
	@Test
	public void testQuery2(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//设置排序字段
			c.addOrder(Order.desc("salary"));
			//设置开始行号
			c.setFirstResult(5);
			//设置每页记录数
			c.setMaxResults(5);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ order by this_.salary desc limit ?, ?
User [userId=5, uname=任亮4, gender=1, salary=1400, birthday=2015-09-16 23:06:25.0]
User [userId=4, uname=任亮3, gender=2, salary=1300, birthday=2015-09-16 23:06:25.0]
User [userId=3, uname=任亮2, gender=1, salary=1200, birthday=2015-09-16 23:06:25.0]
User [userId=2, uname=任亮1, gender=2, salary=1100, birthday=2015-09-16 23:06:25.0]
User [userId=1, uname=任亮0, gender=1, salary=1000, birthday=2015-09-16 23:06:25.0]
限定查询

我们通过Restrictions来设置限定查询的条件

短语含义
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.andand 关系
Restrictions.oror关系
Restrictions.sqlRestrictionSql限定查询

查询工号是5

/**
	 * QBC限定查询
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//创建查询条件
			Criterion ct = Restrictions.eq("userId", 5);
			//把查询条件设置给QBC的查询接口
			c.add(ct);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where this_.user_id=?
User [userId=5, uname=任亮4, gender=1, salary=1400, birthday=2015-09-16 23:06:25.0]

查询工资大于1500小于1800的员工

/**
	 * 工资大于1500小于1800的员工
	 */
	@Test
	public void testQuery3(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//创建查询条件,默认查询条件使用and来做连接
			Criterion ct = Restrictions.gt("salary", 1500);
			Criterion ct1 = Restrictions.lt("salary", 1800);
			//把查询条件设置给QBC的查询接口
			c.add(ct);
			c.add(ct1);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where this_.salary>? and this_.salary<?
User [userId=7, uname=任亮6, gender=1, salary=1600, birthday=2015-09-16 23:06:25.0]
User [userId=8, uname=任亮7, gender=2, salary=1700, birthday=2015-09-16 23:06:25.0]

In的使用

@Test
	public void testQuery4(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//定义要查询的in的集合(也可以是数组)
			Integer[] userIds = new Integer[]{1,2,3};
			//设置查询条件
			Criterion ct = Restrictions.in("userId", userIds);
			c.add(ct);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where this_.user_id in (?, ?, ?)
User [userId=1, uname=任亮0, gender=1, salary=1000, birthday=2015-09-16 23:06:25.0]
User [userId=2, uname=任亮1, gender=2, salary=1100, birthday=2015-09-16 23:06:25.0]
User [userId=3, uname=任亮2, gender=1, salary=1200, birthday=2015-09-16 23:06:25.0]

And的使用

@Test
	public void testQuery5(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//and的条件的使用
			Criterion ct = Restrictions.and(Restrictions.ge("salary", 1500), 
											Restrictions.eq("gender", 2));
			c.add(ct);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where (this_.salary>=? and this_.gender=?)
User [userId=6, uname=任亮5, gender=2, salary=1500, birthday=2015-09-16 23:06:25.0]
User [userId=8, uname=任亮7, gender=2, salary=1700, birthday=2015-09-16 23:06:25.0]
User [userId=10, uname=任亮9, gender=2, salary=1900, birthday=2015-09-16 23:06:25.0]

Or条件的使用

/**
	 * or
	 */
	@Test
	public void testQuery6(){
		Session session = HibernateUtils.getSession();
		
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//or的条件的使用
			Criterion ct = Restrictions.or(Restrictions.ge("salary", 1800), 
											Restrictions.eq("gender", 1));
			c.add(ct);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where (this_.salary>=? or this_.gender=?)
User [userId=1, uname=任亮0, gender=1, salary=1000, birthday=2015-09-16 23:06:25.0]
User [userId=3, uname=任亮2, gender=1, salary=1200, birthday=2015-09-16 23:06:25.0]
User [userId=5, uname=任亮4, gender=1, salary=1400, birthday=2015-09-16 23:06:25.0]
User [userId=7, uname=任亮6, gender=1, salary=1600, birthday=2015-09-16 23:06:25.0]
User [userId=9, uname=任亮8, gender=1, salary=1800, birthday=2015-09-16 23:06:25.0]
User [userId=10, uname=任亮9, gender=2, salary=1900, birthday=2015-09-16 23:06:25.0]
模糊查询
/**
	 * 模糊查询
	 */
	@Test
	public void testQuery7(){
		Session session = HibernateUtils.getSession();
		try {
			//创建qbc的查询接口的实现类
			Criteria c = session.createCriteria(User.class);
			//or的条件的使用,like的模糊查询like的第二个参数和sql语法一致,只是不需要单引号
			Criterion ct = Restrictions.like("uname", "任%");
			c.add(ct);
			//查询User类对象的列表
			List<User> userList = c.list();
			for(User user : userList){
				System.out.println(user);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select this_.user_id as user_id1_0_0_, this_.uname as uname2_0_0_, this_.salary as salary3_0_0_, this_.gender as gender4_0_0_, this_.birthday as birthday5_0_0_ from t_user this_ where this_.uname like ?
User [userId=1, uname=任亮0, gender=1, salary=1000, birthday=2015-09-16 23:06:25.0]
User [userId=2, uname=任亮1, gender=2, salary=1100, birthday=2015-09-16 23:06:25.0]
User [userId=3, uname=任亮2, gender=1, salary=1200, birthday=2015-09-16 23:06:25.0]

SQL查询

可以使用原生sql查询

/**
	 * QBC的对象全量查询
	 */
	@Test
	public void testQuery1(){
		Session session = HibernateUtils.getSession();
		try {
			//sql定义
			String sql = "select uname, gender from t_user";
			//创建sql的查询接口的实现类
			SQLQuery query = session.createSQLQuery(sql);
			List<Object[]> objArrList = query.list();
			for(Object[] objArr : objArrList){
				System.out.println("姓名:"+objArr[0]+ "  性别:"+objArr[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select uname, gender from t_user
姓名:任亮0  性别:1
姓名:任亮1  性别:2
姓名:任亮2  性别:1
姓名:任亮3  性别:2
姓名:任亮4  性别:1

继承映射

单表继承映射

在这里插入图片描述
在这里插入图片描述
配置

<hibernate-mapping package="com.rl.hiber.model">
	<class name="Animal" table="t_animal">
		<!-- id
			是主键映射配置
		 -->
		<id name="anId" column="an_id">
			<!-- 
				generator:主键的映射策略
			 -->
			<generator class="native"></generator>
		</id>
		<!-- 鉴别器,在单表中加入一列来区分子类的 -->
		<discriminator column="type" type="string"></discriminator>
		<property name="anName" column="an_name"></property>
		<property name="gender"></property>
		
		<!-- 子类配置 
			name:子类的类名
			discriminator-value:区分子类的值
		-->
		<subclass name="Pig" discriminator-value="p">
			<!-- 子类中的属性映射 -->
			<property name="weight"></property>
		</subclass>
		<subclass name="Bird" discriminator-value="b">
			<property name="height"></property>
		</subclass>
	</class>
</hibernate-mapping>

保存

@Test
	public void save(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		
		try {
			Pig pig = new Pig();
			pig.setAnName("天蓬元帅");
			pig.setGender(1);
			pig.setWeight(200);
			
			session.save(pig);
			
			Bird b = new Bird();
			b.setAnName("大鹏");
			b.setGender(1);
			b.setHeight(10000);
			session.save(b);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: insert into t_animal (an_name, gender, weight, type) values (?, ?, ?, 'p')
Hibernate: insert into t_animal (an_name, gender, height, type) values (?, ?, ?, 'b')

子类查询

@Test
	public void query(){
		Session session = HibernateUtils.getSession();
		
		try {
			Pig pig = (Pig) session.load(Pig.class, 1);
			System.out.println(pig.getAnName()+"    "+pig.getWeight());
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select pig0_.an_id as an_id1_0_0_, pig0_.an_name as an_name3_0_0_, pig0_.gender as gender4_0_0_, pig0_.weight as weight5_0_0_ from t_animal pig0_ where pig0_.an_id=? and pig0_.type='p'
天蓬元帅    200

查询

get支持多态查询
load的延迟加载的方式返回的是代理类,所以无法做多态查询
/**
	 * load的延迟加载的方式返回的是代理类,所以无法做多态查询
	 */
	@Test
	public void query1(){
		Session session = HibernateUtils.getSession();
		try {
			Animal animal = (Animal) session.load(Animal.class, 1);
			if(animal instanceof Pig){
				System.out.println("是猪");
			}else{
				System.out.println("不是猪");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}
	/**
	 * get支持多态查询
	 */
	@Test
	public void query2(){
		Session session = HibernateUtils.getSession();
		try {
			Animal animal = (Animal) session.get(Animal.class, 1);
			if(animal instanceof Pig){
				System.out.println("是猪");
				Pig pig = (Pig) animal;
				System.out.println(pig.getAnName() +   "   "+pig.getWeight());
			}else{
				System.out.println("不是猪");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

父子表继承映射

父子表继承映射,父类产生父类的表,子类产生子类的表。
在这里插入图片描述
配置

<hibernate-mapping package="com.rl.hiber.model">
	
	<class name="Animal" table="t_animal">
		<!-- id
			是主键映射配置
		 -->
		<id name="anId" column="an_id">
			<!-- 
				generator:主键的映射策略
			 -->
			<generator class="native"></generator>
		</id>
		
		<property name="anName" column="an_name"></property>
		<property name="gender"></property>
		<!-- 
			子类映射配置
			name:子类的名字
			table:子类映射表名
		 -->
		<joined-subclass name="Pig" table="t_pig">
			<!-- 
				key:字表的主键设置
				column:主键名称
			 -->
			<key column="pid"></key>
			<!-- 子类的属性映射 -->
			<property name="weight"></property>
		</joined-subclass>
		<joined-subclass name="Bird" table="t_bird">
			<!-- 
				key:字表的主键设置
				column:主键名称
			 -->
			<key column="bid"></key>
			<!-- 子类的属性映射 -->
			<property name="height"></property>
		</joined-subclass>
		
	</class>
</hibernate-mapping>

父子表的映射因为生成的表多张,查询的时候我们需要多表连接查询,所以效率没有单表继承映射高。

子表继承映射

配置

<hibernate-mapping package="com.rl.hiber.model">
	
	<!-- 字表映射,需要把父类的映射设置成抽象的(不会产生父表)
		abstract="true"
	 -->
	<class name="Animal" table="t_animal" abstract="true">
		<!-- id
			是主键映射配置
		 -->
		<id name="anId" column="an_id">
			<!-- 
				generator:主键的映射策略
			 -->
			<generator class="uuid"></generator>
		</id>
		
		<property name="anName" column="an_name"></property>
		<property name="gender"></property>
		
		<!-- 子表映射 -->
		<union-subclass name="Pig" table="t_pig">
			<property name="weight"></property>
		</union-subclass>
		<union-subclass name="Bird" table="t_bird">
			<property name="height"></property>
		</union-subclass>
	</class>
</hibernate-mapping>

导出表后,产生两张子表,字表中包含父类的映射字段,存取方式一样不再复述

hibernate的并发控制

悲观锁

悲观锁不是hibernate的锁,这是数据库的update锁。Select * from item for update。Hibernate就是用的这种机制,在查询上上锁。

@Test
	public void updateStock(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try{
			//使用悲观锁查询,如果一个请求在查询时,另一个请求被阻塞在外
			Item item = (Item) session.load(Item.class, 1, LockOptions.UPGRADE);
			item.setStock(item.getStock() - 2);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

乐观锁

悲观锁的性能比较低,因为查询也被锁住,我们乐观锁可以很好解决这个问题

通过设置版本号和查询版本号来解决这个问题

@Test
	public void updateStock(){
		Session session = HibernateUtils.getSession();
		Transaction tx = session.beginTransaction();
		try{
			Item item = (Item) session.load(Item.class, 1);
			item.setStock(item.getStock() - 2);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			tx.rollback();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

抓取策略

根据不同需求来选择不同的策略来查询,后台生成的sql也不一样

多对一的单端抓取

many-to-one上的fetch=join
/**
	 * 多对一的单端抓取    many-to-one上的fetch=join
	 */
	@Test
	public void fetch2(){
		Session session = HibernateUtils.getSession();
		try {
			Emp emp = (Emp) session.load(Emp.class,1);
			//发出一条两张表的连接查询把emp和team的数据都查询出来
			System.out.println(emp);
			Team team = emp.getTeam();
			//不发sql
			System.out.println(team);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, emp0_.t_id as t_id6_0_0_, team1_.t_id as t_id1_1_1_, team1_.t_name as t_name2_1_1_, team1_.loc as loc3_1_1_ from t_emp emp0_ left outer join t_team team1_ on emp0_.t_id=team1_.t_id where emp0_.emp_no=?
Emp [empNo=1, ename=0-kobe0, birthday=2015-09-17 20:39:40.0, gender=1, address=洛杉矶]
Team [tId=1, tName=湖人0, loc=洛杉矶]
 many-to-one上的fetch=select
/**
	 * 多对一的单端抓取    many-to-one上的fetch=select
	 */
	@Test
	public void fetch1(){
		Session session = HibernateUtils.getSession();
		try {
			Emp emp = (Emp) session.load(Emp.class,1);
			//发出一条根据emp_no查询emp的sql
			System.out.println(emp);
			//不发sql
			Team team = emp.getTeam();
			//发出一条查询根据t_id查询球队的sql
			System.out.println(team);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			HibernateUtils.closeResource(session);
		}
	}

输出:

Hibernate: select emp0_.emp_no as emp_no1_0_0_, emp0_.ename as ename2_0_0_, emp0_.birthday as birthday3_0_0_, emp0_.gender as gender4_0_0_, emp0_.address as address5_0_0_, emp0_.t_id as t_id6_0_0_ from t_emp emp0_ where emp0_.emp_no=?
Emp [empNo=1, ename=0-kobe0, birthday=2015-09-17 20:39:40.0, gender=1, address=洛杉矶]
Hibernate: select team0_.t_id as t_id1_1_0_, team0_.t_name as t_name2_1_0_, team0_.loc as loc3_1_0_ from t_team team0_ where team0_.t_id=?
Team [tId=1, tName=湖人0, loc=洛杉矶]

总结

  • fetch属性控制生成的SQL语句的策略
    • select:独立查询语句
    • subselect:子查询语句
      – 如果使用Query查询,并且没有提供OID时,才使用子查询
    • join:左外连接查询
      – 如果使用load/get查询才使用左外连接查询
  • lazy
    • false:不开启延迟加载策略
    • true:开启延迟加载策略
    • extre:开启加强延迟加载策略,当调用主关联数据集合对应的size()、isEmpty()等操作时,不加载具体数据

一级缓存

在这里插入图片描述
一级缓存也叫Session的缓存,不能跨Session,如果Session关闭那么缓存数据也清掉。

  • 一级缓存只能缓存实体对象,不能缓存属性
  • Get,load,iterator使用一级缓存,list不使用一级缓存
  • 缓存的刷新,数据库的数据被修改的同时,缓存的数据也会被同步
  • 一级缓存的管理使用Session的evit和clear方法

二级缓存

二级缓存是SessionFactory级别的缓存,这个缓存能被所有的Session共享,可以跨Session,如果SessionFactory关闭,二级缓存随着消失。

二级缓存也是缓存实体对象,不能对普通属性做缓存。
在这里插入图片描述
在这里插入图片描述

二级缓存的应用场景

  • 适合使用二级缓存
    • 数据很少被修改
    • 数据不是特别重要,允许偶尔的并发
    • 参考数据
  • 不适合使用二级缓存
    • 经常要修改的数据
    • 财务数据,绝对不允许并发问题出现。
    • 和其他环境的数据做共享的数据

配置二级缓存

  1. 首先加入二级缓存供应商jar包,为项目添加ehcache对应的jar包
  2. 系统配置文件中开启二级缓存(hibernate.cfg.xml)
    在这里插入图片描述
  3. 系统配置文件中配置二级缓存供应商(hibernate.cfg.xml)在这里插入图片描述
  4. 添加二级缓存配置信息
    – src目录下创建ehcache.xml文件
    – 具体配置信息参考ehcache对应的jar包中配置文件
<diskStore path=“java.io.tmpdir”/>	    
<defaultCache
            maxElementsInMemory="10"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="1200"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds=“60"
            memoryStoreEvictionPolicy="LRU"
            />

Ehcache配置:

属性说明
maxElementsInMemory缓存中对象的个数
eternalElements是否永久有效
TimeToIdleSeconds在对象失效前允许的闲置时间
TimeToLiveSeconds对象在缓存中存在的最大时间
OverFlowToDisk如果内存缓存满了就可以写在硬盘上
MaxElementsOnDisk硬盘上的对象的最大数量
diskPersisent是否在硬盘上永久有效
memoryStoreEvctionPolicyLRC(最近最少使用),FIFO(先进先出)

使用二级缓存的方法:get,load,iterator,不使用的list

  1. 配置加入二级缓存的数据

在映射文件hbm.xml文件中添加配置
在这里插入图片描述
在系统配置文件cfg.xml文件中添加配置
在这里插入图片描述

使用collection-cache定义集合对象缓存,注意这里定义的是关联关系中的集合对象名,而不是关联模型类,更不是集合。

usage定义了缓存的种类:读写缓存、只读缓存等。

在ehcache.xml中添加自定义缓存设定,指定不同的缓存策略

<cache name=“my” 其他配置/>
针对不同的缓存内容,设定使用不同的cache策略
在这里插入图片描述

缓存结构图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二级缓存数据存储区域

  • 类对象缓存区域
  • 关联关系集合对象缓存区域
  • 更新标识时间戳区域
  • 查询缓存区域
    在这里插入图片描述

二级缓存的注意事项

  • 二级缓存的加入可以使用户减少与数据库间进行数据交互的次数,但是并不是所有操作的数据都可以从二级缓存中获取
  • 查询所有姓“李”的教师信息时,如果二级缓存中加载有一定量的数据,但是不确定是不是所有数据,此时数据获取如果从二级缓存中进行,将出现问题。
  • 二级缓存不是数据库的克隆版,不可能将整个数据库信息装入二级缓存,从设计上也是不允许的
  • 二级缓存对数据的识别采用OID的形式进行,只有仅按照OID的形式获取数据,才能从二级缓存中获取
  • 所有从数据库查询得到的数据都将加入二级缓存,为后期查询提高查询速度

查询缓存

二级缓存只能依赖仅使用OID进行查询,这一设定将对二级缓存的实用性大打折扣。

查询缓存可以有效解决上述问题

  • 查询缓存使用查询的最终SQL语句作为Key
  • 查询缓存使用查询的结果作为Value
    在这里插入图片描述

开启查询缓存

设置开启查询缓存功能
在这里插入图片描述

使用查询缓存

对要进行查询缓存的操作开始使用查询缓存设置
在这里插入图片描述
setCacheable(true)操作表明本次查询设定缓存区域为查询缓存区域,而不是二级缓存的常规区域。

注意:查询缓存的数据只能从查询缓存中获取,与二级缓存中其他区域的数据没有关系,因此每次都要设定使用查询缓存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值