hibernate

hibernate是一种orm框架
orm:Object Relational Mapping,即对象关系映射
通过映射文件配置对象与表的关系,代替了jdbc和dbutils

简单的hibernate框架搭建:
1.导包
hibernate包:即官网下载好hibernate后lib目录下的required目录全部jar包
hibernate-release-5.0.7.Final\lib\required
在这里插入图片描述
驱动包:
在这里插入图片描述
log4j包:第一个是核心jar包
在这里插入图片描述
2.创建数据库,准备表,实体

CREATE TABLE cst_customer (
cust_id BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT ‘客户编号(主键)’,
cust_name VARCHAR(32) NOT NULL COMMENT ‘客户名称(公司名称)’,
cust_source VARCHAR(32) DEFAULT NULL COMMENT ‘客户信息来源’,
cust_industry VARCHAR(32) DEFAULT NULL COMMENT ‘客户所属行业’,
cust_level VARCHAR(32) DEFAULT NULL COMMENT ‘客户级别’,
cust_linkman VARCHAR(64) DEFAULT NULL COMMENT ‘联系人’,
cust_phone VARCHAR(64) DEFAULT NULL COMMENT ‘固定电话’,
cust_mobile VARCHAR(16) DEFAULT NULL COMMENT ‘移动电话’,
PRIMARY KEY (cust_id)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

public class Customer {

	private Long cust_id;
	
	private String cust_name;
	private String cust_source;
	private String cust_industry;
	private String cust_level;
	private String cust_linkman;
	private String cust_phone;
	private String cust_mobile;
	public Long getCust_id() {
		return cust_id;
	}
	public void setCust_id(Long cust_id) {
		this.cust_id = cust_id;
	}
	public String getCust_name() {
		return cust_name;
	}
	public void setCust_name(String cust_name) {
		this.cust_name = cust_name;
	}
	public String getCust_source() {
		return cust_source;
	}
	public void setCust_source(String cust_source) {
		this.cust_source = cust_source;
	}
	public String getCust_industry() {
		return cust_industry;
	}
	public void setCust_industry(String cust_industry) {
		this.cust_industry = cust_industry;
	}
	public String getCust_level() {
		return cust_level;
	}
	public void setCust_level(String cust_level) {
		this.cust_level = cust_level;
	}
	public String getCust_linkman() {
		return cust_linkman;
	}
	public void setCust_linkman(String cust_linkman) {
		this.cust_linkman = cust_linkman;
	}
	public String getCust_phone() {
		return cust_phone;
	}
	public void setCust_phone(String cust_phone) {
		this.cust_phone = cust_phone;
	}
	public String getCust_mobile() {
		return cust_mobile;
	}
	public void setCust_mobile(String cust_mobile) {
		this.cust_mobile = cust_mobile;
	}
	@Override
	public String toString() {
		return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
	}
	
	
	

}

3.书写orm元数据(对象与表的映射配置文件)
该配置文件名任意取,满足约束

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
<hibernate-mapping>
	<class name="com.xdh.domain.Customer"  table="cst_customer">
		<id name="cust_id" column="cust_id">
			<generator class=""></generator>
		</id>
		<property name="cust_name" column="cust_name"></property>
		<property name="cust_source" column="cust_source"></property>
		<property name="cust_industry" column="cust_industry"></property>
		<property name="cust_level" column="cust_level"></property>
		<property name="cust_linkman" column="cust_linkman"></property>
		<property name="cust_phone" column="cust_phone"></property>
		<property name="cust_mobile" column="cust_mobile"></property>
	</class>
</hibernate-mapping>	

约束:hibernate-core-5.0.7.Final.jar目录下的org.hibernate目录下的
在这里插入图片描述
4.书写主配置文件:src目录下
约束:这里是hibernate-configuration-3.0.dtd约束
在这里插入图片描述
主约束文件名必须为hibernate.cfg.xml:
配置参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
<!-- 
## MySQL
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate01</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		
<!-- 	
#hibernate.show_sql true
#hibernate.format_sql true
 -->	
 		<property name="hibernate.show_sql">true</property>
 		<property name="hibernate.format_sql">true</property>

<!-- 	
## auto schema export
#hibernate.hbm2ddl.auto create-drop
#hibernate.hbm2ddl.auto create
#hibernate.hbm2ddl.auto update
#hibernate.hbm2ddl.auto validate 
 --> 	
 		<property name="hibernate.hbm2ddl.auto">update</property>
 		
		<mapping resource="com/xdh/domain/customer.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

5.测试类

package com.xdh.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.xdh.domain.Customer;

public class TestCon {

	@Test
	//保存客户
	public void fun1(){
		Configuration conf = new Configuration().configure();
		
		SessionFactory sessionFactory = conf.buildSessionFactory();
		
		Session session = sessionFactory.openSession();
	
		Transaction tx = session.beginTransaction();
		//----------------------------------------------
		Customer c = new Customer();
		c.setCust_name("google公司");
		
		session.save(c);//执行保存
		
		//----------------------------------------------
		tx.commit();
		session.close();
		sessionFactory.close();
	}

}

执行结果:
在这里插入图片描述

配置详解:

1.orm元数据:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
<!-- 根元素,package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简单类名了 -->
<hibernate-mapping package="com.xdh.domain">
	<!-- 
		class元素: 配置实体与表的对应关系的
			name: 完整类名
			table:数据库表名
	 -->
	<!-- <class name="com.xdh.domain.Customer"  table="cst_customer"> -->
	<class name="Customer"  table="cst_customer">
		<!-- id元素:配置主键映射的属性
				name: 填写主键对应属性名
				column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
				type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
						每个类型有三种填法: java类型|hibernate类型|数据库类型
				not-null(可选):配置该属性(列)是否不能为空. 默认值:false
				length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
		 -->
		<id name="cust_id" column="cust_id">
			<!-- generator:主键生成策略 -->
			<generator class="native"></generator>
		</id>
		
		<!-- property元素:除id之外的普通属性映射
				name: 填写属性名
				column(可选): 填写列名
				type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
						每个类型有三种填法: java类型|hibernate类型|数据库类型
				not-null(可选):配置该属性(列)是否不能为空. 默认值:false
				length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
		 -->
		 <!-- type
		 1.java类型:<property name="cust_name" column="cust_name" type="java.lang.String"></property>
		 2.hibernate类型:<property name="cust_name" column="cust_name" type="string"></property>
		 3.数据库类型<property name="cust_name" column="cust_name">
		 				<column name="cust_name" sql-type="varchar" ></column>
		 			</property>
		  -->
		<property name="cust_name" column="cust_name"></property>
		<property name="cust_source" column="cust_source"></property>
		<property name="cust_industry" column="cust_industry"></property>
		<property name="cust_level" column="cust_level"></property>
		<property name="cust_linkman" column="cust_linkman"></property>
		<property name="cust_phone" column="cust_phone"></property>
		<property name="cust_mobile" column="cust_mobile"></property>
	</class>
</hibernate-mapping>		

2.主配置文件:

必选属性配置(5个):

<!-- 数据库驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 数据库url -->
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate01</property>
		<!-- 数据库连接用户名 -->
		<property name="hibernate.connection.username">root</property>
		<!-- 数据库连接密码 -->
		<property name="hibernate.connection.password">root</property>
		<!-- 数据库方言
			不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
			sql99标准: DDL 定义语言  库表的增删改查
					  DCL 控制语言  事务 权限
					  DML 操纵语言  增删改查
			注意: MYSQL在选择方言时,请选择最短的方言.通用语法,针对不同引擎
		 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

可选属性配置:

<!-- 将hibernate生成的sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
<property name="hibernate.format_sql">true</property>
<!-- 
## auto schema export  自动导出表结构. 自动建表
#hibernate.hbm2ddl.auto create		自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
#hibernate.hbm2ddl.auto create-drop 自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
#hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
#hibernate.hbm2ddl.auto validate	校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败,抛出异常
 -->
 <property name="hibernate.hbm2ddl.auto">update</property>

元数据引入配置:

<!-- 引入orm元数据
路径书写: 填写src下的路径
-->
<mapping resource="com/xdh/domain/customer.hbm.xml"/>

API详解:
四个对象
1.Configuration
Configuration功能: 配置加载类,用于加载主配置,orm元数据加载

package com.xdh.api;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

//Configuration功能: 配置加载类,用于加载主配置,orm元数据加载
public class ConfigurationDemo {
	@Test
	public void fun1(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration();
		//2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
		conf.configure();
		//3 读取指定orm元数据(扩展),如果主配置中已经引入映射配置.不需要手动加载
		//conf.addResource(resourceName);
		//conf.addClass(persistentClass);
		
		//4 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		
	}

}

2.SessionFactory
SessionFactory功能: 用于创建操作数据库核心对象session对象的工厂.
简单说功能就一个—创建session对象
注意:1.sessionfactory 负责保存和使用所有配置信息.消耗内存资源非常大.
2.sessionFactory属于线程安全的对象设计.
结论: 保证在web项目中,只创建一个sessionFactory.

package com.xdh.api;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class SessionFactoryDemo {
	@Test
	public void fun1(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration();
		//2 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
		conf.configure();
		
		//3 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//--------------------------------------------------
		//4 获得session
		//打开一个新的session对象
		sf.openSession();
		//获得一个与线程绑定的session对象
		sf.getCurrentSession();
	}
}

3.Session
session对象功能: 表达hibernate框架与数据库之间的连接(会话).session类似于JDBC年代的connection对象,还可以完成对数据库中数据的增删改查操作.
session是hibernate操作数据库的核心对象

package com.xdh.api;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.xdh.domain.Customer;

public class SessionDemo {
	@Test
	//事务操作
	public void fun1(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//3 获得session
		Session session = sf.openSession();
		//4 session获得操作事务的Transaction对象
		//获得操作事务的tx对象
		//Transaction tx = session.getTransaction();
		//开启事务
		//tx.begin();
		//开启事务并获得操作事务的tx对象(建议使用)
		Transaction tx2 = session.beginTransaction();
		//----------------------------------------------
		
		
		//----------------------------------------------
		tx2.commit();//提交事务
		tx2.rollback();//回滚事务
		session.close();//释放资源
		sf.close();//释放资源
	}
	
	@Test
	//session的新增
	public void fun2(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//3 获得session
		Session session = sf.openSession();
		//4 session获得操作事务的Transaction对象
		//开启事务并获得操作事务的tx对象(建议使用)
		Transaction tx2 = session.beginTransaction();
		//----------------------------------------------
		Customer c = new Customer();
		c.setCust_name("sogou");
		
		session.save(c);
		//----------------------------------------------
		tx2.commit();//提交事务
		session.close();//释放资源
		sf.close();//释放资源
	}
	@Test
	//session的查询
	//查询id为1的customer对象
	public void fun3(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//3 获得session
		Session session = sf.openSession();
		//4 session获得操作事务的Transaction对象
		//开启事务并获得操作事务的tx对象(建议使用)
		Transaction tx2 = session.beginTransaction();
		//----------------------------------------------
		
		Customer customer = session.get(Customer.class, 1l);
		
		System.out.println(customer);
		//----------------------------------------------
		tx2.commit();//提交事务
		session.close();//释放资源
		sf.close();//释放资源
	}
	@Test
	//session的修改
	//修改id为1的customer对象的name属性为黑马程序员
	public void fun4(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//3 获得session
		Session session = sf.openSession();
		//4 session获得操作事务的Transaction对象
		//开启事务并获得操作事务的tx对象(建议使用)
		Transaction tx2 = session.beginTransaction();
		//----------------------------------------------
		//1 获得要修改的对象
		Customer c = session.get(Customer.class, 1l);
		//2 修改
		c.setCust_name("firefox");
		//3 执行update
		session.update(c);
		//----------------------------------------------
		tx2.commit();//提交事务
		session.close();//释放资源
		sf.close();//释放资源
	}
	@Test
	//session的删除
	//删除id为1的customer对象
	public void fun5(){
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		SessionFactory sf = conf.buildSessionFactory();
		//3 获得session
		Session session = sf.openSession();
		//4 session获得操作事务的Transaction对象
		//开启事务并获得操作事务的tx对象(建议使用)
		Transaction tx2 = session.beginTransaction();
		//----------------------------------------------
		//1 获得要修改的对象
		Customer c = session.get(Customer.class, 1l);
		//2 调用delete删除对象
		session.delete(c);
		//----------------------------------------------
		tx2.commit();//提交事务
		session.close();//释放资源
		sf.close();//释放资源
	}
}


4.Transaction
事务开启,事务提交,事务回滚

整合成一个返回session对象的Hibernate工具类:

package com.xdh.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
	private static SessionFactory sf;
	
	static{
		//1 创建,调用空参构造
		Configuration conf = new Configuration().configure();
		//2 根据配置信息,创建 SessionFactory对象
		 sf = conf.buildSessionFactory();
	}
	
	//获得session => 获得全新session
	public static Session openSession(){
				//3 获得session
				Session session = sf.openSession();
				
				return session;
		
	}
	//获得session => 获得与线程绑定的session
	public static Session getCurrentSession(){
		//3 获得session
		Session session = sf.getCurrentSession();
		
		return session;
	}
	public static void main(String[] args) {
		System.out.println(HibernateUtils.openSession());
	}
	
}

