一,表与表之间关系:
1.一对多:多的表用一个外键存一的表的主键id。
2.多对多:新建第三张表,两个外键分别存两个多的表的主键id。
3.一对一
二,Hibernate一对多练习:
一对多映射配置(以客户和联系人,客户是一,联系人是多为例子):
1,创建两个实体类,客户和联系人
2,让两个实体类之间互相表示
(1)在客户实体类里面表示多个联系人(一个客户里面有多个联系人)
Customer.java:
package com.myHibernate.entity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
/**
* 客户实体类
* @author AUAS
*/
public class Customer {
/**
* Hibernate要求实体类要有一个属性是唯一的,类似与数据库表的主键
*/
private Integer id;
private String cusName;
private String cusPhone;
//在客户实体类里面表示多个联系人,一个客户有多个联系人
//hibernate要求使用集合表示多的数据,使用set集合
private Set<LinkUser> linkUser = new HashSet<LinkUser>();
public Set<LinkUser> getLinkUser() {
return linkUser;
}
public void setLinkUser(Set<LinkUser> linkUser) {
this.linkUser = linkUser;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCusName() {
return cusName;
}
public void setCusName(String cusName) {
this.cusName = cusName;
}
public String getCusPhone() {
return cusPhone;
}
}
(2)在联系人实体类里面表示所属客户(一个联系人只能属于一个客户)
LinkUser.java:
package com.myHibernate.entity;
import java.util.HashSet;
import java.util.Set;
/**
* 客户实体类
* @author AUAS
*/
public class LinkUser {
/**
* Hibernate要求实体类要有一个属性是唯一的,类似与数据库表的主键
*/
private Integer id;
private String linkName;
private String linkPhone;
//在联系人实体类里面表示所属客户,一个联系人只能属于一个客户
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLinkName() {
return linkName;
}
public void setLinkName(String linkName) {
this.linkName = linkName;
}
public String getLinkPhone() {
return linkPhone;
}
public void setLinkPhone(String linkPhone) {
this.linkPhone = linkPhone;
}
}
3,配置映射关系
(1)一般一个实体类对应一个映射文件
(2)把实体类最基本的配置完成
(3)在映射文件中,配置一对多关系
(3.1)在客户映射文件中,表示所有的联系人。
Costomer.hbm.xml:
<?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="com.myHibernate.entity.Customer" table="t_customer">
<!-- 2 配置实体类id和表id对应
hibernate要求实体类有一个属性唯一值
hibernate要求表有字段作为唯一值
-->
<!-- id标签
name属性:实体类里面id属性名称
column属性:生成的表字段名称
-->
<id name="id" column="id">
<!-- 设置数据库表id增长策略
native:生成表id值就是主键自动增长
-->
<generator class="native"></generator>
</id>
<!-- 配置其他属性和表字段对应
name属性:实体类属性名称
column属性:生成表字段名称
-->
<property name="cusName" column="cusName"></property>
<property name="cusPhone" column="cusPhone"></property>
<!-- 在客户映射文件中,表示所有联系人
使用set标签表示所有联系人
set标签里面有name属性:name属性值与客户实体类里面表示联系人的集合名称一样-->
<set name="linkUser">
<!-- 一对多建表,有外键
hibernate机制:双向维护外键,在一和多那一方都配置外键
column属性值:外键名称(即customer表存对应的LinkUser表的id)
-->
<key column="cusId"></key>
<!-- 客户所有的联系人,class里面写联系人实体类的全路径 -->
<one-to-many class="com.myHibernate.entity.LinkUser"></one-to-many>
</set>
</class>
</hibernate-mapping>
(3.2)在联系人映射文件中,表示所属客户
LinkUser.hbm.xml:
<?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="com.myHibernate.entity.LinkUser" table="t_link_user">
<!-- 2 配置实体类id和表id对应
hibernate要求实体类有一个属性唯一值
hibernate要求表有字段作为唯一值
-->
<!-- id标签
name属性:实体类里面id属性名称
column属性:生成的表字段名称
-->
<id name="id" column="id">
<!-- 设置数据库表id增长策略
native:生成表id值就是主键自动增长
-->
<generator class="native"></generator>
</id>
<!-- 配置其他属性和表字段对应
name属性:实体类属性名称
column属性:生成表字段名称
-->
<property name="linkName" column="linkName"></property>
<property name="linkPhone" column="linkPhone"></property>
<!-- 表示联系人所属客户
names属性:属性值与联系人LinkUser实体类表示客户的名称一致
class属性:customer实体类全路径
column属性:外键名称-->
<many-to-one name="customer" class="com.myHibernate.entity.Customer" column="cusId"></many-to-one>
</class>
</hibernate-mapping>
4.创建核心配置文件,把映射文件引入到核心配置文件中
hibernate.cfg.xml:
5.一对多级联保存:
三,HIbernate多对多操作:
多对多映射配置:
以用户和角色为例(一个用户可以有多个角色,一个角色可以有多个用户)
1.创建实体类,用户实体类和角色实体类
2.两个实体类之间互相表示
(1)一个用户里面有多个角色,使用set集合
(2)一个角色有多个用户,使用set集合
四,Hibernate查询方式:
1.对象导航查询:
(1)根据id查询某个客户,再查询这个客户里面所有联系人
2.OID查询:
(1)根据id查询某一条记录,返回对象
3.hql查询:
(1)Query对象,写hql语句实现查询
4.QBC查询:
(1)Criteria对象
5.本地sql查询:
(1)SQLQuery对象,使用普通sql实现查询
对象导航查询:
1.查询某个客户里面所有联系人过程,使用对象导航实现
package cn.itcast.hibernatetest;
import com.myHibernate.entity.Customer;
import com.myHibernate.entity.LinkUser;
import com.myHibernate.entity.User;
import com.myHibernate.utils.HibernateUtils;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;
import java.util.List;
import java.util.Set;
public class HibernateDemo {
@Test
public void testSelect() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
//提供返回与本地线程的session的方法
session = HibernateUtils.getSessionObject();
//开启事务
transaction = session.beginTransaction();
//演示对象导航查询
//查询cid=1客户,再查询这个客户的所有联系人
Customer customer = session.get(Customer.class,1);
//再查询这个客户里面所有联系人(直接得到客户里面联系人的set集合)
Set<LinkUser> linkUsers = customer.getLinkUser();
System.out.println(linkUsers.size());
//提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
transaction.rollback();
} finally {
//关闭操作
// session.close();
// sessionFactory.close();
}
}
}
OID查询:
1.根据id查询记录
(1)调用session里面的get方法实现
HQL查询:
1.hql:hibernate query language ,是hibernate提供的一种查询语言,hql语言喝普通sql很相似。
区别:普通sql操作数据库表喝字段;hql操作实体类和属性
2.常用的hql语句(使用hql查询操作时候,使用Query对象)
(1)查询所有数据( from 实体类名称)
(1.1)创建Query对象,写hql语句
(1.2)调用Query对象里面的方法得到结果
(2)条件查询
(2.1)hql条件查询语句写法:
from 实体类名称 where 实体类属性名称 = ? and 实体类属性名称 = ?
from 实体类名称 where 实体类属性名称 like ?
(3)排序查询
(3.1)hql排序语句写法
from 实体类名称 order by 实体类属性名称 asc / desc
(4)分页查询
(4.1)mysql实现分页(使用关键字limit实现)
(4.2)在hql中实现分页(在hql中的语句不能写limit。hibernate的Query对象封装两个方法实现分页操作)
(5)投影查询
(5.1)投影查询(即查表中的某个(某些)字段,不是查询所有字段
sql语句:
(5.2)投影查询的hql语句写法:
select 实体类属性名称1,实体类属性名称2 from 实体类名称
注意:hql语句的select 后面不能像sql语句一下写 * 查所有。
(6)聚集函数使用
(6.1)常用的聚集函数(count ,sum, avg ,max ,min)
(6.2)hql聚集函数的写法
package cn.itcast.hibernatetest;
import com.myHibernate.entity.Customer;
import com.myHibernate.entity.LinkUser;
import com.myHibernate.entity.User;
import com.myHibernate.utils.HibernateUtils;
import org.hibernate.*;
import org.junit.Test;
import java.util.List;
import java.util.Set;
public class HibernateDemo {
@Test
public void testSelect() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
//提供返回与本地线程的session的方法
session = HibernateUtils.getSessionObject();
//开启事务
transaction = session.beginTransaction();
//演示hql 条件查询
//创建Query对象
// Query query = session.createQuery("FROM Customer As c Where c.cusName like ?");
// //设置条件值,向?里面设置值
// //setParameter方法两个参数(第一个参数:int类型是?位置,?位置从0开始。第二个参数:具体参数值)
// query.setParameter(0,"%小%");//设置第一个问号的值为2
// //调用方法得到结果
// List<Customer> customerList = query.list();
// for (Customer customer : customerList) {
// System.out.println(customer.getCusName()+":"+customer.getCusPhone());
// }
// //演示hql 排序查询
// //创建Query对象
// Query query = session.createQuery("FROM Customer ORDER BY id DESC");
// //设置条件值,向?里面设置值
// //调用方法得到结果
// List<Customer> customerList = query.list();
// for (Customer customer : customerList) {
// System.out.println(customer.getCusName()+":"+customer.getCusPhone());
// }
// //演示分页查询
// //创建Query对象
// Query query = session.createQuery("FROM Customer");
// //设置分页数据
// query.setFirstResult(0); //设置分页开始位置
// query.setMaxResults(2); //设置每页记录数
// //调用方法得到结果
// List<Customer> customerList = query.list();
// for (Customer customer : customerList) {
// System.out.println(customer.getCusName()+":"+customer.getCusPhone());
// }
// //演示投影查询
// //创建Query对象
// Query query = session.createQuery("SELECT cusName FROM Customer");
// //调用方法得到结果
// List<Object> cusNameList = query.list();
// for (Object cusName: cusNameList) {
// System.out.println(cusName);
// }
//演示聚集函数
//创建Query对象
Query query = session.createQuery("SELECT COUNT(*) FROM Customer");
//调用方法得到结果
//query对象里面有方法,直接返回对象形式
Object number = query.uniqueResult();
//放回int类型
//首先吧Object变成long类型,再变成int类型
Long longNumber = (Long)number;
int count = longNumber.intValue();
System.out.println(count);
//提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
transaction.rollback();
} finally {
//关闭操作
// session.close();
// sessionFactory.close();
}
}
}
QBC查询:
1.使用hql查询需要写hql语句实现,但是使用qbc时候,不需要写语句了,使用方法实现。
2.使用qbc时候,操作实体类和属性。
3.使用qbc,使用Criteria对象实现
(1)查询所有:
(1.1)创建Criteria对象(session.createCriteria(Customer.class))
(1.2)调用方法得到结果
(2) 条件查询:
没有语句,使用封装的方法实现(criteria.add(Restrictions.eq(“id”,2));)
(3)排序查询:
(4) 分页查询
开始位置计算公式:(当前页-1)* 每页记录数
(5)统计查询:
(6)离线查询:
(6.1)servlet调用service,service调用dao
(6.11)在dao里面对数据库crud操作
(6.12)在dao里面使用hibernate框架,使用hibernate框架时候,调用session里面的方法实现功能
HQL多表查询:
mysql里面多表查询:
1.HQL内连接查询:
(1)内连接查询hql语句写法 from Customer c inner join c.linkUser
返回list,list里面每部分是数组形式
(2)迫切内连接
(2.1)迫切内连接和内连接底层实现是一样的
(2.2)区别:使用内连接返回list中每部分是数组,迫切内连接返回list每部分是对象
(2.3)hql语句写法 from Customer c inner join fetch c.linkUser
返回list,list里面每部分是对象形式
2.HQL左外连接查询:
(1)左外连接hql语句: from Customer c left outer join c.linkUser
(2)迫切左外连接hql语句: from Customer c left outer join fetch c.linkUser
注意:左外连接返回list中每部分是数组,迫切左外连接返回list每部分是对象
3.右外连接hql语句:
from CUstomer c right outer join c.linkUser
HIbernate检索策略:
检索策略的概念:
1.hibernate检索策略分为两类:
(1)立即查询:根据id查询,调用get方法,一调用get方法马上发送语句查询数据库
(2)延迟查询:根据id查询,还有load方法,调用load方法不会马上发送语句查询数据,只有得到对象里面的值的时候才会发送语句查询数据库。
@Test
public void testSelect1() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
//提供返回与本地线程的session的方法
session = HibernateUtils.getSessionObject();
//开启事务
transaction = session.beginTransaction();
// //1.演示hibernate检索策略(立即查询)
// //查询id=1的客户信息(执行get方法之后,是否发送sql语句)
// //调用get方法马上发送sql语句查询数据库
// Customer customer = session.get(Customer.class,1);
// System.out.println(customer.getId());
//2.演示hibernate检索策略(延迟查询)
//查询id=1的客户信息(执行loda方法之后,是否发送sql语句)
//调用load方法不会马上发送sql语句查询数据库
//返回对象里面只有id值
//得到对象里面不是id的其它值时候才会发送语句
Customer customer = session.load(Customer.class,2);
System.out.println(customer.getId());
System.out.println(customer.getCusName());
//提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
transaction.rollback();
} finally {
//关闭操作
// session.close();
// sessionFactory.close();
}
}
延迟查询分成两类:
(1)类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送语句
(2)关联级别延迟:查询某个客户,再查询客户的所有联系人,查询客户的所有联系人的过程是否需要延迟,这个过程成为关联级别延迟。
关联级别延迟操作:
1.在映射文件中进行配置实现(根据客户得到所有的联系人,在客户映射文件中配置)
2.在set标签上使用属性(具体如下)
立即查询配置如下:
及其懒惰(需要什么查什么),延迟检索配置如下:
批量抓取:
1.查询所有客户,返回list集合,遍历list集合,得到每个客户,得到每个客户的所有联系人。
方法一:会查询多次数据库,性能不好
方法二:配置了批量抓取,性能好