JavaEE三层结构
- web层:struts2框架
- service层:spring框架
- dao层:hibernate框架(对数据库进行crud操作)
MVC思想
- m:模型
- v:视图
- c:控制器
Hibernate概述
什么是框架
- 写程序,使用框架后,帮我们实现一部分功能,使用框架的好处,少写一部分代码实现功能
什么是hibernate框架(重点)
- hibernate框架应用在javaee三层结构中,dao层框架
- 在dao层里面做对数据库crud操作,使用hibernate实现crud操作,hibernate底层代码就是jdbc,hibernate对jdbc进行封装,使用hibernate好处,不需要写复杂jdbc代码,不需要写sql语句实现
- hibernate开源的轻量级框架
- hibernate版本——Hibernate5.x
ORM思想
- hibernate使用orm思想对数据库进行crud操作
- 在web阶段学习javabean,更正确的叫法,实体类
- orm:object——relational——mapping(对象关系映射)
- 让实体类和数据库表进行一一对应关系
让实体类首先和数据库表对应
让实体类属性和表里面的字段对应 - 不需要直接操作数据库表,而操作表对应实体类对象
- 让实体类和数据库表进行一一对应关系
Hibernate入门
搭建hibernate环境
1. 导入hibernate的Jar包
hibernate-release-5.2.12.Final\lib\required
(阳总给的有)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k19PVxSG-1592817931270)(https://raw.githubusercontent.com/GGMyfriends/IMG/master/TIM%E5%9B%BE%E7%89%8720180206111113.png)]
2. 创建实体类
public class User {
/*
* hibernate要求实体类有一个属性唯一的值
*/
private int uid;
private String username;
private String password;
private String address;
使用hibernate的时候,不需要自己手动创建表,hibernate帮把表创建
3. 配置实体类和数据库表一一对应关系(映射关系)
使用配置文件实现映射关系
- 创建xml格式的配置文件
- 映射配置文件名和位置没有固定要求
- 建议:在实体类所在的包里面创建,实体类名称.hbm.xml
- 配置是xml格式,在配置文件中首先引入xml约束
- 在hibernate里面引入的约束dtd约束——hibernate-mapping-3.0.dtd
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- 配置
<?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>
<!-- 1.配置类和表对应
class标签:
name属性:实体类全路径
table属性:数据库表名称
-->
<class name="entity.User" table="t_user">
<!-- 2.配置实体类id和表id对应
hibernate要求实体类有一个属性唯一值
hibernate要求表有字段作为唯一值
-->
<!-- id标签
name属性:实体类里面id属性名称
column属性:生成的表字段名称
-->
<id name="uid" column="uid">
<!-- 设置数据表id增长策略
native:生成表id值就是主键自动增长
-->
<generator class="native"></generator>
</id>
<!-- 配置其他的属性和表字段对应
name属性:实体类属性名称
column:生成表字段名称
-->
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
4. 创建hibernate的核心配置文件
- 核心配置文件格式xml,但是核心配置文件名称和位置固定的
- 位置:必须在src下面
- 名称:必须hibernate.cfg.xml
- 引入dtd约束
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
- hibernate操作过程中,只会加载核心配置文件,其他配置文件不会加载
第一部分:配置数据库信息
第二部分:配置Hibernate信息
第三部分: 把映射文件放到核心配置文件中
<?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>
<!-- 第一部分:配置数据库信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">789</property>
<!-- 第二部分:配置Hibernate信息 -->
<!-- 输出底层sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 输出底层sql语句格式化-->
<property name="hibernate.format_sql">true</property>
<!-- hibernate帮我们创建表,需要配置之后
update:如果已经有表,更新,如果没有,创建
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库方言
在mysql里面实现分页 关键字limit,只能使用mysql里面
在oracle数据库,实现分页rownum
让hibernate框架识别不同数据库的语句
-->
<property name="hibernate.dialect">org.hibernate.spatial.dialect.mysql.MySQLDialect</property>
<!-- 第三部分: 把映射文件放到核心配置文件中 必须的-->
<mapping resource="entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
实现添加操作
- 加载hibernate核心配置文件
- 创建SessionFactory对象
- 使用SessionFactory创建session对象
- 开启事务
- 写具体逻辑crud操作
- 提交事务
- 关闭资源
Hibernate配置文件详解
Hibernate映射配置文件
- 映射配置文件名称和位置没有固定要求
- 映射配置文件中,标签name属性值写实体类相关内容
- class标签name属性值实体类全路径
- id标签和property标签name属性值 实体类属性名称
- id标签和property标签,column属性可以省略的
- 不写值和name属性值一样
- property标签type属性,设置生成表字段的类型,自动对应
Hibernate核心配置文件
- 配置项位置要求
<hibernate-configuration>
<session-factory>
配置项
</session-factory>
</hibernate-configuration>
配置三部分要求
- 数据库部分必须
- hibernate部分可选的
- 映射文件必须的
核心配置文件名称和位置固定额度
- 位置:src下面
- 名称:hibernate.cfg.xml
Hibernate核心api
Configuration
//到src下面找到名称hibernate.cfg.xml配置文件,创建对象,把配置文件放到对象里面(加载核心配置文件)
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory
- 使用cofiguration对象创建sessionFactory对象
根据核心配置文件中,有数据库配置,有映射文件部分,到数据库里面根据映射关系把表创建
<property name="hibernate.hbm2ddl.auto">update</property>
创建sessionFactory过程中,这个过程特别耗资源
- 在hibernate操作中,建议一个项目一般创建一个sessionFactory对象
具体实现
- 写工具类,写静态代码块实现-静态代码块在类加载时候执行,执行一次
public class HibernateUtils {
static Configuration cfg = null;
static SessionFactory sessionFactory = null;
//静态代码块实现
static {
//加载核心配置文件
cfg = new Configuration();
cfg.configure();
sessionFactory = cfg.buildSessionFactory();
}
//提供方法返回sessionFactory
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}
Session(重点)
- session类似于jdbc中connection
- 调用session里面不同的方法实现crud操作
- 添加-save方法
- 修改-update方法
- 删除-delete方法
- 根据Id查询-get方法
- session对象单线程对象
- session对象不能共用,只能自己使用
Transaction
- 事务对象
//4. 开启事务
Transaction tx = session.beginTransaction();
- 事务提交和回滚方法
tx.commit();
tx.rollback();
- 事务概念
- 事务四个特性
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误
实体类的编写规则
- 实体类里面属性私有的
- 私有属性使用公开的set和get方法操作
- 要求实体类有属性作为唯一值(一般使用id值)
- 实体类属性建议不适用基本数据类型,使用基本数据类型对应的包装类
- 八个基本数据类型对应的包装类
int——Integer
char——Character
其他的都是首字母大写 如double——Double - 比如 表示学生的分数,假如int score;
比如学生得了0分,int score = 0;
如果表示学生没有参加考试,int score = 0;(不能准确表示学生是否参加考试)
解决:使用包装类,Integer score = 0,表示学生得了0分
表示学生没有参加考试,integer score = null
- 八个基本数据类型对应的包装类
Hibernate主键生成策略
- hibernate要求实体类里面有一个属性作为唯一值,对应表主键,主键可以有不同生成策略
- hibernate主键生成策略有很多的值
- 在class属性里面有很多值
- native:根据使用的数据库帮选择哪个值
- uuid:之前web阶段写代码生成uuid值,hibernate帮我们生成uuid值(当使用uuid作为生成策略时,实体类id必须是字符串类型)
添加操作
//添加功能
User user = new User();
user.setUsername("张三");
user.setPassword("666");
user.setAddress("中国");
//调用session的方法实现添加
session.save(user);
根据ID进行查询
//根据ID查询,调用session的get方法
//第一个参数:实体类的class
//第二个参数:id值
User user = session.get(User.class, 5);
修改操作
//先进行查询再修改
User user = session.get(User.class, 4);
user.setUsername("李焕朝");
session.update(user);
删除操作
User user = session.get(User.class, 4);
session.delete(user);
实体类对象的状态(概念)
- 实体类状态有三种
- 瞬时态:对象里面没有Id值,对象与session没有关联(添加操作的状态)
- 持久态:对象里面有Id值,对象与session有关联(查询出来的状态)
- 托管态:对象里面有Id值,对象与session没有关联
User user = new User();
user.setUid(6);
user.setUsername("张三");
user.setPassword("666");
user.setAddress("中国");
- 演示操作实体类对象的方法
saveOrUpdate方法:实现添加、修改
实体类对象状态是瞬时态,做添加操作;实体类对象状态是托管态或持久态,做修改操作
Hibernate的一级缓存
什么是缓存
- 数据存到数据库里面,数据库本身是文件系统,使用流方式操作文件效率并不是很高
- 把数据存到内存里面,不需要使用流的方式,可以直接读取内存中数据
- 把数据放到内存中,提高读取效率
Hibernate缓存
hibernate框架中提供很多优化方式,hibernate的缓存就是一个优化方式
hibernate缓存特点:
第一类 hibernate的一级缓存- hibernate的一级缓存默认打开的
- hibernate的一级缓存使用范围,是session范围,从session创建到session关闭范围
- hibernate的一级缓存中,存储数据必须持久态数据
第二类 hibernate的二级缓存
- 目前已经不适用了,替代技术redis
- 二级缓存默认不是打开的,需要配置
- 二级缓存的使用范围,是sessionFactory范围
验证一级缓存存在
- 验证方式
- 首先根据uid=1查询,返回对象
- 其次再根据uid=1查询,返回对象
Hibernate:
select
user0_.uid as uid1_0_0_,
user0_.username as username2_0_0_,
user0_.password as password3_0_0_,
user0_.address as address4_0_0_
from
t_user user0_
where
user0_.uid=?
User [uid=6, username=张三, password=666, address=中国]
29
User [uid=6, username=张三, password=666, address=中国]
0
第一步执行get方法之后,发送sql语句查询数据库
第二步执行get方法之后,没有发送sql语句,查询以及缓存内容
Hibernate事务代码规范写法
- 代码结构
try{
//开启事务
Transaction tx = session.beginTransaction();
//提交事务
tx.commit();
} catch(SQLException e) {
//回滚事务
tx.rollback();
} finally {
//关闭操作
session.close();
sessionFactory.close();
}
Hibernate绑定session
- session类似于jdbc的connection,之前web阶段学过threadLocal
- 帮我们实现与本地线程绑定session
- 获取与本地线程session
在hibernate核心配置文件中配置
<!-- 配置与本地线程绑定的session -->
<property name="hibernate.current_session_context_class">thread</property>
调用sessionFactory里面的方法得到
//提供返回与本地线程绑定的session的方法
public static Session getSessionObject() {
return sessionFactory.getCurrentSession();
}
- 获取与本地线程绑定的session时候,关闭session报错,不需要手动关闭了
Hibernate的api使用
Query对象
- 使用query对象,不需要写sql语句,但是写hql语句
- hql:hibernate query language,hibernate提供的查询语言,这个hql语句和普通sql语句很相似
- hql和sql语句的区别:
使用sql操作表和字段
使用hql操作实体类和属性
- 查询所有hql语句:
- from 实体类名称
- Query对象使用
- 创建Query对象
- 调用query对象里面的方法得到结果
//1.创建Query对象
//方法里面写sql语句
Query query = session.createQuery("from User");
//2.调用query对象里面的方法得到结果
List<User> list = query.list();
for(User user : list){
System.out.println(user);
}
Criteria对象
- 使用这个对象查询操作,但是使用这个对象的时候,不需要写语句,直接调用方法实现
- 实现过程
- 创建criteria对象
- 调用对象里面的方法
//1.创建criteria对象
Criteria criteria = session.createCriteria(User.class);
//2.调用方法得到的结果
List<User> list = criteria.list();
for(User user : list){
System.out.println(user);
}
SQLQuery对象
- 使用hibernate时候,调用底层sql实现
- 实现过程
- 创建对象
- 调用对象的方法得到结果
返回list集合每部分是数组
//1.创建SQLQuery对象
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
List<Object[]> list = sqlQuery.list();
for(Object[] objects : list){
System.out.println(Arrays.toString(objects));
}
返回list集合每部分是对象形式
tx = session.beginTransaction();
//1.创建SQLQuery对象
SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
sqlQuery = sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list();
for(User user : list){
System.out.println(user);
}
Hibernate的一对多操作(重点)
一对多映射配置
以客户和联系人为例: 客户是1,联系人是多
第一步 创建两个实体类,客户和联系人
第二步 让两个实体类之间互相表示
- 在客户实体类里面表示多个联系人(一个客户里面有多个联系人)
//在客户实体类里面表示多个联系人,一个客户有多个联系人
//hibernate要求使用集合表示多的数据,使用set集合
private Set<LinkMan> setLinkMan = new HashSet<LinkMan>();
public Set<LinkMan> getSetLinkMan() {
return setLinkMan;
}
public void setSetLinkMan(Set<LinkMan> setLinkMan) {
this.setLinkMan = setLinkMan;
}
- 在联系人实体类里面表示所属客户(一个联系人只能属于一个客户)
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
- 配置映射关系
在客户映射文件中,表示所有联系人——一个客户里面有多个联系人
<!-- 在客户映射文件中,表示所有联系人
使用set标签表示所有联系人
set标签里面有name属性:属性值写在客户实体类里面表示联系人的set集合名称
-->
<set name="setLinkMan">
<!-- 一对多的建表,有外键 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="entity.LinkMan"/>
</set>
在联系人实体类里面表示所属客户——一个联系人只能属于一个客户
<!-- 表示联系人所属客户
name属性:因为在联系人实体类使用customer对象表示,写customer名称
class属性:cusotmer全路径
column:外键的名称
-->
<many-to-one name="customer" class="entity.Customer" column="clid"></many-to-one>
- 创建核心配置文件
一对多级联操作
级联保存
添加了一个客户,为这个客户添加多个联系人
//添加一个客户,为这个客户添加一个联系人
//1 创建客户和联系人对象
Customer customer = new Customer();
customer.setCustName("洛阳电竞养老院");
customer.setCustLevel("vip1");
customer.setCustPhone("110");
customer.setCustMobile("999");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("lucy");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("911");
//2 在客户表示所有联系人,在联系人表示客户
//建立客户对象和联系人对象关系
//2.1 把联系人对象放到客户对象的set集合里面
customer.getSetLinkMan().add(linkMan);
//2.2 把客户对象放到联系人里面
linkMan.setCustomer(customer);
//提交事务
tx.commit();
简化写法
一般根据客户添加联系人
- 第一步 在客户映射文件中进行配置
在客户映射文件里面set标签进行配置
<set name="setLinkMan" cascade="save-update">
- 第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了
//添加一个客户,为这个客户添加一个联系人
//1 创建客户和联系人对象
Customer customer = new Customer();
customer.setCustName("洛阳电竞养老院");
customer.setCustLevel("vip1");
customer.setCustPhone("110");
customer.setCustMobile("999");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("lucy");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("911");
//2 把联系人放到客户里面
customer.getSetLinkMan().add(linkMan);
session.save(customer);
session.save(linkMan);
//提交事务
tx.commit();
级联删除
删除某一个客户,这个客户里面的所有联系人也删除
具体实现
- 第一步 在客户映射文件set标签,进行配置
使用属性cascade属性值 delete - 第二步 在代码中直接删除客户
根据id查询对象,调用session里面delete方法删除
//1 根据id查询客户对象
Customer customer = session.get(Customer.class, 2);
//2 调用方法删除
session.delete(customer);
执行过程
根据id查询客户
根据外键id值查询联系人
把联系人外键设置为null
删除联系人和客户
一对多修改操作
- 修改联系人所属客户
//1 根据id查询客户联系人对象,根据id查询客户对象,并设置持久态对象值
Customer customer = session.get(Customer.class, 2);
LinkMan linkMan = session.get(LinkMan.class, 1);
//把联系人放到客户里面
customer.getSetLinkMan().add(linkMan);
//把客户放到联系人里面
linkMan.setCustomer(customer);
- inverse属性
- 因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户一次外键,修改联系人时候也修改一次外键
- 解决方式:让其中一方不维护外键——一对多里面,让其中一方放弃维护
- 具体实现:在放弃关系维护映射文件中进行配置,在set标签上使用inverse属性
<!-- inverse属性默认值:false
false(不放弃关系维护)
true(放弃关系维护) -->
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
<!-- 一对多的建表,有外键 -->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="entity.LinkMan"/>
</set>
多对多映射配置
以用户和角色为例演示
第一步 创建实体类,用户和角色
第二步 让两个实体类之间相互表示
- 一个用户里面表示所有角色,使用set集合
- 一个角色有多个用户,使用set集合
第三步 配置映射关系
- 基本配置
- 配置多对多关系
第四步 在核心配置文件中引入映射文件
<!-- name:角色set集合名称
table:第三张表名称
-->
<set name="setRole" table="user_role">
<!-- key标签里面配置
配置当前映射文件在第三张表外键名称 -->
<key column="userid"></key>
<!-- class:角色实体类全路径
column:角色在第三张表外键名称
-->
<many-to-many class="Role" column="roleid"></many-to-many>
</set>
多对多映射配置
- 对象导航查询
根据id查询某个客户,再查询这个客户里面所有的联系人
- OID查询:调用session里面的get方法实现
根据id查询某一条记录,返回对象
- hql查询
创建Query对象,写hql语句
调用query对象里面的方法得到结果
//1 创建query对象
Query query = session.createQuery("from Customer c where c.cid=? and c.custName=?");
//2 设置条件值
//向?里面设置值
//setParameter方法两个参数
//第一个参数:位置,int类型是?位置,?的位置从0开始
//第二个参数:具体参数值
//设置第一个?的值
query.setParameter(0, 1);
//设置第二个?的值
query.setParameter(1, "洛阳电竞养老院");
//3 调用方法得到结果
List<Customer> list = query.list();
for(Customer customer : list) {
System.out.println(customer);
}
模糊查询
//1 创建query对象
Query query = session.createQuery("from Customer c where custName like ?");
//2 设置条件值
query.setParameter(0, "%af%");
分页查询
//1 创建query对象
Query query = session.createQuery("from User");
//2 设置分页数据
//2.1 设置开始位置
query.setFirstResult(0);
//2.2 设置每页显示的记录数
query.setMaxResults(3);
//3 调用方法得到结果
List<User> list = query.list();
for(User user : list) {
System.out.println(user);
}
投影查询
投影查询:查询的不是所有字段值,而是部分字段的值
投影查询hql语句写法:select 实体类属性名称1,实体类属性名称2 from 实体类名称
具体实现
//1 创建query对象
Query query = session.createQuery("select count(*) from Customer");
//2 调用方法得到结果
//query对象里面有方法,直接返回对象形式
Object obj = query.uniqueResult();
Long lo = (Long) obj;
int count = lo.intValue();
System.out.println(count);
多表查询
hql多表查询
内连接
//创建query对象
Query query = session.createQuery("from Customer c inner jion c.setLinkMan");
List list = query.list();
迫切内连接——迫切内连接和内连接底层实现是一样的,区别:使用内连接返回list中每部分是数组,迫切内连接返回list每部分是对象
左外连接
右外连接
迫切内连接
迫切左外连接
- QBC查询
使用hql查询需要写hql语句实现,但是使用qbc时候,不需要语句了,使用方法实现
使用qbc时候,操作实体类和属性
使用qbc时候,使用Criteria对象实现
查询所有
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 调用方法得到结果
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
条件查询
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 使用criteria对象里面的方法设置条件值
//首先使用add方法,表示设置条件值
//在add方法里面使用类的方法实现条件设置
criteria = criteria.add(Restrictions.eq("cid", 2));
Object obj = criteria.uniqueResult();
System.out.println(obj);
排序查询
//1 创建对象
Criteria criteria = session.createCriteria(User.class);
//2 设置对哪个属性进行排序,设置排序规则
criteria.addOrder(Order.desc("uid"));
List<User> list = criteria.list();
分页查询
//1 创建对象
Criteria criteria = session.createCriteria(User.class);
//2 设置分页数据
//2.1 设置开始位置
criteria.setFirstResult(0);
//2.2 每页显示记录数
criteria.setMaxResults(3);
统计查询
//1 创建对象
Criteria criteria = session.createCriteria(User.class);
//2 设置操作
criteria.setProjection(Projections.rowCount());
//3 调用方法得到结果
Object obj = criteria.uniqueResult();
Long lobj = (Long)obj;
int count = lobj.intValue();
离线查询
servlet调用service,service调用dao
- 在dao里面对数据库crud操作
- 在dao里面使用hibernate框架,使用hibernate框架的时候,调用session里面的方法实现功能
//1 创建对象
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);
//2 最终执行的时候才需要到session
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<User> list = criteria.list();
- 本地sql查询
SQLQuery对象,使用普通sql实现查询
Hibernate检索策略
- 立即查询:根据id查询,调用get方法,一调用get方法马上发送语句查询数据库
//根据cid=1客户
//执行get方法后,是否发送sql语句
//调用get方法马上发送sql语句查询数据库
Customer customer = session.get(Customer.class, 1);
- 延迟查询:根据id查询,还有load方法,调用load方法不会马上发送语句查询数据,只有得到对象里面的值时候才会发送语查询数据库
//调用load方法之后,不会马上发送sql语句(返回对象里面只有id)
//得到对象里面不是id的其他值时候才会发送语句
Customer customer = session.load(Customer.class, 1);
延迟查询分成两类
- 类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送语句
- 关联级别延迟:查询出某个客户,再查询这个客户所有联系人的过程是否需要延迟,这个过程就称为关联级别延迟
(是否需要延迟的判断依据:是否向数据库发送语句)
批量抓取
- 查询所有联系人,返回list集合,遍历list集合,得到每个客户,得到每个客户的所有联系人
//查询所有客户
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
//得到每个客户里面所有的联系人
for(Customer customer : list) {
System.out.println(customer);
//每个客户里面所有的联系人
Set<LinkMan> setLinkMan = customer.getSetLinkMan();
for(LinkMan linkman : setLinkMan) {
System.out.println(linkman);
}
}
- 在客户的映射文件中,set标签配置
batch-size值,值越大发送语句越少
<set name="setLinkMan" batch-size="10">