hibernate中的实体规则

1.实体类创建的注意事项:
1)持久化类提供无参构造(newInstance方法需要调用无参构造)
2)成员变量私有,提供get/set方法,即提供属性
3)持久化类中的属性,尽量使用包装类型
包装类型的初始值为null,防止数据库中有空值给基本类型赋不上值
4)持久化类需要提供oid,与数据库中主键对应
没有主键的表无法映射到hibernate中
5)不要用final修饰class
hibernate使用cglib代理生成代理对象,代理对象继承被代理对象,如果被final修饰将无法生成代理对象

2.主键类型:
1)自然主键
表的业务中有某业务列符合主键规则,可作为主键使用
2)代理主键
创建一个没有业务意义的列作为主键

3.主键生成策略
元数据orm中关于主键的配置:

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

hibernate中的对象状态

三种状态:
1.瞬时状态
没有id,没有在session缓存中
2.持久化状态
有id,在session缓存中
特点:持久化状态对象的任何变化都会自动同步到数据库中
3.游离/托管状态
有id,没有在session缓存中

Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
c.setCust_name("baidu公司");//瞬时状态
session.save(c);//持久化状态
tx.commit();
session.close();//关闭后,有id,没有关联,游离/托管状态

save方法本质是一个对象状态转化,为了生成id

