Criter查询(单表条件查询)
Ctiter是Hibernate无语句面向对象查询
- 条件查询
public void getVoid(){
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//====编写实体对象===============
/**
* 查询所有的查询对象
*/
Criteria createCriteria = session.createCriteria(User.class);
List<User> list = createCriteria.list();
System.out.println("list:"+list);
//查询单个对象
//User uniqueResult = (User)createCriteria.uniqueResult();
//===================
tx.commit();
session.close();
}
- 条件查询
/***
* Restrictions 条件参数的设置
* > --> gt
* >= --> ge
* < --> lt
* <= --> le
* == --> eq
* != --> ne
* in --> in
* between and --> between
* like --> like
* is not null --> isNotNull
* is null --> inNull
* or --> or
* and --> and
*/
//====编写实体对象===============
/**
* 查询所有的查询对象
*/
Criteria createCriteria = session.createCriteria(User.class);
//添加查询的参数
createCriteria.add(Restrictions.eq("id", 1l));
List list = createCriteria.list()
- 分页查询
/**
* 设置分页的信息
*/
Criteria createCriteria = session.createCriteria(User.class);
createCriteria.setFirstResult(1);//开始
createCriteria.setMaxResults(3);//多少条数据
List list = createCriteria.list();
- 设置查询聚合函数
* 设查询聚合行数==》总行数
*/
Criteria createCriteria = session.createCriteria(User.class);
//
createCriteria.setProjection(Projections.rowCount());
Long uniqueResult = (Long)createCriteria.uniqueResult();
- 排序查询
Criteria createCriteria = openSession.createCriteria(User.class);
createCriteria.addOrder(Order.desc("id"));
List<User> list = createCriteria.list();
for (User user : list) {
System.out.println(user);
}
- 离线查询对象
- 传统的离线查询
- 离线的Criteria查询
- 测试
public void getVoid04(){
//创建离线的查询
DetachedCriteria forClass = DetachedCriteria.forClass(User.class);
//拼装条件进行查询
forClass.add(Restrictions.idEq(3l));
//创建Session
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session openSession = sessionFactory.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//------------------
//进行组装session条件
Criteria executableCriteria = forClass.getExecutableCriteria(openSession);
List list = executableCriteria.list();
for (Object object : list) {
System.out.println(object);
}
//------------------
beginTransaction.commit();
openSession.close();
}
- 原生态SQL查询(复杂的业务的查询)
- 基本查询:
- 返回数据list
//===原生的SQL语句查询===============
String sql="select * from user";
//创建SQL的查询对象
SQLQuery createSQLQuery = session.createSQLQuery(sql);
List<Object[]> list = createSQLQuery.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
/* 查询单个
* createSQLQuery.uniqueResult();*/
//===================
-
- 返回对象list
//===原生的SQL语句查询===============
String sql="select * from user";
//创建SQL的查询对象
SQLQuery createSQLQuery = session.createSQLQuery(sql);
// 将结果集封装到结果对象中
createSQLQuery.addEntity(User.class);
//得到结果
List<User> list = createSQLQuery.list();
System.out.println(list);
- 条件查询
//===原生的SQL语句查询===============
String sql="select * from user where id =?";
//创建SQL的查询对象
SQLQuery createSQLQuery = session.createSQLQuery(sql);
//设置参数
createSQLQuery.setParameter(0,1l);
createSQLQuery.addEntity(User.class);
//得到结果
List<User> list = createSQLQuery.list();
System.out.println(list);
- 分页查询
//===原生的SQL语句查询===============
String sql="select * from user limit ?,?";
//创建SQL的查询对象
SQLQuery createSQLQuery = session.createSQLQuery(sql);
//设置参数
createSQLQuery.setParameter(0, 1);
createSQLQuery.setParameter(1, 3);
createSQLQuery.addEntity(User.class);
//得到结果
List<User> list = createSQLQuery.list();
- 一对多&多对一关系表达
- 数据库中的表的表达关系
- 实体类对象的表示
1.客户实体类
public class Customer {
private Long c_id;
private String c_name;
//使用Set集合表达一对多的关系
private Set<Orders> orders=new HashSet<Orders>();
//对应的get set 方法
}
2.订单实体类
public class Orders {
private Long o_id;
private String o_name;
//表达多对一的的关系
private Customer customer;
//对应的get set 方法
}
- ORM数据配置
- 主配置文件hibernate.cfg.cml要加入
<mapping resource="com/hibernate01/dem02/bean/Customer.hbm.xml" />
<mapping resource="com/hibernate01/dem02/bean/Orders.hbm.xml" />
- 一对多
<hibernate-mapping >
<class name="com.hibernate01.dem02.bean.Customer" >
<id name="c_id" column="c_id">
<generator class="native"></generator>
</id>
<property name="c_name" column="c_name" > </property>
<!--集合;一对多关系的配置 -->
<!--name 集合的属性名
cascade:级联操作如(保存客户时把客户的订单也同时保存)
save-update:级联保存更新
delete:级联删除
all:(save-update+delete)
级联操作:本质,就是简化操作
inverse:配置关联维护关系(反转)
true:当前配置的类不维护关系
false:默认值 当前配置类维护
关联维护本质:提高关系维护的性能
-->
<set name="orders" cascade="" inverse="" >
<!--column:对应的是外键关系 (必须一致)
-->
<key column="o_c_id" ></key>
<!--one-to-many 指向的一对多
class:与本类关联的对象完整类名
-->
<one-to-many class="com.hibernate01.dem02.bean.Orders" />
</set>
</class>
</hibernate-mapping>
- 多对一
<hibernate-mapping>
<class name="com.hibernate01.dem02.bean.Orders">
<id name="o_id" column="o_id">
<generator class="native" ></generator>
</id>
<property name="o_name" column="o_name" ></property>
<!-- 多对一的配置
name:配置对象的属性名
column:对应的是外键关系(必须一致)
class:与本类关联的对象完整类名
cascade:级联操作如(保存客户是把客户的订单也同时保存)
save-update:级联保存更新
delete:级联删除
all:(save-update+delete)
-->
<many-to-one cascade="" name="customer" column="o_c_id" class="com.hibernate01.dem02.bean.Customer" ></many-to-one>
</class>
</hibernate-mapping>
测试
- 保存 客户意见客户下的订单
**
* 多对一| 一对多
* 保存 客户意见客户下的订单
*/
@Test
public void getVoid(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//-------操作----------
Customer customer = new Customer();
customer.setC_name("小张");
Orders order = new Orders();
order.setO_name("西瓜");
Orders order1 = new Orders();
order1.setO_name("苹果");
/**
* 表示一对多,客户下有多个订单
*/
customer.getOrders().add(order);
customer.getOrders().add(order1);
/**
* 表示多对的多,订单属于那个客户
*/
order1.setCustomer(customer);
order.setCustomer(customer);
openSession.save(customer);
/*
* 如这两行代码不写,需要配置级联操作
* save-update:级联保存更新
* openSession.save(order);
openSession.save(order1);*/
//---------------------
beginTransaction.commit();
openSession.close();
}
- 只为客户添加订单
//-------操作----------
Customer customer = openSession.get(Customer.class, 1L);
Orders order = new Orders();
order.setO_name("葡萄");
Orders order1 = new Orders();
order1.setO_name("香蕉");
/**
* 表示一对多,客户下有多个订单
*/
customer.getOrders().add(order);
customer.getOrders().add(order1);
/**
* 表示多对的多,订单属于那个客户
*/
order1.setCustomer(customer);
order.setCustomer(customer);
openSession.save(order);
openSession.save(order1);
- 只为客户删除订单数据
Customer customer = openSession.get(Customer.class, 1L);
Orders orders = openSession.get(Orders.class, 1L);
customer.getOrders().remove(orders);
orders.setCustomer(null)
- 级联操作
- 多对一/一对多中的属性一样的配置
- 级联造作:本质,就是简化操作
多对一配置
Name:配置对象的属性名
Column:对应的是外建关系(必须一致)
Class:与本类关联的对象完整类名
Cascade:级联操作(保存客户时把客户的订单同时保存)
save-update:级联保存更新
delete:级联删除
all:(save-update+delete)
<many-to-one cascade="" name="customer" column="o_c_id" class="com.hibernate01.dem02.bean.Customer" ></many-to-one>
- 关系-维护
- 在没有进行关系维护是Sql语句执行多次操作
- 先执行添加在执行修改语句
- 早保存时,都会维护外键关系。关系维护两次
- 关系维护本质:提高关系维护性能
/**
* 多对一| 一对多
* 保存 客户意见客户下的订单
*/
@Test
public void getVoid(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//-------操作----------
Customer customer = new Customer();
customer.setC_name("小张");
Orders order = new Orders();
order.setO_name("西瓜");
Orders order1 = new Orders();
order1.setO_name("苹果");
/**
* 表示一对多,客户下有多个订单
* 如果客户放弃维护,代码可以不用写
*/
customer.getOrders().add(order);
customer.getOrders().add(order1);
/**
* 表示多对的多,订单属于那个客户
*/
order1.setCustomer(customer);
order.setCustomer(customer);
openSession.save(customer);
openSession.save(order);
openSession.save(order1);
//---------------------
openSession.close();
}
- 配置关系维护
- sql语句不会执行Update语句
- 在有外键的一方是不能放弃维护,只能有一的一方可以放弃维护
inverse:配置关联维护关系(反转)
true:当前配置的类不维护关系
false:默认值 当前配置类维护
<set name="orders" inverse="true" >
<!--column:对应的是外键关系 (必须一致)
-->
<key column="o_c_id" ></key>
<!--one-to-many 指向的一对多
class:与本类关联的对象完整类名
-->
<one-to-many class="com.hibernate01.dem02.bean.Orders" />
</set>
2.注意—放弃维护方
1.添加:
/**
* 表示一对多,客户下有多个订单
* 如果客户放弃维护,代码可以不用写
*/
customer.getOrders().add(order);
customer.getOrders().add(order1);
2.删除
/**
* 如:Customer设置了,不进行维护关系
* 在这里是不能删除的
* 如需要删除:
* 方式一: 开启 cascade="delete"
* 方式二: 开始维护 inverse="false"
* */
Customer customer = openSession.get(Customer.class, 1L);
openSession.delete(customer);
删除的配置
<set name="orders" inverse="true" cascade="delete" >
<!-- <set name="orders" inverse="false" > -->
<!--column:对应的是外键关系 (必须一致)
-->
<key column="o_c_id" ></key>
<!--one-to-many 指向的一对多
class:与本类关联的对象完整类名
-->
<one-to-many class="com.hibernate01.dem02.bean.Orders" />
</set>
- 多对多关系的表达
- 数据库表关系表达
- 实体类关系表达
- ORM映射文件的配置
多对多的表达关系
name:集合对应的属性名
table:中间表名
<set name="student" table="student_teacher">
<!--column:外键 指定别人<引用我>的ID名 -->
<key column="t_id"></key>
<!--class:指定那个类是多对多的关系
column:外键<我引用>别人的外键
-->
<many-to-many class="com.hibernate01.dem02.bean.Student" column="s_id"></many-to-many>
</set>
- 操作关联属性
- 维护关系
- 在多对多的是一定要配置维护关系
- Inverse属性:如果遇到多对多关系,一定要选择一方放弃维护关系
- 一般谁来放弃要看业务方向,有业务方维护业务方,非业务方放弃维护
1.1非业务方不进行保存
public void getVoid(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//-------操作----------
Teacher teacher = new Teacher();
teacher.setT_name("陈老师");
Teacher teacher1 = new Teacher();
teacher1.setT_name("张老师");
Student student = new Student();
student.setS_name("张三同学");
Student student2 = new Student();
student2.setS_name("张三同学");
/**
* 对象的关系设置
*/
//teacet的对应关系
/* 非业务方不进行保存
* teacher1.getStudent().add(student);
teacher1.getStudent().add(student2);
teacher.getStudent().add(student);
teacher.getStudent().add(student2);*/
//student的对应关系
student.getTeacher().add(teacher);
student.getTeacher().add(teacher1);
student2.getTeacher().add(teacher);
student2.getTeacher().add(teacher1);
/**
* 保存
*/
openSession.save(teacher);
openSession.save(teacher1);
openSession.save(student);
openSession.save(student2);
//---------------------
beginTransaction.commit();
openSession.close();
}
1.2.非业务方放弃维护关系
<!-- 使用inverse属性
true: 放弃维护外键关系
false(默认值):维护关系
结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
一般谁来放弃要看业务方向.
业务方向维护角色. 非业务方向不需要维护关系.放弃维护
-->
<set name="student" table="student_teacher" inverse="true">
<!--column:外键 指定别人<引用我>的ID名 -->
<key column="t_id"></key>
<!--class:指定那个类是多对多的关系
column:外键<我引用>别人的外键
-->
<many-to-many class="com.hibernate01.dem02.bean.Student" column="s_id"></many-to-many>
</set>
- 级联属性
- ascade=“save-update”配置了就少写openSession.save()代码
/**
* 给学生添加老师
*/
@Test
public void getVoid1(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//-------操作----------
//获取到学生
Student student = openSession.get(Student.class, 1l);
//创建老师
Teacher teacher = new Teacher();
teacher.setT_name("王老师");
//添加老师
student.getTeacher().add(teacher);
//将瞬时状态转换为持久状态
openSession.save(teacher);
//---------------------
beginTransaction.commit();
openSession.close();
}
<!--多对多的表达关系
name:集合对应的属性名
table:中间表名
cascade:级联操作如
save-update:级联保存更新
delete:级联删除(风险大特别是多对多的时,不建议使用)
all:(save-update+delete)
结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
-->
<set name="teacher" table="student_teacher" cascade="save-update">
<!--column:外键 指定别人<引用我>的ID名 -->
<key column="s_id"></key>
<!--class:指定那个类是多对多的关系
column:外键<我引用>别人的外键
-->
<many-to-many class="com.hibernate01.dem02.bean.Teacher" column="t_id"></many-to-many>
</set>
public void getVoid1(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
Student student = openSession.get(Student.class, 1l);
Teacher teacher = new Teacher();
teacher.setT_name("王老师");
student.getTeacher().add(teacher);
//---------------------
beginTransaction.commit();
openSession.close();
}
- 解除
/**
* 为学生,解除老师
*/
@Test
public void getVoid2(){
Session openSession = HibernateUtils.openSession();
Transaction beginTransaction = openSession.beginTransaction();
Student student = openSession.get(Student.class, 1l);
Teacher teacher = openSession.get(Teacher.class, 1l);
Teacher teacher2 = openSession.get(Teacher.class, 2l);
student.getTeacher().remove(teacher);
student.getTeacher().remove(teacher2);
//---------------------
beginTransaction.commit();
openSession.close();
}
- HQL多表语法详解
- 数据表||实体类
- 数据库表数据
- Orders
- Custoner
2.实体类
public class Orders {
private Long o_id;
private String o_name;
//表达多对一的的关系
private Customer customer;
//对应的 get set方法
}
public class Customer {
private Long c_id;
private String c_name;
//使用Set集合表达一对多的关系
private Set<Orders> orders=new HashSet<Orders>();
//对应的get set 方法
}
2.回顾原生SQL语句多表查询
1.交叉连接-笛卡尔乘积
Select * from 表名1,表名2
2.内连接
1.隐士连接
Select * from 表名1,表名2 where 表名1.id=表名2.id
2.显示内连接
Select * from 表名1 inner join 表名2 on 表名.id=表名2.id
- 外连接
- 左外连接
Select * from 表名1 left jion 表名2 表名2 on 表名.id=表名2.id
- 右连接
Select * from 表名1 right jion 表名2 表名2 on 表名.id=表名2.id
3.HSQL的多表查询
1.内连接
1.平常内连接:将连接的两端对象分别返回放置数组中
public void getVoid01(){
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session openSession = sessionFactory.openSession();
Transaction beginTransaction = openSession.beginTransaction();
//------------
String hql="from Customer c inner join c.orders";
Query createQuery = openSession.createQuery(hql);
List<Object[]> list = createQuery.list();
for (Object[] object : list) {
System.out.println(Arrays.toString(object));
}
//------------
beginTransaction.commit();
openSession.close();
}
- 迫切内连接:进行封装,返回一个对象
String hql="from Customer c inner join fetch c.orders";
Query createQuery = openSession.createQuery(hql);
List<Customer> list = createQuery.list();
for (Customer object : list) {
System.out.println(object);
}
- 左外连接
String hql="from Customer c left join c.orders";
Query createQuery = openSession.createQuery(hql);
List<Object[]> list = createQuery.list();
for (Object[] object : list) {
System.out.println(Arrays.toString(object));
}
- 右外连接
String hql="from Customer c right join c.orders";
Query createQuery = openSession.createQuery(hql);
List<Object[]> list = createQuery.list();
for (Object[] object : list) {
System.out.println(Arrays.toString(object));
}}
- 类级加载策略(赖加载|延迟加载)
- load(延迟加载)|| get(不同加载)
- 使用get方法进行查询:open.session()加载时立即查询则会打印SQL语句
Customer customer = openSession.get(Customer.class,1l);
System.out.println(customer);
2.使用load方法加载
1.(默认)是执行时,不发生SQL语句,返回一个对象,使用该对象时才执行SQL查询
2.延迟加载:只是获得对象没有使用不会查询,在使用的时候进行查询
Customer customer = openSession.load(Customer.class,1l);
System.out.println(customer);
2.1延迟加载策略
- 可以通过配置文件中的class元素上的lazy进行配置
- lazy:true加载时,不查询使用时候查询(默认)
- lazy:false:加载时立即查询
- get方法没有 延迟加载策略
<hibernate-mapping >
<class name="com.hibernate01.dem02.bean.Customer" lazy="true" >
</class>
</hibernate-mapping >
3.赖加载流程
3.1lazy=true
查询时,会返回一个代理对象,会在使用属性时,根据关联session查询数据库,加载数据
3.2 lazy=false(和get没区别,调用立即加载数据)
直接返回对象
3.3注意:使用懒加载时,调用数据加载数据必须保证session的开启
- 关联级别
- 集合关联策略
Customer customer = openSession.get(Customer.class,1l);
//关联级别
Set<Orders> orders = customer.getOrders();
1.0:加载的策略
<hibernate-mapping >
<class name="com.hibernate01.dem02.bean.Customer" lazy="true" >
<!--
lazy:延迟加载
|-true:(默认)延迟加载
|-false:立即加载
|-extra:极其懒惰
fetch:抓取策略.使用什么样的SQL语句加载集合数据
|-select:(默认)单表查询加载
|-join:使用多表查询加载集合
|-subselect:使用子查询加载集合
-->
<set name="orders" lazy="true" fetch="select">
<key column="o_c_id" ></key>
<one-to-many class="com.hibernate01.dem02.bean.Orders" />
</set>
</class>
</hibernate-mapping>
1.1:lazy=true && fetch=select(默认)
- 执行44行时(不执行查询集合)
- 执行47行使用时(加载集合数据)
1.2:lazy=false && fetch=select
执行44行时,还没有使用集合就会加载集合数据
1.3:lazy=extra && fetch=select
极其懒惰与懒加载基本一致,如获得集合的size,只查询集合的size
1.4:fetch=select
- 执行44行代码,则会使用多表查询出所有的数据,44行执行之后不会再执行SQL语句
- 当fetch=select时lazy无论是true|false|extra都失效,则都是立即加载
1.5:lazy=true && fetch=subselect
String Hsql="FROM Customer";
Query createQuery = openSession.createQuery(Hsql);
List<Customer> list = createQuery.list();
for (Customer customer : list) {
System.out.println(customer);
System.out.println(customer.getOrders().size());
System.out.println(customer.getOrders());
}
注意:执行45行代码则使用的子查询,与懒加载
1.6:lazy=false && fetch=subselect
- 执行到43行则执行2行sql查询
- 执行之后的查询则不会再执行sql语句
1.7;lazy=extra && fetch=subselect
- 极其懒惰与懒加载类型
2.属性关联策略
<hibernate-mapping>
<class name="com.hibernate01.dem02.bean.Orders">
<!--
lazy:延迟加载
|-false:立即加载
|-proxy:由该类属性类级别的加载策略 (lazy)进行决定
fetch:抓取策略.使用什么样的SQL语句加载数据
|-select:(默认)单表查询加载
|-join:使用多表查询加载集合
-->
<many-to-one lazy="proxy" fetch="join" name="customer" column="o_c_id" class="com.hibernate01.dem02.bean.Customer" ></many-to-one>
</class>
</hibernate-mapping>
2.0:加载策略
Orders orders = openSession.get(Orders.class, 1l);
Customer customer = orders.getCustomer();
System.out.println(customer);
2.1:fetch=jion
- lazy属性值无论是false|peoxy都会失效
- 在执行40行代码时,会执行多表查询,后面的不会执行sql语句
3.总结
1.为了提高fetch应当选择select:lazy应当选择true(使用默认值)
2.no-session(session关闭)
1.过大session的作用使用Filter拦截器进行扩展
4.使用批量加载
<hibernate-mapping >
<class name="com.hibernate01.dem02.bean.Customer" >
<!--batch-size:表示每次加载多少条数据-->
<set name="orders" batch-size="3">
<key column="o_c_id" ></key>
<one-to-many class="com.hibernate01.dem02.bean.Orders" />
</set>
</class>
</hibernate-mapping>
在执行44行代码时,不会执行多个sql语句