Hibernate学习笔记

1. 概述

1.1 Hibernate介绍

Hibernate框架应用在三层架构中的dao层,对JDBC进行封装,完成CRUD。Hibernate是开源的轻量级框架。

1.2 ORM 思想

ORM:object relational mapping 对象关系映射。

  1. 让实体类和数据库表进行一一对应关系
    让实体类首先和数据库表对应
    让实体类属性 和 表里面字段对应
  2. 不需要直接操作数据库表,而操作表对应实体类对象。
1.3 搭建Hibernate环境
  1. 导入jar包

  2. 创建实体类:使用Hibernate的时候不需要自己手动创建表,hibernate会自动创建。
    注意:

    1. 要求必须有唯一的属性;
    2. 属性类型不建议为基本数据类型,使用对应的包装类。
  3. 创建映射配置文件:

  4. 创建核心配置文件

    1. 配置数据库信息
    2. 配置hibernate信息:非必须的
    3. 加载映射文件
    4. 注意:
      • 名称和位置必须固定:必须在resource下,名称必须为hibernate.cfg.xml;

      • 配置文件中:

        true
        true

                <!--只有配置了之后,Hibernate会自动创建表-->
                <property name="hibernate.hbm2ddl.auto">update</property>
        
                <!--配置数据库方言:让Hibernate框架自动识别不同数据库的特有的语言-->
                <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        
  5. 编写测试类。
    第一步 加载hibernate核心配置文件:到resources下面找到名称hibernate.cfg.xml配置文件,创建对象,把配置文件放到对象里面(加载核心配置文件)
    第二步 创建SessionFactory对象:根据核心配置文件中,有数据库配置,有映射文件部分,到数据库里面根据映射关系把表创建。不过该过程特别耗资源,一般一个项目只加载一个SessionFactory对象。
    第三步 使用SessionFactory创建session对象:session类似于jfbc中的connection,可以使用session实现crud操作。
    注意:session对象是单线程对象,不能被共用,只能自己使用。
    第四步 开启事务
    第五步 写具体逻辑 crud操作
    第六步 提交事务
    第七步 关闭资源
    public void testAdd()
    {
    //加载核心配置文件
    Configuration configuration = new Configuration();
    configuration.configure();

            //创建SessionFactory对象
            SessionFactory factory = configuration.buildSessionFactory();
    
            //使用SessionFactory创建session对象
            Session session = factory.openSession();
    
            //开启事务
            Transaction tx = session.beginTransaction();
    
            User user = new User();
            user.setName("李淼");
            user.setPassword("123");
            user.setAddress("临汾");
    
            session.save(user);
    
            //提交事务
            tx.commit();
    
            //关闭资源
            session.close();
            factory.close();
    
        }
    
1.4 主键生成策略
    <id name="id" column="id">
               <generator class="native"></generator>
           </id>

class属性中有很多值,例如native,increment,identity,sequence,uuid等,使用最多的是native和uuid。
(1)native:根据使用的数据库选择哪个值。适合跨数据库开发。
(2)uuid:

UUID的使用:
1. 实体类id属性类型 必须 字符串类型;
2.

1.5 实体类的状态
  1. 瞬时态
    瞬时态的实例是由new命令创建,开辟内存空间的对象,不存在持久化标识符OID(相当于主键),尚未与Hibernate Session关联。
  2. 持久态
    持久态的对象存在持久化标识符OID,加入到了session的缓存中,并且相关联的session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象。持久态对象是在事务还未提交之前变成的。
  3. 托管态
    也称离线态或脱离态,当某个持久态的实例与session的连接被关闭后,就成为了托管态。托管态对象存在持久化标识符OID,并且仍然与数据库的数据相关联,只是失去了和session的关联。

2. 缓存

2.1 一级缓存
2.1.1 特点
  1. 一级缓存默认打开
  2. 使用范围:session。session从打开到关闭
  3. 存储数据必须为持久态数据。
2.1.2 特性