三种状态转换:
在这里插入图片描述
hibernate:一级缓存
缓存:提高效率

提高效率手段:
1.查询时,第一次查询时,对象会放入缓存,再次查询则返回缓存中数据,提高查询效率

//执行以下三条语句,只执行一次select
Customer c1 =  session.get(Customer.class, 1l);
Customer c2 =  session.get(Customer.class, 1l);
Customer c3 =  session.get(Customer.class, 1l);
System.out.println(c1==c3);//返回true

在这里插入图片描述
2.修改时,使用快照对比修改前后对象属性区别,只执行一次修改,减少不必要的修改语句发送

//假设当cust_id为1l时,cust_name为哈哈,以下代码只执行了select(快照)
Customer customer = session.get(Customer.class, 1l);
customer.setCust_name("呵呵");
customer.setCust_name("哈哈");

在这里插入图片描述
hibernate的事务

在主配置文件中配置事务的隔离级别:

 <!-- 指定hibernate操作数据库时的隔离级别 
	#hibernate.connection.isolation 1|2|4|8		
	0001	1	读未提交
	0010	2	读已提交
	0100	4	可重复读
	1000	8	串行化
 -->
 <property name="hibernate.connection.isolation">4</property>

在项目中管理事务:
业务开始之前打开事务,业务执行之后提交事务,执行过程中出现异常,回滚事务

