一、Hibernate概述
1.什么是Hibernate?
Hibernate是一个开放源码的ORM(Object Relational Mapping,对象关系映射)框架,它对JDBC进行了轻量级的封装,使得Java开发人员可以使用面向对象的编程思想来操作数据库。
2.什么是ORM?
ORM:Object Relational Mapping(对象关系映射)。指的是将一个Java中的对象与关系型数据库中的表建立一种映射关系,从而操作对象就可以操作数据库中的表。
3.为什么要使用Hibernate?
在使用传统的Servlet+JSP+JavaBean+JDBC开发应用系统,针对大型应用系统开发时,需要写多条sql查询语句,过程枯燥繁琐。使用Hibernate可以提高数据访问层的编程效率,也是最流行的ORM框架。
4.Hibernate5下载使用
下载地址:https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
5.Hibernate压缩包结构
documentation :Hibernate开发的文档
lib :Hibernate开发包
required :Hibernate开发的必须的依赖包
optional :Hibernate开发的可选的jar包
project :Hibernate提供的项目
二、Hibernate简单配置
1.创建数据库和表
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_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;
2.创建实体类
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_phone;
private String cust_mobile;
}
3. 创建映射
在实体类Customer所在包中,创建一个名为Customer.hbm.xml的映射文件,在该文件中定义了实体类Customer的属性是如何映射到cst_customer表的列上的。
<?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.jzfblog.hibernate.Customer" table="cst_customer"> <!-- 建立类中的属性与表中的主键对应 --> <id name="cust_id" column="cust_id" > <generator class="native"/> </id> <!-- 建立类中的普通的属性和表的字段的对应 --> <property name="cust_name" column="cust_name" length="32" /> <property name="cust_source" column="cust_source" length="32"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> </class> </hibernate-mapping>
4.创建一个Hibernate的核心配置文件
Hibernate的核心配置文件的名称:hibernate.cfg.xml
<?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> <!-- #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> <!-- 数据库url --> <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property> <!-- 数据库连接用户名 --> <property name="hibernate.connection.username">root</property> <!-- 数据库连接密码 --> <property name="hibernate.connection.password">1234</property> <!-- 数据库方言 不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成. sql99标准: DDL 定义语言 库表的增删改查 DCL 控制语言 事务 权限 DML 操纵语言 增删改查 注意: MYSQL在选择方言时,请选择最短的方言. --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- #hibernate.show_sql true #hibernate.format_sql true --> <!-- 将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下的路径 --> <!-- 指定hibernate操作数据库时的隔离级别 #hibernate.connection.isolation 1|2|4|8 0001 1 读未提交 0010 2 读已提交 0100 4 可重复读 1000 8 串行化 --> <property name="hibernate.connection.isolation">4</property> <!-- 指定session与当前线程绑定 --> <property name="hibernate.current_session_context_class">thread</property> <mapping resource="cn/jzfblog/domain/Customer.hbm.xml" /> </session-factory> </hibernate-configuration>
5.编写测试代码
首先创建Configuration类的实例,并通过它来读取并解析配置文件hibernate,cfg.xml。然后创建SessionFactory读取解析映射文件信息,并将Configration对象中所有配置信息拷贝到SessionFactory内存中。接下来,打开Session,让SessionFactory提供链接,并开启事务,之后创建对象,向对象中添加数据,通过session.save()方法完成向数据库中保存数据的操作。最后提交事务,并关闭资源。
// 1.加载Hibernate的核心配置文件
Configuration configuration = new Configuration().configure();
// 手动加载映射
// configuration.addResource("com/jzfblog/hibernate/Customer.hbm.xml");
// 2.创建一个SessionFactory对象:类似于JDBC中连接池
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 3.通过SessionFactory获取到Session对象:类似于JDBC中Connection
Session session = sessionFactory.openSession();
// 4.手动开启事务:
Transaction transaction = session.beginTransaction();
// 5.编写代码
Customer customer = new Customer();
customer.setCust_name("王西");
session.save(customer);
// 6.事务提交
transaction.commit();
// 7.资源释放
session.close();
sessionFactory.close();
三、Hibernate常见配置
1.映射的配置
1) class标签的配置
标签用来建立类与表的映射关系。
属性:
name :类的全路径
table :表名(类名与表名一致,table可以省略)
catalog :数据库名
2) id标签的配置
标签用来建立类中的属性与表中的主键的对应关系。
属性:
name :类中的属性名
column :表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length :长度
type :类型
3) property标签的配置
标签用来建立类中的普通属性与表的字段的对应关系。
属性:
name :类中的属性名
column :表中的字段名
length :长度
type :类型
not-null :设置非空
unique :设置唯一
2.Hibernate的核心的配置
2.1 必须的配置
1) 连接数据库的基本的参数
①驱动类
②url路径
③用户名
④密码
2) 方言
2.2 可选的配置
1) 显示SQL:hibernate.show_sql
2) 格式化SQL:hibernate.format_sql
3) 自动建表:hibernate.hbm2ddl.auto
①none :不使用hibernate的自动建表。
②create :如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)
③create-drop:如果数据库中已经有表,删除原有表,执行操作,删除这个表。如果没有表,新建一个,使用完了删除该表。(测试)
④update :如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)。
⑤validate :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。
2.3 映射文件的引入
引入映射文件的位置
<mapping resource="com/jzfblog/hibernate/demo1/Customer.hbm.xml"/>
3.Hibernate的核心API
3.1 Hibernate配置对象—Configration
Configration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。
1) 加载核心配置文件
hibernate.properties
Configuration cfg = new Configuration();
2) hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
3) 加载映射文件
// 手动加载映射
configuration.addResource("com/jzfblog/hibernate/Customer.hbm.xml");
3.2 Session工厂—SessionFactory
充当数据存储源的代理,负责创建Session对象。通常情况下,一个项目只需要一个SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
配置连接池:(了解)
<!-- 配置C3P0连接池 --> <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!--在连接池中可用的数据库连接的最少数目 --> <property name="c3p0.min_size">5</property> <!--在连接池中所有数据库连接的最大数目 --> <property name="c3p0.max_size">20</property> <!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 --> <property name="c3p0.timeout">120</property> <!--每3000秒检查所有连接池中的空闲连接 以秒为单位--> <property name="c3p0.idle_test_period">3000</property>
抽取工具类
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static{
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session openSession(){
return sf.openSession();
}
public static Session getCurrentSession(){
return sf.getCurrentSession();
}
}
3.3 类似Connection连接对象—Session
Session代表的是Hibernate与数据库的链接对象。不是线程安全的。与数据库交互桥梁。
1) 保存方法:
Serializable save(Object obj);
// 保存客户
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王小西");
Serializable id = session.save(customer);
System.out.println(id);
tx.commit();
session.close();
}
2) 查询方法:
T get(Class c,Serializable id);
T load(Class c,Serializable id);
get方法和load方法的区别?
get方法:
采用的是立即加载,执行到这行代码的时候,就会马上发送SQL语句去查询。
查询后返回是真实对象本身。
查询一个找不到的对象的时候,返回null
load方法:
采用的是延迟加载(lazy懒加载),执行到这行代码的时候,不会发送SQL语句,当真正使用这个对象的时候才会发送SQL语句。
查询后返回的是代理对象。javassist-3.18.1-GA.jar 利用javassist技术产生的代理。
查询一个找不到的对象的时候,返回ObjectNotFoundException
// 查询:
public void demo2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 使用get方法查询
/*Customer customer = session.get(Customer.class, 100l); // 发送SQL语句
System.out.println(customer);*/
// 使用load方法查询
Customer customer = session.load(Customer.class, 200l);
System.out.println(customer);
tx.commit();
session.close();
}
3) 修改方法:
void update(Object obj);
// 修改操作
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 直接创建对象,进行修改
/*Customer customer = new Customer();
customer.setCust_id(1l);
customer.setCust_name("王聪");
session.update(customer);*/
// 先查询,再修改(推荐)
Customer customer = session.get(Customer.class, 1l);
customer.setCust_name("王小贱");
session.update(customer);
tx.commit();
session.close();
}
4) 删除方法:
void delete(Object obj);
// 删除操作
public void demo4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 直接创建对象,删除
/* Customer customer = new Customer();
customer.setCust_id(1l);
session.delete(customer);*/
// 先查询再删除(推荐)--级联删除
Customer customer = session.get(Customer.class, 2l);
session.delete(customer);
tx.commit();
session.close();
}
5) 保存或更新:
void saveOrUpdate(Object obj)
// 保存或更新
public void demo5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*Customer customer = new Customer();
customer.setCust_name("王凤");
session.saveOrUpdate(customer);*/
Customer customer = new Customer();
customer.setCust_id(3l);
customer.setCust_name("李如花");
session.saveOrUpdate(customer);
tx.commit();
session.close();
}
6) 查询所有:
// 查询所有
public void demo6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 接收HQL:Hibernate Query Language 面向对象的查询语言
/*Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}*/
// 接收SQL:
SQLQuery query = session.createSQLQuery("select * from cst_customer");
List<Objects[]> list = query.list();
for (Objects[] object : list) {
System.out.println(Arrays.toString(object));
}
tx.commit();
session.close();
}
四、持久化类的编写规则
1.什么是持久化?
1) 持久化
将内存中的一个对象持久化到数据库的过程,其中Hibernate框架正是持久化框架。
2) 持久化类
一个Java类与数据库的表建立了映射关系,那么该类在Hibernate中称为是持久化类。
2.编写规则?
①对持久化类提供一个无参数构造方法,原因:Hibernate底层需要使用反射生成实例。
②属性需要私有,对私有属性提供public的get和set方法,原因:Hibernate中获取,设置对象的值。
③对持久化类提供一个唯一标识OID与数据库主键对应,原因:数据库中通过主键确定是否是同一个记录。
④持久化类中属性尽量保证使用包装类类型,原因:基本数据类型默认是0,包装类类型默认值是null。
⑤持久化类不要用final进行修饰,原因:使得持久化类不能产生子类,从而不会产生代理对象,延迟加载策略就会失效。
五、主键生成策略
1.主键的分类
1) 自然主键
主键的本身就是表中的一个字段(实体中一个具体的属性)。
2) 代理主键
主键的本身不是表中必须的一个字段(不是实体中的某个具体的属性)。
2.生成策略
1) increment
Hibernate中提供的自动增长机制,适用short、int、long类型的主键,在单线程中使用。
2) identity
数据库底层的自动增长机制,适用short、int、long类型的主键。(支持Mysql,不支持Oracle)
3) sequence
采用序列的方式,适用short、int、long类型的主键。(支持Oracle、不支持Mysql)
4) uuid
适用于字符串类型的主键,使用Hibernate中的随机方式生成字符串主键。
5) native
本地策略,可以在identity和sequence之间自由切换。
6) assigned
Hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。
六、持久化类的三种状态
1.瞬时态
这种对象没有唯一标识OID,被session所管理。
2.持久态
这种对象有唯一标识OID,被session所管理。
3.脱管态
这种对象有唯一标识OID,没有被session管理。
// 测试三种状态
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer(); // 瞬时态对象:没有持久化标识OID,没有被session管理
customer.setCust_name("王小西");
Serializable id = session.save(customer); // 持久化对象:有持久化标识OID,被session管理
tx.commit();
session.close();
System.out.println(customer); // 脱管态对象:有持久化标识OID,没有被session管理
}
4.持久化对象的状态转换
1) 瞬时态转化到其他态
获取瞬时态:使用new关键词创建。
瞬时态转化为持久态:执行Session的save()或saveOrUpdate()方法。
瞬时态转化为脱管态:为瞬时态对象设置持久化标识OID。
2) 持久态转化到其他态
获取持久态:通过Hibernate中session的get、load、Query查询等方法从数据库中获得。
持久态转化为瞬时态:执行Session的delete方法。
持久态转化为脱管态:执行Session的evict()、close()或clear()方法。
3) 脱管态转化到其他态
获取脱管态:不能直接获得,需通过其他态进行转化。
脱管态转化到瞬时态:将脱管态对象的持久化标识OID设置为null。
脱管态转化为持久态:执行Session的update()、saveUpdate()或lock()方法。
七、Hibernate的一级缓存
1.什么是缓存?
是一种优化的方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。
2.Hibernate的缓存
一级缓存:称为是Session级别的缓存,一级缓存生命周期与Session一致(由Session中的一系列Java集合构成,自带不可卸载)。
二级缓存:是SessionFactory级别的缓存,需要配置缓存。
3.Hibernate中的事务管理
除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的核心配置文件中对事务进行配置。
<!-- 指定hibernate操作数据库时的隔离级别 #hibernate.connection.isolation 1|2|4|8 0001 1 读未提交 0010 2 读已提交 0100 4 可重复读 1000 8 串行化 --> <property name="hibernate.connection.isolation">4</property> <!-- 指定session与当前线程绑定 --> <property name="hibernate.current_session_context_class">thread</property>
八、Hibernate其他API
1.Query
1) 基本查询:
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list(); // 返回list结果
//query.uniqueResult();//接收唯一的查询结果
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
2) 别名查询
//别名查询
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 别名的查询
/*
* Query query = session.createQuery("from Customer c");
* List<Customer> list = query.list();
*/
Query query = session.createQuery("select c from Customer c");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
3) 排序查询
//排序查询
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序的查询
// 默认情况
// List<Customer> list = session.createQuery("from Customer order by cust_id").list();
// 设置降序排序 升序使用asc 降序使用desc
List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
4) 条件查询
按位置绑定
//条件查询
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//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();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
按名称邦定
//条件查询
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1> 书写HQL语句
String hql = " from Customer where cust_id = :cust_id "; // 查询所有Customer对象
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id", 1l);
//3> 根据查询对象获得查询结果
Customer c = (Customer) query.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
5) 投影查询
查询对象的某个或某些属性。
// 投影查询
public void demo6() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 投影查询
// 单个属性
/*
* List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
* for (Object object : list) {
* System.out.println(object);
* }
*/
// 多个属性:
/*
* List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
* for(Object[] objects : list) {
* System.out.println(Arrays.toString(objects)); }
*/
// 查询多个属性,但是我想封装到对象中。
List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
6) 分页查询
//分页查询
public void fun5(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//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();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
7) 分组统计查询
//分组统计查询
public void demo8() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 聚合函数的使用:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
// 分组统计:
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source").list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tx.commit();
}
8) 多表查询
//HQL的多表查询
public void demo9() {
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// SQL:SELECT * FROM cst_customer c INNER JOIN cst_linkman l ON c.cust_id = l.lkm_cust_id;
// HQL:内连接 from Customer c inner join c.linkMans
/*
* List<Object[]> list = session.createQuery("from Customer c inner join c.linkMans").list();
* for (Object[] objects : list) {
* System.out.println(Arrays.toString(objects));
* }
*/
// HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner join fetch c.linkMans
List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans").list();// 通知hibernate,将另一个对象的数据封装到该对象中
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
2.Criteria
1) 基本查询
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//查询所有的Customer对象
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
System.out.println(list);
//Customer c = (Customer) criteria.uniqueResult();
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
2) 排序查询
//排序查询
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
// 排序查询
Criteria criteria = session.createCriteria(Customer.class);
// criteria.addOrder(Order.asc("cust_id")); // 升序
criteria.addOrder(Order.desc("cust_id")); // 降序
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
3) 条件查询
//条件查询
//HQL语句中,不可能出现任何数据库相关的信息的
// > gt
// >= ge
// < lt
// <= le
// == eq
// != ne
// in in
// between and between
// like like
// is not null isNotNull
// is null isNull
// or or
// and and
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//添加查询参数 => 查询cust_id为1的Customer对象
criteria.add(Restrictions.eq("cust_id", 1l));
//执行查询获得结果
Customer c = (Customer) criteria.uniqueResult();
System.out.println(c);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
4) 分页查询
//分页查询
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置分页信息 limit ?,?
criteria.setFirstResult(1);
criteria.setMaxResults(2);
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
5) 查询总记录数
//查询总记录数
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//创建criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询的聚合函数 => 总行数
criteria.setProjection(Projections.rowCount());
//执行查询
Long count = (Long) criteria.uniqueResult();
System.out.println(count);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
6) 离线条件查询
脱离session使用
//离线条件查询
public void demo6(){
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.like("cust_name", "李%"));
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
3.SQLQuery
1) 基本查询
//基本查询
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//3 调用方法查询结果
List<Object[]> list = query.list();
//query.uniqueResult();
for(Object[] objs : list){
System.out.println(Arrays.toString(objs));
}
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
//基本查询
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//1 书写sql语句
String sql = "select * from cst_customer";
//2 创建sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//指定将结果集封装到哪个对象中
query.addEntity(Customer.class);
//3 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
2) 条件查询
//条件查询
public void fun3(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//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 调用方法查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
3) 分页查询
//分页查询
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 控制事务
Transaction tx = session.beginTransaction();
//3执行操作
//-------------------------------------------
//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();
System.out.println(list);
//-------------------------------------------
//4提交事务.关闭资源
tx.commit();
session.close();// 游离|托管 状态, 有id , 没有关联
}
九、Hibernate一对多关联映射
1.一的情况配置
1) 创建持久类(假如一个客户有多个联系人)
// 一个客户有多个联系人:客户中应该放有联系人的集合。
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
2) 客户的映射
<!-- 配置一对多的映射:放置的多的一方的集合 --> <!-- set标签 : * name :多的一方的对象集合的属性名称。 * cascade:级联 * inverse:放弃外键维护权。 --> <set name="linkMans" cascade="save-update" inverse="true"> <!-- key标签 * column:多的一方的外键的名称。 --> <key column="lkm_cust_id"/> <!-- one-to-many标签 * class :多的一方的类的全路径 --> <one-to-many class="com.jzfblog.hibernate.domain.LinkMan"/> </set>
2.多的情况配置
1) 创建持久类(一个联系人对应一个客户)
// 面向对象的ORM
private Customer customer;
2) 联系人的映射
<!-- 配置多对一的关系:放置的是一的一方的对象 -->
<!--
many-to-one标签
* name :一的一方的对象的属性名称。
* class :一的一方的类的全路径。
* column :在多的一方的表的外键的名称。
-->
<many-to-one name="customer" class="com.jzfblog.hibernate.domain.Customer" column="lkm_cust_id"/>
十、Hibernate一对多级联操作
1.什么叫做级联
级联指的是,操作一个对象的时候,是否会同时操作其关联的对象。
2.什么是级联的方向性
操作一的一方的时候,是否操作到多的一方。
操作多的一方的时候,是否操作到一的一方。
3.级联保存或更新
1) 保存客户
<!-- set标签 : * name :多的一方的对象集合的属性名称。 * cascade:级联 --> <set name="linkMans" cascade="save-update" inverse="true"> ... </set>
2) 保存联系人
<!-- many-to-one标签 * name :一的一方的对象的属性名称。 * class :一的一方的类的全路径。 * column :在多的一方的表的外键的名称。 --> <many-to-one name="customer" class="com.jzfblog.hibernate.domain.Customer" cascade="save-update" column="lkm_cust_id"/>
4.级联删除
删除一边的时候,同时将另一方的数据也一并删除。
<!-- set标签 : * name :多的一方的对象集合的属性名称。 * cascade:级联 --> <set name="linkMans" cascade="save-update, delete" inverse="true"> ... </set>
十一、Hibernate多对多关联映射
1.用户的配置(用户与角色多对多关系)
<!-- 建立与角色的多对多的映射关系 --> <!-- set标签 * name :对方的集合的属性名称。 * table :多对多的关系需要使用中间表,放的是中间表的名称。 --> <set name="roles" table="sys_user_role" cascade="save-update,delete" > <!-- key标签: * column :当前的对象对应中间表的外键的名称。 --> <key column="user_id"/> <!-- many-to-many标签: * class :对方的类的全路径 * column :对方的对象在中间表中的外键的名称。 --> <many-to-many class="com.jzfblog.hibernate.domain.Role" column="role_id"/> </set>
2.角色的配置(角色与用户多对多关系)
因为多对多的关系中,采用的是中间表查询,所以必须有一方放弃外键维护权,一般由被动的一方放弃。
<!-- 与用户的多对多的映射关系 -->
<!--
set标签
* name :对方的集合的属性名称。
* table :多对多的关系需要使用中间表,放的是中间表的名称。
-->
<set name="users" table="sys_user_role" cascade="save-update,delete" inverse="true">
<!--
key标签:
* column :当前的对象对应中间表的外键的名称。
-->
<key column="role_id"/>
<!--
many-to-many标签:
* class :对方的类的全路径
* column :对方的对象在中间表中的外键的名称。
-->
<many-to-many class="com.jzfblog.hibernate.domain.User" column="user_id"/>
</set>
十二、Hibernate的抓取策略(优化)
1.什么是延迟加载?
也可以说是懒加载,执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。
2.延迟加载的分类
1) 类级别的延迟加载
指的是通过load方法查询某个对象,是否采用延迟。(使懒加载失效:在class标签上配置的lazy属性或使用final修饰持久类)。
2) 关联级别的延迟
指的是在查询到某个对象的时候,查询其关联的对象,是否采用延迟加载。(使懒加载失效:在set或many-to-one标签上配置lazy属性)。
3.什么是抓取策略?
Hibernate的抓取策略是Hibernate提升性能的一种手段,可以在获取关联对象的时候,对发送的语句进行优化,往往需要与延迟加载配合使用。
4.set上的fetch和lazy
fetch:抓取策略,控制SQL语句格式
select :默认值,发送普通的select语句,查询关联对象
join :发送一条迫切左外连接查询关联对象
subselect :发送一条子查询查询其关联对象
lazy:延迟加载,控制查询关联对象的时候是否采用延迟
true :默认值,查询关联对象的时候,采用延迟加载
false :查询关联对象的时候,不采用延迟加载
extra :极其懒惰。
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
5.many-to-one上的fetch和lazy
fetch:抓取策略,控制SQL语句格式。
select :默认值,发送普通的select语句,查询关联对象。
join :发送一条迫切左外连接。
lazy:延迟加载,控制查询关联对象的时候是否采用延迟。
proxy :默认值,proxy具体的取值,取决于另一端的<class>上的lazy的值。
false :查询关联对象,不采用延迟。
no-proxy :(不会使用)
在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join。
6.批量抓取
同时查询多个对象的关联对象的时候,可以采用批量抓取进行优化。如果要实现批量抓取,可以通过配置batch-size来完成。