持久态自动更新数据库。

        Session session = factory.openSession();
        //开启事务
        Transaction tx = session.beginTransaction();

        User user2 = session.get(User.class,2);
        user2.setName("马窦桂梅");
        //提交事务
        tx.commit();
        //关闭资源
        session.close();
        factory.close();

以上代码中并没有session.update(),但是仍然会修改数据库中的数据。

2.2二级缓存
2.1.2 特点
  1. 目前已经不在使用,使用redis代替
  2. 默认不打开 ,需要进行配置
  3. 使用范围:sessionFactory

3. 事务操作

3.1 代码规范
try {
  开启事务
  提交事务
}catch() {
  回滚事务
}finally {
  关闭
}

4. Hibernate三个对象

4.1 Query

使用query对象,不需要写sql语句,但是写hql语句

(1)hql:hibernate query language,hibernate提供查询语言,这个hql语句和普通sql语句很相似

(2)hql和sql语句区别:

  • 使用sql操作表和表字段

  • 使用hql操作实体类和属性

2 查询所有hql语句:

(1)from 实体类名称

 Query query = session.createQuery("from User");
            List<User> users = query.list();
            for(User user: users)
            {
                System.out.println(user);
            }
4.2 Criteria对象

使用这个对象查询操作,但是使用这个对象时候,不需要写语句,直接调用方法实现。

 Criteria criteria = session.createCriteria(User.class);
            List<User> users = criteria.list();
            for(User user: users)
            {
                System.out.println(user);
            }
4.3 SQLQuery对象

使用hibernate时候,调用底层sql实现.

 SQLQuery sqlQuery = session.createSQLQuery("select * from t_user");
            sqlQuery.addEntity(User.class);
            List<User> users = sqlQuery.list();
            for(User user: users)
            {
                System.out.println(user);
            }

5. Hibernate的一对多操作

5.1 创建两个实体类

一个客户有多个联系人。在客户实体类中添加private Set linkManSet = new HashSet<>();

一个联系人对应一个客户:在联系人实体类中添加private Customer customer;

5.2 创建映射文件

创建客户实体类对应的映射文件,与之前的不同在于:

<set name="linkManSet">
            <key column="clid"></key>
            <one-to-many class="com.nuc.domain.LinkMan"></one-to-many>
</set>

创建联系人实体类对应的映射文件,与之前的不同在于:

<many-to-one name="customer" class="com.nuc.domain.Customer" column="clid"></many-to-one>
5.3 创建核心配置文件

引入以上两个映射配置文件。

5.4 测试

分别创建两个对象,然后添加到表中。

session = factory.openSession();
            tx = session.beginTransaction();

            Customer customer = new Customer();
            customer.setCustLevel("vip");
            customer.setCustName("腾讯");
            customer.setCustMobile("123456");
            customer.setCustPhone("1384949");
            customer.setCustSource("山西");

            LinkMan linkMan = new LinkMan();
            linkMan.setLkm_name("小王");
            linkMan.setLkm_phone("1381446");
            linkMan.setLkm_gender("男");

            customer.getLinkManSet().add(linkMan);
            linkMan.setCustomer(customer);

            session.save(customer);
            session.save(linkMan);

            tx.commit();
5.5 级联操作

首先进行如下配置:

<set name="linkManSet" cascade="save-update,delete"/>

级联添加:

Customer customer = new Customer();
            customer.setCustLevel("普通");
            customer.setCustName("nba");
            customer.setCustMobile("4568");
            customer.setCustPhone("1384949");
            customer.setCustSource("美国");

            LinkMan linkMan = new LinkMan();
            linkMan.setLkm_name("小科");
            linkMan.setLkm_phone("1381446");
            linkMan.setLkm_gender("男");

            customer.getLinkManSet().add(linkMan);


            session.save(customer);

级联删除:

session = factory.openSession();
            tx = session.beginTransaction();
            Customer customer = session.get(Customer.class,2);
            session.delete(customer);
            tx.commit();