在Dao层操作数据库需要使用到session对象,在service层控制事务也使用到session对象,这时需确保dao层和service层使用的是同一个session

在hibernate中,使用sessionFactory.getCurrentSession()即获得了与当前线程绑定的session对象

注意:
1.调用getCurrentSession()方法需在主配置文件中配置:

<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>

2.通过getCurrentSession()方法获得的session对象,当事务提交时,session会自动关闭,不能手动关闭

hibernate中的批量查询

1.HQL查询
hibernate独家查询语言,属于面向对象的查询语言,select * from 完整类名 where 属性名 = XXX,不出现数据库表名和列名

  • 基本查询:

1)返回多条:

//1> 书写HQL语句
//String hql = " from com.xdh.domain.Customer ";
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list();	// 返回list结果

2)返回单条:

String hql = " from Customer where cust_id = 1l";
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
Customer c =(Customer) query.uniqueResult();//接收唯一的查询结果
  • 条件查询:
    1)?占位符的使用
		//1> 书写HQL语句
		String hql = " from Customer where cust_id = ? "; // 查询所有Customer对象
		//2> 根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//设置参数
		//query.setLong(0, 1l);
		query.setParameter(0, 1l);//通用
		//3> 根据查询对象获得查询结果
		Customer c = (Customer) query.uniqueResult();

