Hibernate框架介绍
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
从度娘的介绍,我们可以看出:Hibernate是对JDBC进行封装的一个轻量级的框架,底层是使用JDBC来对数据库表进行交互操作。也就是说,我们可以使用Hibernate来完成原来JDBC与数据库表的交互操作。Hibernate是在Dao层使用的框架。
Hibernate的核心接口一共有6个,分别为:Session、SessionFactory、Transaction、Query、Criteria和Configuration。
ORM介绍
对象关系映射(Object-Relational Mapping)提供了概念性的、易于理解的模型化数据的方法。ORM方法论基于三个核心原则: 简单:以最基本的形式建模数据。 传达性:数据库结构被任何人都能理解的语言文档化。 精确性:基于数据模型创建正确标准化的结构。 典型地,建模者通过收集来自那些熟悉应用程序但不熟练的数据建模者的人的信息开发信息模型。建模者必须能够用非技术企业专家可以理解的术语在概念层次上与数据结构进行通讯。建模者也必须能以简单的单元分析信息,对样本数据进行处理。ORM专门被设计为改进这种联系。
简单说:ORM是对象与数据库表的映射,是对象的属性与数据表的字段的映射。
Hibernate基础入门
一、Hibernate简单了解
1、持久化对象和标识符
(1)持久化类:配置完关系后,操作的实体对应的类,成为持久化类 (Customer)
(2)持久化类标识符(oid:object id)
(3)持久化类主键的生成策略
<id name="cust_id">
<generator class="native"></generator>
</id>
generator的class属性的取值:
数据库底层生成主键:
identity:底层以自增的方式生成主键 例如mysql
sequence:底层以序列方式生成主键 例如oracle
native:根据数据库底层的主键生成策略自动选用identity还是sequence (使用最多)
hibernate生成主键:
increment:自增
uuid:生成不重复的字符串
手动指定主键:
assigned
代理主键:没有实际业务意义的字段
自然主键:可以具备主键的要求(唯一不空) 与此同时还具备业务意义(身份证、手机号、学号....)
2.hibernate持久化对象的三种状态和一级缓存
(1)持久化对象的三种状态(了解)
瞬时态:实体没有oid 也与session没有关联
持久态:实体有oid 与session有关联 (重点),持久态对象具备自动发送sql的能力
脱管态:实体有oid 与session失去关联
代码演示:
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer(); //瞬时态
customer.setCust_name("jd"); //瞬时态
System.out.println(customer); //瞬时态
session.save(customer); //执行完毕后 持久态
System.out.println(customer); //持久态
transaction.commit(); //持久态
session.close(); //脱管态
System.out.println(customer); //脱管态
(2)hibernate的一级缓存(重点)
hibernate存在两级缓存:
一级缓存:hibernate的内置缓存,session级别的缓存
二级缓存:hibernate的外置缓存,sessionFactory级别缓存(不学) redis
验证一级缓存是存在的?
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//查询对象
Customer customer = session.get(Customer.class, 4L);//发送sql查询数据 封装Customer 将customer缓存在session中
Customer customer2 = session.get(Customer.class, 4L);//从session获取4号customer
System.out.println(customer);
System.out.println(customer2);
transaction.commit();
session.close();
3.事务
(1)事务的特性ACID
原子性:事务是数据库操作最小单位 不可再分割
一致性:同时成功或同时失败
隔离性:多个事务互不影响的
持久性:当事务提交 数据就会被持久化到磁盘上
(2)并发操作出现的问题
脏读:A事务读取到B事务尚未提交的数据(最不安全的 开发中必须要避免的)
不可重复读:一个事务中多次读取数据的内容不一致
虚读/幻读:一个事务中多次读取数据的条数不一致
(3)设置数据库的隔离级别(isolation)解决并发问题
read uncommitted: 都不能解决 没人用
read committed:解决脏读 oracle的默认隔离级别
repeatabel read:解决不可重复读和脏读 mysql的默认隔离级别
serializable:都能解决 性能很低
(4)hibernate与事务相关的配置
1)session与线程绑定
作用:业务层使用session控制事务 dao层使用同一个session进行实体操作
<property name="hibernate.current_session_context_class">thread</property>
2)hibernate可以配置隔离级别
<property name="hibernate.connection.isolation">1/2/4/8</property>
read uncommitted: 1
read committed:2
repeatabel read:4
serializable:8
4.ibernate的查询操作(5种查询方式)
1、oid方式 --- get/load方法
2、对象导航方式
3、HQL方式(Hibernate Query Language) --- 面向对象+结构化查询 (重点)
4、QBC方式(Query By Criteria) --- 完全面向对象的(api)
5、SQL方式 --- 通过sql语句查询
二、Hibernate快速入门五部曲:
1.搭建环境(导入Hibernate的jar包)
(1)Hibernate必须的包:
(2)日志记录包:
(3)驱动包:
(4)Hibernate配置文件(项目可以不需要这个配置文件)
我一般会将配置文件放到src下
2.创建实体类和数据库表(cst_customer为例,需要生产get、set方法)
实体类结构:
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;//移动电话
数据库表:
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=15 DEFAULT CHARSET=utf8;
3.编写映射配置文件(配置实体与表的关系)
<?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>
<!-- 配置实体与表的关系
name: 要映射的实体的全限定名
table: 要映射的表的名称
-->
<class name="com.itheima.domain.Customer" table="cst_customer">
<!-- 配置实体的属性和表的字段的关系
在hibenrate中id具备特殊地位 修改、删除等默认都是根据id执行的
id标签
name:实体中的id的属性名称
column:表中的id的字段名称
主语:不管是id还是普通属性 当实体的属性名称 与 表的字段名称 一致时 此时column可以省略
-->
<id name="cust_id" column="cust_id">
<generator class="native"></generator>
</id>
<!-- 配置普通属性
name:实体中的属性名称
column:表中的字段名称
-->
<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_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
</class>
</hibernate-mapping>
4.编写主配置文件(配置数据源的信息)
<?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工厂:造session对象
session对象:会话对象 hibernate与数据库的连接对象
session工厂内部需要配置三部分内容
1、数据源信息
2、hibernate其他配置参数
3、加载映射关系
-->
<session-factory>
<!--数据源信息:JDBC连接数据库的四个基本配置参数-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
hibernate的其他配置参数:我一般配置四个参数
(方言、控制台显示SQL语句、格式化显示SQL语句、ddl策略)
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--加载映射-->
<mapping resource="com/itheima/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
5.测试(操作实体类)
public class HibernateTest {
@Test
public void test(){
//通过工具类获得session工厂
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//操作实体类
Customer customer = new Customer();
customer.setCust_name("阿里巴巴");
//保存
session.save(customer);
//提交
transaction.commit();
//释放资源
HibernateUtils.close(session);
}
}
在这里,我将获得session工厂的操作提取成一个简单的工具类:
public class HibernateUtils {
private static Configuration configuration = null;
private static SessionFactory sessionFactory = null;
static {
//创建配置对象,加载路径下(src)hibernate.cfg.xml文件
configuration = new Configuration().configure();
//通过配置对象 去构建session工厂(session工厂的创建下需要使用到hibernate的核心配置文件)
sessionFactory = configuration.buildSessionFactory();
}
public static Session openSession(){
//通过sesson工厂开启一个新的session
return sessionFactory.openSession();
}
public static void close(Session session){
if(session!=null){
session.close();
}
}
}
三、Hibernate常见查询操作
1、oid方式 --- get/load方法(get/load方法一样)
public class HibernateTest {
@Test
public void test(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 1L);
Customer customer2 = session.get(Customer.class, 4L);
System.out.println(customer);
System.out.println(customer2);
transaction.commit();
HibernateUtils.close(session);
}
}
2、对象导航方式(一对多为例)
public class OneToManyTest {
@Test
//测试对象导航查询
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Linkman linkman = session.get(Linkman.class, 1L);
System.out.println(linkman.getLkm_name());
Customer customer = linkman.getCustomer();
System.out.println(customer.getCust_name());
transaction.commit();
session.close();
}
@Test
//测试对象导航查询
public void test2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 1L);
System.out.println(customer.getCust_name());
//查询与该customer相关的linkman
Set<Linkman> linkmans = customer.getLinkmans();
for(Linkman man : linkmans){
System.out.println(man.getLkm_name());
}
transaction.commit();
session.close();
}
}
3、HQL方式(Hibernate Query Language) --- 面向对象+结构化查询 (重点)
public class HQLHibernate {
//排序查询
@Test
public void test07(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//Query代表面向对象的hibernate操作,createQuery创建查询对象
Query query = session.createQuery("FROM Customer ORDER BY cust_name DESC");
List<Object> list = query.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//分页查询
@Test
public void test06(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("FROM Customer");
query.setFirstResult(0);//起始索引
query.setMaxResults(3);//最大索引
List<Object> list = query.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//分组查询
@Test
public void test05(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//Query query = session.createQuery("FROM Customer group by cust_name");
Query query = session.createQuery("FROM Customer");
List<Object> list = query.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//统计查询(聚合查询)
@Test
public void test04(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("SELECT MAX(cust_id) FROM Customer");
List<Object> list = query.list();
for(Object object : list){
System.out.println(object);
}
transaction.commit();
HibernateUtils.close(session);
}
//条件查询
@Test
public void test03(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("FROM Customer where cust_name=?");
query.setString(0,"阿里巴巴");
List<Object> list = query.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//投影查询(查询部分字段)
@Test
public void test02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("SELECT new Map(cust_id,cust_name) FROM Customer");
List<Map<String,Object>> list = query.list();
for(Map<String,Object> map : list){
System.out.println(map);
}
/*Query query = session.createQuery("SELECT new Customer(cust_id,cust_name) FROM Customer");
List<Customer> list = query.list();
for(Customer customer : list){
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}*/
/* //Query query = session.createQuery("SELECT cust_name FROM Customer");
Query query = session.createQuery("SELECT cust_id,cust_name FROM Customer");
//List<Object> list = query.list();
List<Object[]> list = query.list();
for(Object[] objects : list){
System.out.println(Arrays.asList(objects));
}*/
transaction.commit();
HibernateUtils.close(session);
}
//基本查询(查询全部字段)
@Test
public void test01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("FROM Customer");
List<Customer> list = query.list();
for(Customer customer : list){
System.out.println(customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
}
4、QBC方式(Query By Criteria) --- 完全面向对象的(api)
QBC方式也叫Criteria 查询:
public class QBCHibernate {
//离线查询
@Test
public void test06(){
//在service/web层凭空创建Criteria对象
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//拼装sql查询条件
detachedCriteria.setProjection(Projections.property("cust_name"));
detachedCriteria.add(Restrictions.gt("cust_id",3L));
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得可被执行的criteria,把离线变成在线
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List<Object> list = criteria.list();
for(Object object : list){
System.out.println(object);
}
transaction.commit();
HibernateUtils.close(session);
}
//聚合查询
@Test
public void test05(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
criteria.setProjection(Projections.avg("cust_id"));
Object o = criteria.uniqueResult();
System.out.println(o);
transaction.commit();
HibernateUtils.close(session);
}
//分页查询
@Test
public void test04(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(0);
criteria.setMaxResults(3);
List<Object> list = criteria.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//条件查询
@Test
public void test03(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cust_name","%阿里%"));
List<Object> list = criteria.list();
for(Object object : list){
Customer customer = (Customer) object;
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
//查询部分字段(投影)
@Test
public void test02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
criteria.setProjection(Projections.property("cust_name"));
List<Object> list = criteria.list();
for(Object object : list){
System.out.println(object);
}
transaction.commit();
HibernateUtils.close(session);
}
//查询全部字段
@Test
public void test01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for(Customer customer : list){
System.out.println(customer.getCust_id()+" "+customer.getCust_name());
}
transaction.commit();
HibernateUtils.close(session);
}
}
5、SQL方式 --- 通过sql语句查询
一直没用过SQL方式,SQL方式参考这篇文章:
Hibernate SQLQuery原生sql查询https://blog.csdn.net/hjiacheng/article/details/53717727
四、查询操作的方法说明:
1、Query中的方法说明:
(1)list方法:该方法用于查询语句,返回的结果是一个list集合。
(2)uniqueResult方法:该方法用于查询,返回的结果是一个 Object对象。
(3)setter方法: Query接口中提供了一系列的 setter方法用于设置查询语句中的参数,针对不同的数据类型,需要用到不同的 setter方法。
(4)uniqueResult()方法:该方法用于返回唯的结果,在确保只有一条记录的查询时可以使用该方法。
(5)setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
(5)setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与 setFirstResult方法结合使用,用于限制结果集的范围,以实现分页功能。
2、Criteria中的方法说明:
五、Hibernate中的多表查询
1、多表设计(总结)
(1)多表关系
1)一对一:
表的设计原则(分表原则):
优化表的性能
基于语意化分表
一对一的两张表 之间的关系怎么维护?
主外键
相同主键值
2)一对多:
建表原则:
在一的一方有主键 主表
多的一方有与主表的主键相关联外键 从表
3)多对多
建表原则:
两种主表(业务表) 中间存在一张中间表
中间表内部维护两个外键
中间表分为两种:
仅仅维护关系的中间表
不仅存在维护关系的外键 还有其他业务字段 例如:订单表 订单项表 商品表
(2)多表设计
1)根据业务设计表模型
2)分析表的关系: 分方向 看一条(起始表)
3)一对一设计:
学生表 学籍表
4)一对多设计:
客户表 联系人表
百度 张三
jd 李四
google 王武
赵六
田七
孙八
5)多对多设计(权限5张表):
1、通过用户名和密码才能登陆
2、系统有不同的职务
3、不同的职务可以有不同的权限
用户表 职务表(角色表) 权限表(菜单表、功能表)
张三 CEO 查下自己薪资
李四 CTO 查看全部人薪资
王武 CFO 请假
田七 COO 批假
程序员 查看项目进度
查看项目金额
用户角色关系表 角色权限关系表
1、Hibernate一对多的操作
实体类结构:
//客户表:
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;//移动电话
private Set<Linkman> linkmanSet = new HashSet<Linkman>();//多的一方集合
//联系人表
private long lkm_id;//'联系人编号(主键)',
private String lkm_name;// '联系人姓名',
private String lkm_gender;//'联系人性别',
private String lkm_phone;//'联系人办公电话',
private String lkm_mobile;//'联系人手机',
private String lkm_email;// '联系人邮箱',
private String lkm_qq;//'联系人qq',
private String lkm_position;// '联系人职位',
private String lkm_memo;//'联系人备注',
//lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
private Customer customer;//一的一方对象
配置映射关系:
<!--客户表关系映射-->
<hibernate-mapping>
<class name="com.itheima.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<generator class="native"></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_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!--
配置一对多 一个Customer 对应多个 联系人
private Set<Linkman> linkmans = new HashSet<>();
Set标签name属性:Set集合的名称 (当前实体使用哪个变量与对方维护关系)
key标签的column:外键的名称
one-to-many标签的class:对方的全限定名
级联保存:在保存一方时 于此同时保存与该方有关系的其他对象
cascade="save-update"
级联删除:在删除一方时 于此同时删除与该方有关系的另一方
cascade="delete"
放弃外键维护权
inverse="true"
inverse直译:反转(反转外键维护权) 该方放弃外键维护权
查询:延迟加载 lazy="true/false"
查询一的一方 多的一方默认是延迟加载
结论:
在开发中 习惯在一的一方配置级联操作(cascade) 在一的一方配置放弃外键维护权
-->
<set name="linkmanSet" cascade="save-update,delete" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="com.itheima.domain.Linkman"></one-to-many>
</set>
</class>
</hibernate-mapping>
<!--联系人表关系映射-->
<hibernate-mapping>
<class table="cst_linkman" name="com.itheima.domain.Linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<property name="lkm_memo" column="lkm_memo"></property>
<!--
配置多对一
private Customer customer;
name:当前实体使用哪个变量与对方维护关系
class:对方的全限定
column:外键名称
-->
<many-to-one name="customer" column="lkm_cust_id" class="com.itheima.domain.Customer"></many-to-one>
</class>
</hibernate-mapping>
配置核心参数:
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="com/itheima/domain/Customer.hbm.xml"/>
<mapping resource="com/itheima/domain/Linkman.hbm.xml"/>
</session-factory>
</hibernate-configuration>
测试:
public class OneToManyTets {
//对象导航查询
@Test
public void test3(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 5l);
Set<Linkman> linkmanSet = customer.getLinkmanSet();
for(Linkman linkman : linkmanSet){
System.out.println(linkman.getLkm_id()+" "+linkman.getLkm_name());
}
//测试导航对象
Linkman linkman = session.get(Linkman.class, 1l);
System.out.println("Customer:"+customer.getCust_name());
System.out.println("Linkman:"+linkman.getLkm_name());
transaction.commit();
HibernateUtils.close(session);
}
//级联删除
@Test
public void test2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//Linkman linkman = session.get(Linkman.class, 6l);
//session.delete(linkman);
Customer customer = session.get(Customer.class, 9l);
session.delete(customer);
transaction.commit();
HibernateUtils.close(session);
}
//一对多存储、级联保存
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
Linkman linkman1 = new Linkman();
Linkman linkman2 = new Linkman();
customer.setCust_name("CF");
linkman1.setLkm_name("盖比");
linkman2.setLkm_name("拉伦多");
//维护关系
customer.getLinkmanSet().add(linkman1);
customer.getLinkmanSet().add(linkman2);
linkman1.setCustomer(customer);
linkman2.setCustomer(customer);
//保存
session.save(customer);
//session.save(linkman1);
//session.save(linkman2);
transaction.commit();
HibernateUtils.close(session);
}
}
2、Hibernate多对多的操作
实体类结构
//用户实体类
private long user_id;//'用户id',
private String user_code;// '用户账号',
private String user_name;// '用户名称',
private String user_password;// '用户密码',
private String user_state;// '1:正常,0:暂停',
private Set<Role> roles = new HashSet<Role>();//多对多集合
//角色实体类
private long role_id;
private String role_name;//'角色名称',
private String role_memo;// '备注',
private Set<User> users = new HashSet<User>();//多对多集合
配置映射关系
<!--用户关系配置-->
<hibernate-mapping>
<class name="com.itheima.domain.User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!-- 配置多对多
name:set集合的名称
key的column:当前实体在中间表中的外键名称(别人引用我的外键)
many-to-many的class:对方的全限定名
many-to-many的column:代表对方的外键名称(我引用别人的外键)
table:中间表名称
-->
<set name="roles" table="sys_user_role" inverse="true">
<key column="user_id"></key>
<many-to-many class="com.itheima.domain.Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
<!--角色关系配置-->
<hibernate-mapping>
<class name="com.itheima.domain.Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"></generator>
</id>
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<set name="users" table="sys_user_role">
<key column="role_id"></key>
<many-to-many class="com.itheima.domain.User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
配置核心配置参数
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="com/itheima/domain/Role.hbm.xml"/>
<mapping resource="com/itheima/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
测试
public class ManyToManyTest {
@Test
public void test02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//给用户添加角色
User user = session.get(User.class, 9l);
Role role = session.get(Role.class,13l);
role.getUsers().add(user);
session.save(role);
transaction.commit();
HibernateUtils.close(session);
}
@Test
public void test01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//添加用户和角色
User user01 = new User();
User user02 = new User();
Role role01 = new Role();
Role role02 = new Role();
user01.setUser_name("魔兽世界");
user02.setUser_name("LOL");
role01.setRole_name("摩登莫西");
role02.setRole_name("路西多亚");
user01.getRoles().add(role01);
user02.getRoles().add(role02);
role01.getUsers().add(user01);
role02.getUsers().add(user02);
session.save(role01);
session.save(role02);
session.save(user01);
session.save(user02);
transaction.commit();
HibernateUtils.close(session);
}
}
六、Hibernate检索查询(五种查询方法详解)
1、HQL
单表检索
public class HQLFunction {
//投影检索
@Test
public void fun6(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " select cust_name from com.itheima.domain.Customer ";
String hql2 = " select cust_name,cust_id from com.itheima.domain.Customer ";
String hql3 = " select new Customer(cust_id,cust_name) from com.itheima.domain.Customer ";
Query query = session.createQuery(hql1);
List list = query.list();
System.out.println(list);
transaction.commit();
HibernateUtils.close(session);
}
//统计检索
@Test
public void fun5(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " select count(*) from com.itheima.domain.Customer ";//完整写法
Query query = session.createQuery(hql1);
Number number = (Number) query.uniqueResult();
System.out.println(number);
transaction.commit();
HibernateUtils.close(session);
}
//分页检索
@Test
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from com.itheima.domain.Customer";//完整写法
Query query = session.createQuery(hql);
query.setFirstResult(0);
query.setMaxResults(3);
List list = query.list();
System.out.println(list);
transaction.commit();
HibernateUtils.close(session);
}
//条件检索
@Test
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " from com.itheima.domain.Customer where cust_id=? ";//完整写法
String hql2 = " from com.itheima.domain.Customer where cust_id=:id ";//完整写法
Query query = session.createQuery(hql2);
query.setParameter("id",1l);
Object object = query.uniqueResult();
System.out.println(object);
transaction.commit();
HibernateUtils.close(session);
}
//排序检索
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " from com.itheima.domain.Customer order by cust_id asc ";//完整写法
String hql2 = " from com.itheima.domain.Customer order by cust_id desc ";//完整写法
Query query = session.createQuery(hql2);
List<Customer> list = query.list();
for(Customer customer : list){
System.out.println(customer);
}
transaction.commit();
HibernateUtils.close(session);
}
//基本检索
@Test
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = "from com.itheima.domain.Customer";//完整写法
String hql2 = "from Customer";//简写
String hql3 = "from kava.long.Object";//根据类型查,当前映射文件中注册的所有Object的子类对象
Query query = session.createQuery(hql1);
List<Customer> list = query.list();
for(Customer customer : list){
System.out.println(customer);
}
transaction.commit();
HibernateUtils.close(session);
}
}
多表检索
public class HQLMTMFunctiom {
/*
复习原生SQL:
交叉连接-笛卡尔积(避免)
select * from A,B
内连接
|-隐式内连接
select * from A,B where b.aid = a.id
|-显式内连接
select * from A inner join B on b.aid = a.id
外连接
|- 左外
select * from A left [outer] join B on b.aid = a.id
|- 右外
select * from A right [outer] join B on b.aid = a.id
*/
//HQL 右外连接 => 将连接的两端对象分别返回.放到数组中.
@Test
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer c right join c.linkmanSet";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for(Object[] objects : list){
System.out.println(Arrays.toString(objects));
}
transaction.commit();
HibernateUtils.close(session);
}
//HQL 左外连接 => 将连接的两端对象分别返回.放到数组中.
@Test
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer c left join c.linkmanSet";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for(Object[] objects : list){
System.out.println(Arrays.toString(objects));
}
transaction.commit();
HibernateUtils.close(session);
}
//HQL 迫切内连接 => 帮我们进行封装.返回值就是一个对象
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer c inner join fetch c.linkmanSet";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer customer : list){
System.out.println(customer);
}
transaction.commit();
HibernateUtils.close(session);
}
//HQL 内连接 => 将连接的两端对象分别返回.放到数组中.
@Test
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer c inner join c.linkmanSet";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for(Object[] object : list){
System.out.println(Arrays.toString(object));
}
transaction.commit();
HibernateUtils.close(session);
}
}
2、Criteria(BQC)
public class Demo {
@Test
//基本语法
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//条件语法
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = session.createCriteria(Customer.class);
// c.add(Restrictions.idEq(2l));
c.add(Restrictions.eq("cust_id",2l));
List<Customer> list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//分页语法 - 与HQL一样
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = session.createCriteria(Customer.class);
//limit ?,?
c.setFirstResult(0);
c.setMaxResults(2);
List<Customer> list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//排序语法
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = session.createCriteria(Customer.class);
c.addOrder(Order.asc("cust_id"));
//c.addOrder(Order.desc("cust_id"));
List<Customer> list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//统计语法
public void fun5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Criteria c = session.createCriteria(Customer.class);
//设置查询目标
c.setProjection(Projections.rowCount());
List list = c.list();
System.out.println(list);
//----------------------------------------------------
tx.commit();
session.close();
}
}
public class Demo2 {
//离线检索
@Test
public void fun1(){
//Service/web层
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致)
//----------------------------------------------------
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();
}
}
3、OID
4、对象导航
5、原生SQL
七、CRM查询优化
1、延迟加载
//懒加载|延迟加载
public class Demo {
@Test
// get方法 : 立即加载.执行方法时立即发送sql语句查询结果
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.get(Customer.class, 2l);
System.out.println(c);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
// load方法(默认):是在执行时,不发送任何sql语句.返回一个对象.使用该对象时,才执行查询.
// 延迟加载: 仅仅获得没有使用.不会查询.在使用时才进行查询.
// 是否对类进行延迟加载: 可以通过在class元素上配置lazy属性来控制.
//lazy:true 加载时,不查询.使用时才查询b
//lazy:false 加载时立即查询.
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.load(Customer.class, 2l);
//----------------------------------------------------
tx.commit();
session.close();
System.out.println(c);
}
}
结论:为了提高效率.建议使用延迟加载(懒加载)。
注意:使用懒加载时要确保,调用属性加载数据时,session还是打开的.不然会抛出异常。
2、抓取策略
//关联级别 延迟加载 & 抓取策略
public class Demo {
//集合级别的关联
//fetch:select 单表查询
//lazy:true 使用时才加载集合数据.
@Test
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.get(Customer.class, 2l);
Set<LinkMan> linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens);
//----------------------------------------------------
tx.commit();
session.close();
}
//集合级别的关联
//fetch:select 单表查询
//lazy:false 立即记载集合数据
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.get(Customer.class, 2l);
Set<LinkMan> linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens);
//----------------------------------------------------
tx.commit();
session.close();
}
//集合级别的关联
//fetch:select 单表查询
//lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句)
@Test
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.get(Customer.class, 2l);
Set<LinkMan> linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens.size());
System.out.println(linkMens);
//----------------------------------------------------
tx.commit();
session.close();
}
//集合级别的关联
//fetch:join 多表查询
//lazy:true|false|extra 失效.立即加载.
@Test
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
Customer c = session.get(Customer.class, 2l);
Set<LinkMan> linkMens = c.getLinkMens();//关联级别
System.out.println(linkMens.size());
System.out.println(linkMens);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//fetch: subselect 子查询
//lazy: true 懒加载
public void fun5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
String hql = "from Customer";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//fetch: subselect 子查询
//lazy: false 立即加载
public void fun6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
String hql = "from Customer";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//fetch: subselect 子查询
//lazy: extra 极其懒惰
public void fun7(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
String hql = "from Customer";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c);
System.out.println(c.getLinkMens().size());
System.out.println(c.getLinkMens());
}
//----------------------------------------------------
tx.commit();
session.close();
}
}
//关联级别 延迟加载 & 抓取策略
public class Demo2 {
@Test
//fetch:select 单表查询
//lazy:proxy
//customer-true 懒加载
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
LinkMan lm = session.get(LinkMan.class, 3l);
Customer customer = lm.getCustomer();
System.out.println(customer);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//fetch:join 多表
//lazy: 失效
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
LinkMan lm = session.get(LinkMan.class, 3l);
Customer customer = lm.getCustomer();
System.out.println(customer);
//----------------------------------------------------
tx.commit();
session.close();
}
@Test
//fetch:select 单表查询
//lazy:proxy
//customer-false 立即加载
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
LinkMan lm = session.get(LinkMan.class, 3l);
Customer customer = lm.getCustomer();
System.out.println(customer);
//----------------------------------------------------
tx.commit();
session.close();
}
}
结论:为了提高效率.fetch的选择上应选择select. lazy的取值应选择 true. 全部使用默认值。
no-session问题解决: 扩大session的作用范围(使用Filter)。
3、批量抓取
public class Demo {
@Test
public void fun1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//----------------------------------------------------
String hql = "from Customer ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
for(Customer c:list){
System.out.println(c.getLinkMens());
}
//----------------------------------------------------
tx.commit();
session.close();
}
}