级联修改:

 Customer customer = session.get(Customer.class,2);
            LinkMan linkMan = session.get(LinkMan.class,1);
            customer.getLinkManSet().add(linkMan);
            linkMan.setCustomer(customer);
            tx.commit();

因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题。

解决方式:让其中的一方不维护外键

 <set name="linkManSet" inverse="true">

6. Hibernate的多对多操作

6.1 多对多映射配置
  1. 编写user和role两个实体类,在各自的属性中使用set引用对方,添加get,set方法。
  2. 配置映射文件:主要是set的配置。
    User对应的映射文件:







    role对应的映射文件:




  3. 在核心配置文件中引入以上两个配置文件。
  4. 编写测试类:实现级联添加,删除等。
6.2 维护第三张表的关系

给某一个用户添加角色,只需要在该用户的set集合中添加一个role即可。

		   User user = session.get(User.class,3);
            Role role = session.get(Role.class,3);

            user.getRoleSet().add(role);

给某一个用户删除角色,只需要在该用户的set集合中删除role即可。

            User user = session.get(User.class,3);
            Role role = session.get(Role.class,3);

            user.getRoleSet().remove(role);

7. Hibernate查询方式

7.1 对象导航方式

根据id查询某个客户,再查询这个客户里面所有的联系人

Customer customer = session.get(Customer.class,2);
Set<LinkMan> linkMEN = customer.getLinkManSet();

for (LinkMan l:linkMEN
    ) {
    System.out.println(l);
}
7.2 OID查询

调用session里面的get方法实现.

 Customer customer = session.get(Customer.class,2);
7.3 HQL查询
  1. hql:hibernate query language,hibernate提供一种查询语言,hql语言和普通sql很相似,区别:普通sql操作数据库表和字段,hql操作实体类和属性
  2. 常用的hql语句

(1)查询所有: from 实体类名称

(2)条件查询: from 实体类名称 where 属性名称=?

(3)排序查询: from 实体类名称 order by 实体类属性名称 asc/desc

  1. 使用hql查询操作时候,使用Query对象

(1)创建Query对象,写hql语句

(2)调用query对象里面的方法得到结果

7.4 QBC查询

1 使用hql查询需要写hql语句实现,但是使用qbc时候,不需要写语句了,使用方法实现

2 使用qbc时候,操作实体类和属性

3 使用qbc,使用Criteria对象实现

7.6 本地sql查询

8. 多表查询

  1. 内连接
    Query query = session.createQuery(“from Customer c inner join c.linkManSet”);
    List customers = query.list();
    System.out.println(customers.size());

  2. 迫切内连接:
    Query query = session.createQuery(“from Customer c inner join fetch c.linkManSet”);

        List<Customer> customers = query.list();
    
        for (Customer c:customers
            ) {
            System.out.println(c);
        }
    

    二者的区别在于:内连接返回的是数组,迫切内连接返回的是对象。
    左连接,左外连接,右连接,右外连接与之类似。

9. 检索策略

9.1 立即查询

根据id查询,调用get方法,一调用get方法马上发送语句查询数据库

9.2 延迟查询

根据id查询,还有load方法,调用load方法不会马上发送语句查询数据,只有得到对象里面的值时候才会发送语句查询数据库。延迟查询分为两类:

  1. 类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送语句
  2. 关联级别延迟:查询某个客户,再查询这个客户的所有联系人,查询客户的所有联系人的过程是否需要延迟,这个过程称为关联级别延迟。实现方法如下:
    在set标签上使用属性
    (1)fetch:值select(默认)
    (2)lazy:值
    • true:延迟(默认)
    • false:不延迟
    • extra:极其延迟
9.3 批量抓取

查询所有的客户,返回list集合,遍历list集合,得到每个客户,得到每个客户的所有联系人。之前的方式会发送多次sql语句。

解决:在客户的映射文件中,set标签配置:batch-size值,值越大发送语句越少

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值