这里注意索引从0开始,JDBC的setString()从1开始

2)命名占位符的使用

//1> 书写HQL语句
String hql = " from Customer where cust_id = :cust_id "; //冒号后为自定义占位符名称
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id", 1l);//键对应自己定义的占位符名称
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
  • 分页查询:
//1> 书写HQL语句
String hql = " from Customer  "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置分页信息 limit ?,?
query.setFirstResult(1);//第几条
query.setMaxResults(1);//展示几条
//3> 根据查询对象获得查询结果
List<Customer> list =  query.list();

2.Criteria查询
hibernate自创的无语句面向对象查询

  • 基本查询
Criteria criteria = session.createCriteria(Customer.class);
		
List<Customer> list = criteria.list();//多条

Customer c = (Customer) criteria.uniqueResult();//单条
  • 条件查询
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//添加查询参数 => 查询cust_id为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
//执行查询获得结果
Customer c = (Customer) criteria.uniqueResult();

注意:
// > gt
// >= ge
// < lt
// <= le
// == eq
// != ne
// in in
// between and between
// like like
// is not null isNotNull
// is null isNull
// or or
// and and

  • 分页查询
		//创建criteria查询对象
		Criteria criteria = session.createCriteria(Customer.class);
		//设置分页信息 limit ?,?
		criteria.setFirstResult(1);
		criteria.setMaxResults(2);
		//执行查询
		List<Customer> list = criteria.list();
  • 查询总记录数
		//创建criteria查询对象
		Criteria criteria = session.createCriteria(Customer.class);
		//设置查询的聚合函数 => 总行数
		criteria.setProjection(Projections.rowCount());
		//执行查询
		Long count = (Long) criteria.uniqueResult();

原生SQL查询

  • 基本查询

1)返回数组List

		//1 书写sql语句
		String sql = "select * from cst_customer";
		//2 创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		//3 调用方法查询结果
		List<Object[]> list = query.list();//多条
		//query.uniqueResult();//单条

2)返回对象List

		String sql = "select * from cst_customer";
		//2 创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		//指定将结果集封装到哪个对象中
		query.addEntity(Customer.class);
		//3 调用方法查询结果
		List<Customer> list = query.list();
  • 条件查询
		//1 书写sql语句
		String sql = "select * from cst_customer where cust_id = ? ";
		//2 创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		query.setParameter(0, 1l);
		//指定将结果集封装到哪个对象中
		query.addEntity(Customer.class);
		//3 调用方法查询结果
		Customer c = (Customer)query.uniqueResult();

注意:索引从0开始

  • 分页查询
		//1 书写sql语句
		String sql = "select * from cst_customer  limit ?,? ";
		//2 创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		query.setParameter(0, 0);
		query.setParameter(1, 1);
		//指定将结果集封装到哪个对象中
		query.addEntity(Customer.class);
		//3 调用方法查询结果
		List<Customer> list = query.list();

多表关系在hibernate中的表达

1.一对多/多对一

1)数据库中表达
从表外键指向主表主键
2)在对象中的表达

  • 主对象中:
    private Set<从对象> xx;
	//使用set集合,表达一对多关系
	private Set<LinkMan> linkMens = new HashSet<LinkMan>();
	
  • 从对象中:
    private 主对象 xx;
//表达多对一关系
private Customer customer ;

3)元数据orm中的表达:

  • 主对象的映射文件:
<!-- 集合,一对多关系,在配置文件中配置 -->
		<!-- 
			name属性:集合属性名
			column属性: 外键列名
			class属性: 关联的对象完整类名
		 -->
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
		</set>
  • 从对象的映射文件:
<!-- 多对一 -->
		<!-- 
			name属性:引用属性名
			column属性: 外键列名
			class属性: 与我关联的对象完整类名
		 -->
		<many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
		</many-to-one>

测试:

		Customer c = new Customer();
		c.setCust_name("baidu");
		
		LinkMan lm1 = new LinkMan();
		lm1.setLkm_name("mrli");
		
		LinkMan lm2 = new LinkMan();
		lm2.setLkm_name("missma");
		
		//表达一对多,客户下有多个联系人
		//如果customer元数据配置了放弃维护关系,以下两行代码无需执行
		c.getLinkMens().add(lm1);
		c.getLinkMens().add(lm2);
		
		//表达多对一,联系人属于哪个客户
		lm1.setCustomer(c);
		lm2.setCustomer(c);
		
		session.save(c);
		//如果customer元数据配置了cascade="save-update",以下两行代码无需执行
		session.save(lm1);
		session.save(lm2);

补充级联和关系(外键)维护属性配置:
主对象元数据中:

		 <!-- 
		 	级联操作:	cascade
		 		save-update: 级联保存更新,即主对象更新数据,从对象同步更新
		 		delete:级联删除
		 		all:save-update+delete
		 	级联操作: 简化操作.目的就是为了少两行代码.
		  -->
		  <!-- inverse属性: 配置关系是否维护. 
		  		true: customer不维护关系
		  		false(默认值): customer维护关系
		  		
		  	inverse属性: 性能优化.提高关系维护的性能.
		  	原则: 无论怎么放弃,总有一方必须要维护关系.
		  	一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
		  -->
		<set name="linkMens" inverse="true" cascade="save-update"  >
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
		</set>

从对象元数据中:

		  <!-- 
		 	级联操作:	cascade
		 		save-update: 级联保存更新
		 		delete:级联删除
		 		all:save-update+delete
		 	级联操作: 简化操作.目的就是为了少些两行代码.
		  -->
		  <!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方.  -->
		<many-to-one name="customer" column="lkm_cust_id" class="Customer"  cascade="save-update">
		</many-to-one>

注意:
1).主从对象元数据中只需一方配置cascade=""
2).在保存时,双方都会维护外键关系,关系维护两次,冗余了
3).外键在的一方不能放弃维护关系,

2.多对多

1)数据库中表达
使用中间表,至少两类,都是外键列,分别引用两张表的主键
2)实体中表达
实体A:
private Set b;

private Set<Role> roles = new HashSet<Role>();

实体B:
private Set a;

private Set<User> users = new HashSet<User>();

3)元数据orm中表达
User对象元数据:

<!-- 多对多关系表达 -->
		<!-- 
			name: 集合属性名
			table: 配置中间表名
			key
			 |-column:外键,别人引用"我"的外键列名
			 class: 我与哪个类是多对多关系
			 column:外键.我引用别人的外键列名
		 -->
		 <!-- cascade级联操作:
		 			save-update: 级联保存更新
		 			delete:级联删除
		 			all:级联保存更新+级联删除
		 	结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
		 		 如果使用delete操作太过危险.尤其在多对多中.不建议使用.
		 			 -->
		<set name="roles" table="sys_user_role" cascade="save-update" >
			<key column="user_id" ></key>
			<many-to-many class="Role" column="role_id" ></many-to-many>
		</set>

Role对象元数据:

<!-- 使用inverse属性
			true: 放弃维护外键关系
			false(默认值):维护关系
			
		结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
			 一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
			 那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
		 -->		
		<set name="users" table="sys_user_role" inverse="true" >
			<key column="role_id" ></key>
			<many-to-many class="User" column="user_id" ></many-to-many>
		</set>

测试:

package com.xdh.onemany;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.xdh.domain.Role;
import com.xdh.domain.User;
import com.xdh.utils.HibernateUtils;

public class TestMany2Many {
	
	@Test
	//保存员工以及角色
	public void fun1(){
		//1 获得session
		Session session = HibernateUtils.openSession();
		//2 开启事务
		Transaction tx = session.beginTransaction();
		//-------------------------------------------------
		//3操作
		//1> 创建两个 User
		User u1 = new User();
		u1.setUser_name("张三");
		
		User u2 = new User();
		u2.setUser_name("李四");
		
		//2> 创建两个 Role
		Role r1 = new Role();
		r1.setRole_name("程序员");
		
		Role r2 = new Role();
		r2.setRole_name("会计");
		//3> 用户表达关系
		u1.getRoles().add(r1);
		u1.getRoles().add(r2);
		
		u2.getRoles().add(r1);
		u2.getRoles().add(r2);
		
		//4> 角色表达关系
		//双方默认都维护关系,都会向中间表中插入数据,违反主键唯一原则
		//所以必须只能指定一方维护关系,不指定以下代码报错
		r1.getUsers().add(u1);
		r1.getUsers().add(u2);
		
		r2.getUsers().add(u1);
		r2.getUsers().add(u2);
		
		//5> 调用Save方法一次保存
		session.save(u1);
		session.save(u2);
		session.save(r1);
		session.save(r2);
		//-------------------------------------------------
		//4提交事务
		tx.commit();
		//5关闭资源
		session.close();
	}
	
	
	@Test
	//为张三新增一个角色
	public void fun3(){
		//1 获得session
		Session session = HibernateUtils.openSession();
		//2 开启事务
		Transaction tx = session.beginTransaction();
		//-------------------------------------------------
		//3操作
		//1> 获得张三用户
		User user = session.get(User.class, 1l);
		//2> 创建公关角色
		Role r = new Role();
		r.setRole_name("项目经理");
		//3> 将角色添加到用户中
		user.getRoles().add(r);
		//4> 将角色转换为持久化
		//配了级联后以下代码不用写
		//session.save(r);
		//-------------------------------------------------
		//4提交事务
		tx.commit();
		//5关闭资源
		session.close();
	}
	
	@Test
	//为张三解除一个角色
	public void fun4(){
		//1 获得session
		Session session = HibernateUtils.openSession();
		//2 开启事务
		Transaction tx = session.beginTransaction();
		//-------------------------------------------------
		//3操作
		//1> 获得张三用户
		User user = session.get(User.class, 1l);
		//2> 获得要操作的角色对象(会计,项目经理)
		Role r1 = session.get(Role.class, 2l);
		Role r2 = session.get(Role.class, 3l);
		//3> 将角色从用户的角色集合中移除
		user.getRoles().remove(r1);
		user.getRoles().remove(r2);
		
		//-------------------------------------------------
		//4提交事务
		tx.commit();
		//5关闭资源
		session.close();
	}
}




hibernate查询总结:
1.get()
2.对象属性导航查询
3.HQL
4.Criteria
5.原生SQL

HQL查询:

1)基础语法

		String hql = " from  com.xdh.domain.Customer ";//完整写法
		String hql2 = " from  Customer "; //简单写法
		String hql3 = " from java.lang.Object "; 
		
		Query query = session.createQuery(hql3);
		List list = query.list();

2)排序

		String hql1 = " from  com.xdh.domain.Customer order by cust_id asc ";//完整写法
		String hql2 = " from  com.xdh.domain.Customer order by cust_id desc ";//完整写法
		
		Query query = session.createQuery(hql2);
		List list = query.list();

3)条件查询

		String hql1 = " from  com.xdh.domain.Customer where cust_id =? ";//完整写法
		String hql2 = " from  com.xdh.domain.Customer where cust_id = :id ";//完整写法
		
		Query query = session.createQuery(hql2);
		
//		query.setParameter(0, 2l);
		query.setParameter("id", 2l);
		
		List list = query.list();

4)分页查询

		String hql1 = " from  com.xdh.domain.Customer  ";//完整写法
		
		Query query = session.createQuery(hql1);
		
		//limit ?,?
		query.setFirstResult(2);// (当前页数-1)*每页条数
		query.setMaxResults(2);
		
		List list = query.list();

5)聚合函数查询

		String hql1 = " select count(*) from  com.xdh.domain.Customer  ";//完整写法
		String hql2 = " select sum(cust_id) from  com.xdh.domain.Customer  ";//完整写法
		String hql3 = " select avg(cust_id) from  com.xdh.domain.Customer  ";//完整写法
		String hql4 = " select max(cust_id) from  com.xdh.domain.Customer  ";//完整写法
		String hql5 = " select min(cust_id) from  com.xdh.domain.Customer  ";//完整写法
		
		Query query = session.createQuery(hql5);
		
		Number number  = (Number) query.uniqueResult();

6)投影查询(即查询部分属性)

		String hql1 = " select cust_name from  com.xdh.domain.Customer  ";
		String hql2 = " select cust_name,cust_id from  com.xdh.domain.Customer  ";
		String hql3 = " select new Customer(cust_id,cust_name) from  com.xdh.domain.Customer  ";
		
		Query query = session.createQuery(hql3);
		
		List list = query.list();

7)内连接

  • 内连接
		String hql = " from Customer c inner join c.linkMens ";
		
		Query query = session.createQuery(hql);
		
		List<Object[]> list = query.list();
  • 迫切内连接
		String hql = " from Customer c inner join fetch c.linkMens ";
		
		Query query = session.createQuery(hql);
		
		List<Customer> list = query.list();

内连接是把查询结果封装在Object数组里,数组里有Customer和Linkman两个对象,而迫切内连接则是把查询结果封装在一个对象里

8)左连接

		String hql = " from Customer c left join c.linkMens ";
		
		Query query = session.createQuery(hql);
		
		List<Object[]> list = query.list();

9)右连接

		String hql = " from Customer c right join c.linkMens ";
		
		Query query = session.createQuery(hql);
		
		List<Object[]> list = query.list();

Criteria查询:
1)基本语法

		Criteria c = session.createCriteria(Customer.class);
		
		List<Customer> list = c.list();

2)条件查询

		Criteria c = session.createCriteria(Customer.class);
		
//		c.add(Restrictions.idEq(2l));
		c.add(Restrictions.eq("cust_id",2l));
		
		List<Customer> list = c.list();

3)分页查询

		Criteria c = session.createCriteria(Customer.class);
		//limit ?,? 
		c.setFirstResult(0);
		c.setMaxResults(2);
		
		List<Customer> list = c.list();

4)排序

		Criteria c = session.createCriteria(Customer.class);
		
		c.addOrder(Order.asc("cust_id"));
		//c.addOrder(Order.desc("cust_id"));
		
		List<Customer> list = c.list();

5)聚合函数

		Criteria c = session.createCriteria(Customer.class);
		
		//设置查询目标
		c.setProjection(Projections.rowCount());
		
		List list = c.list();

6)离线Criteria
当使用Criteria查询时,查询条件只能在dao层指定,为了在web层接收参数,所以使用离线Criteria
非离线:
在这里插入图片描述
离线:
在这里插入图片描述

		//Service/web层
		DetachedCriteria dc  = DetachedCriteria.forClass(Customer.class);
		
		dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致)
		
		//----------------------------------------------------
		//Dao层
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//----------------------------------------------------
		Criteria c = dc.getExecutableCriteria(session);
		
		List list = c.list();
		
		System.out.println(list);
		//----------------------------------------------------
		tx.commit();
		session.close();

查询优化:

1.类级别查询
1)get方法: 立即加载,执行方法时立即发送sql语句查询结果
2)load方法:
在类上配置:

<class name="Customer" table="cst_customer" lazy="true">

lazy:true 加载时,不查询,使用时才查询b(默认)
lazy:false 加载时立即查询.

		Transaction tx = session.beginTransaction();
		
		Customer c = session.load(Customer.class, 2l);
		System.out.println(c);//输出c代表使用对象了,执行该条语句才会查询

2.关联级别查询
1)集合策略
即把联系人集合加载到客户类中

<!-- 
		lazy属性: 决定是否延迟加载
			true(默认值): 延迟加载,懒加载
			false: 立即加载
			extra: 极其懒惰
		fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据
			select(默认值): 单表查询加载
			join: 使用多表查询加载集合
			subselect:使用子查询加载集合
	 -->
	 <!-- batch-size: 抓取集合的数量为3.
	 		抓取客户的集合时,一次抓取几个客户的联系人集合.
	  -->
		<set name="linkMens" fetch="select" lazy="true" batch-size="3">
			<key column="lkm_cust_id" ></key>
			<one-to-many class="LinkMan" />
		</set>
  • fetch:select 单表查询
    lazy:true 使用时才加载集合数据.
  • fetch:select 单表查询
    lazy:false 立即记载集合数据
  • fetch:select 单表查询
    lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句)
  • fetch:join 多表查询
    lazy:true|false|extra 失效.立即加载.
  • fetch: subselect 子查询
    lazy: true 懒加载
  • fetch: subselect 子查询
    lazy: false 立即加载
  • fetch: subselect 子查询
    lazy: extra 极其懒惰

2)关联属性策略
即把客户类加载到联系人类中

<!-- 
		fetch 决定加载的sql语句
			select: 使用单表查询
			join : 多表查询
		lazy  决定加载时机
			false: 立即加载
			proxy: 由customer的类级别加载策略决定.
		 -->
		<many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy"  >
  • fetch:select 单表查询
    lazy:proxy
    customer-true 懒加载
  • fetch:join 多表
    lazy: 失效
  • fetch:select 单表查询
    lazy:proxy
    customer-false 立即加载

总结:
1.为了提高效率,fetch的应该用select,lazy应该用true,即都用默认值
2.当用了懒加载后,可能会存在session关闭了,需要的数据还没有返回前端
解决没有session的情况:加一个过滤器
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值