超全面 hibernate 复习总结笔记

如有转载,请申明:
转载自 IT天宇: http://www.jianshu.com/p/50964e92c5fb

前言

博客正式转到,实在忍受不了 CSDN 的模版,有广告或界面难看还可以忍,但有些模版还有 bug,作为程序员忍无可忍,修个 bug 真的有那么难吗,这么多年了。

接着上篇,先说个段子。
三四年前如果有人问我 Android/Ios 如何入门,我可能会推荐上百 G 的资料,但如果现在问我,我只会推荐一本书《app开发从上架到上吊》


超全面 hibernate 复习总结笔记_第1张图片

你可能觉得我危言耸听,但今年的移动开发行情真的很差,看到很多几年经验的一个月才收到几个面试通知,没有经验的就更绝望了。

好吧,今天不是来讨论行情的。
前段时间写了一篇 struts2 的笔记,有好心的老司机告诉我,struts2 已经被抛弃了。但话是这么说,面试的时候,难免碰到问 struts2,如果这个时候表现得一脸懵逼,那估计 offer 就没有了。所以虽然现在 hibernate 用得不多了,但还是得复习一下。

目录

  1. 环境搭建
  2. 实体类映射
  3. 核心配置详解
  4. 一级缓存
  5. 关系映射
  6. 抓取策略
  7. HQL
  8. QBC
  9. 其他配置
  10. 事务
  11. 二级缓存

正文

1.环境搭建

导包

根据需要选择手动导入 jar 包,或者用依赖管理工具。

  • 下载
    http://hibernate.org/orm/downloads/
    必须导入的是 lib\required 下面 jar 包
  • Gradle
    compile "org.hibernate:hibernate-core:5.2.9.Final"
    

此外,为了连接数据库,还需要数据库的驱动包。

配置

核心配置文件以 hibernate.cfg.xml 命名,放在类路径下(Idea 放在 resources 下)



    
    
        
        com.mysql.jdbc.Driver
        jdbc:mysql:///db01
        root
        1234
    
    



2.实体类映射

数据库

create database db01;
use db01;

实体类

public class User {
    private Integer uid;
    private String username;
    private String password;
// 省略 get set 方法
}

映射实体类

可以用 xml 或者 注解来映射

xml

放在实体类同目录下,名字和实体类相同,扩展名为 .hbm.xml
例如: ser.hbm.xml



    
        
        
            
        
        
        
        
        
    
    

核心配置文件中加上映射文件位置


注解

// name 对应表名称
@Entity
@Table(name = "t_user")
public class User {
    // 主键
    @Id
    @GeneratedValue
    private Integer uid;
    private String username;
    private String password;
// 省略 get set 方法
}

在核心配置文件中加上映射文件位置


测试

public class HelloWorld {
    @Test
    public void hello() {
        // username, password
        User user = new User("123456", "123");

        // 1.加载配置文件
        Configuration configure = new Configuration().configure();
        // 2.获得session factory对象
        SessionFactory sessionFactory = configure.buildSessionFactory();
        // 3.创建session
        Session session = sessionFactory.openSession();
        // 4.开启事务
        Transaction transaction = session.beginTransaction();
        // 5.保存并提交事务
        session.save(user);
        transaction.commit();
        // 6.释放资源
        session.close();
        sessionFactory.close();
    }
}

3.核心配置详解

核心 api

Configuration

常用方法

  • 构造方法:默认加载 hibernate.properties
  • configure() 方法:默认加载 hibernate.cfg.xml
  • configure(String) 方法:加载指定配置文件

手动添加映射

// 手动加载指定的配置文件
config.addResource("com/ittianyu/a_hello/User.hbm.xml");

// 手动加载指定类,对应的映射文件 User--> User.hbm.xml
config.addClass(User.class);

SessionFactory

  • SessionFactory 相当于java web连接池,用于管理所有session
  • 获得方式:config.buildSessionFactory();
  • sessionFactory hibernate缓存配置信息 (数据库配置信息、映射文件,预定义HQL语句 等)
  • SessionFactory线程安全,可以是成员变量,多个线程同时访问时,不会出现线程并发访问问题
  • 开启一个 session:factory.openSession();
  • 获取和当前线程绑定的会话(需要配置):factory.getCurrentSession();
    thread
    

Session

  • Session 相当于 JDBC的 Connection -- 会话
  • 通过session操作PO对象 --增删改查
  • session单线程,线程不安全,不能编写成成员变量。
  • Api:
    save 保存
    update 更新
    delete 删除
    get 通过id查询,如果没有 null
    load 通过id查询,如果没有抛异常
    createQuery("hql")  获得Query对象
    createCriteria(Class) 获得Criteria对象
    

Transaction

开启事务 beginTransaction()
获得事务 getTransaction()

提交事务:commit()
回滚事务:rollback()

和 spring 整合后,无需手动管理

Query

  • hibernate执行hql语句
  • hql语句:hibernate提供面向对象查询语句,使用对象(类)和属性进行查询。区分大小写。
  • 获得 session.createQuery("hql")
  • 方法:
    list()  查询所有
    uniqueResult() 获得一个结果。如果没有查询到返回null,如果查询多条抛异常。
    
    setFirstResult(int) 分页,开始索引数startIndex
    setMaxResults(int) 分页,每页显示个数 pageSize
    

Criteria

  • QBC(query by criteria),hibernate提供纯面向对象查询语言,提供直接使用PO对象进行操作。
  • 获得方式:Criteria criteria = session.createCriteria(User.class);
  • 条件
    criteria.add(Restrictions.eq("username", "tom"));
    Restrictions.gt(propertyName, value)        大于
    Restrictions.ge(propertyName, value)    大于等于
    Restrictions.lt(propertyName, value)    小于
    Restrictions.le(propertyName, value)    小于等于
    Restrictions.like(propertyName, value)  模糊查询,注意:模糊查询值需要使用 % _
    

工具类

public class HibernateUtils {
    private static SessionFactory sessionFactory;
    static {
        Configuration configuration = new Configuration().configure();
        sessionFactory = configuration.buildSessionFactory();

        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                sessionFactory.close();
            }
        });
    }

    public static Session openSession() {
        return sessionFactory.openSession();
    }

    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    public static void main(String[] args) {
        Session session = openSession();
        System.out.println(session);
        session.close();

    }
}

核心配置

基本配置



    
    com.mysql.jdbc.Driver
    jdbc:mysql:///h_day01_db
    root
    1234

    
    thread

        
        org.hibernate.dialect.MySQL5Dialect
    
    
    
    true
    true

    
    create
    
    
    none

    
    

主键种类

  • 自然主键: 在业务中,某个属性符合主键的三个要求.那么该属性可以作为主键列.
  • 代理主键: 在业务中,不存符合以上3个条件的属性,那么就增加一个没有意义的列.作为主键.

类型对应

Java数据类型 Hibernate数据类型 标准SQL数据类型(不同DB有差异)
byte、java.lang.Byte byte TINYINT
short、java.lang.Short short SMALLINT
int、java.lang.Integer integer INGEGER
long、java.lang.Long long BIGINT
float、java.lang.Float float FLOAT
double、java.lang.Double double DOUBLE
java.math.BigDecimal big_decimal NUMERIC
char、java.lang.Character character CHAR(1)
boolean、java.lang.Boolean boolean BIT
java.lang.String string VARCHAR
boolean、java.lang.Boolean yes_no CHAR(1)('Y'或'N')
boolean、java.lang.Boolean true_false CHAR(1)('Y'或'N')
java.util.Date、java.sql.Date date DATE
java.util.Date、java.sql.Time time TIME
java.util.Date、java.sql.Timestamp timestamp TIMESTAMP
java.util.Calendar calendar TIMESTAMP
java.util.Calendar calendar_date DATE
byte[] binary VARBINARY、BLOB
java.lang.String text CLOB
java.io.Serializable serializable VARBINARY、BLOB
java.sql.Clob clob CLOB
java.sql.Blob blob BLOB
java.lang.Class class VARCHAR
java.util.Locale locale VARCHAR
java.util.TimeZone timezone VARCHAR
java.util.Currency currency VARCHAR

普通属性

 
            package 用于配置PO类所在包
                例如: package="com.ittianyu.d_hbm"
         配置 PO类 和 表 之间对应关系
            name:PO类全限定类名
                例如:name="com.ittianyu.d_hbm.Person"
                如果配置 package,name的取值可以是简单类名 name="Person"
            table : 数据库对应的表名
            dynamic-insert="false" 是否支持动态生成insert语句
            dynamic-update="false" 是否支持动态生成update语句
                如果设置true,hibernate底层将判断提供数据是否为null,如果为null,insert或update语句将没有此项。
        普通字段
            
                name : PO类的属性
                column : 表中的列名,默认name的值相同
                type:表中列的类型。默认hibernate自己通过getter获得类型,一般情况不用设置
                    取值1: hibernate类型
                        string 字符串
                        integer 整形
                    取值2: java类型 (全限定类名)
                        java.lang.String 字符串
                    取值3:数据库类型
                        varchar(长度) 字符串
                        int 整形
                        
                            
                        
                        javabean 一般使用类型 java.util.Date
                        jdbc规范提供3中
                            java类型              mysql类型
                            java.sql.Date       date
                            java.sql.time       time
                            java.sql.timestamp  timestamp
                            null                datetime
                            
                            以上三个类型都是java.util.Date子类
                            
                length : 列的长度。默认值:255
                not-null : 是否为null
                unique : 是否唯一
                access:设置映射使用PO类属性或字段
                    property : 使用PO类属性,必须提供setter、getter方法
                    field : 使用PO类字段,一般很少使用。
                insert 生成insert语句时,是否使用当前字段。
                update 生成update语句时,是否使用当前字段。
                    默认情况:hibernate生成insert或update语句,使用配置文件所有项
        注意:配置文件如果使用关键字,列名必须使用重音符    

主键

配置主键
name:属性名称
access="" 设置使用属性还是字段
column=""  表的列名
length=""  长度
type="" 类型
 class属性用于设置主键生成策略
1.increment 由hibernate自己维护自动增长
    底层通过先查询max值,再+1策略
    不建议使用,存在线程并发问题
2.identity hibernate底层采用数据库本身自动增长列
    例如:mysql auto_increment
3.sequence hibernate底层采用数据库序列
    例如:oracle 提供序列
4.hilo 
    
    
5.native 根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。【】
##以上策略使用整形,long, short 或者 int 类型
6.uuid 采用字符串唯一值【】
##以上策略 代理主键,有hibernate维护。
7.assigned 自然主键,由程序自己维护。【】

4.一级缓存

对象状态

三种状态

  • 瞬时态:transient,session没有缓存对象,数据库也没有对应记录。
    OID特点:没有值
  • 持久态:persistent,session缓存对象,数据库最终会有记录。(事务没有提交)
    OID特点:有值
  • 脱管态:detached,session没有缓存对象,数据库有记录。
    OID特点:有值

转换

超全面 hibernate 复习总结笔记_第2张图片
三种状态转换图

一级缓存

一级缓存:又称为session级别的缓存。当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。当session关闭时,一级缓存销毁。

@Test
public void demo02(){
    //证明一级缓存
    Session session = factory.openSession();
    session.beginTransaction();
    
    //1 查询 id = 1
    User user = (User) session.get(User.class, 1);
    System.out.println(user);
    //2 再查询 -- 不执行select语句,将从一级缓存获得
    User user2 = (User) session.get(User.class, 1);
    System.out.println(user2);
    
    session.getTransaction().commit();
    session.close();
}

可以调用方法清除一级缓存

//清除
//session.clear();
session.evict(user);

快照

与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。

当缓存和数据库数据不一样且在提交之前,可以调用 refresh 强制刷新缓存。

5.关系映射

一对一

一对一关系一般是可以整合成一张表,也可以分成两张表。
维护两张表的关系可以选择外键也可以选择让主键同步。

实体类

Address.java

public class Address {
    private Integer id;
    private String name;

    private Company company;
    // 省略 get set
}

Company.java

public class Company {
    private Integer id;
    private String name;

    private Address address;
    // 省略 get set
}

外键维护关系

Address.hbm.xml



    
        
        
            company
        
    
    

    
    

Company.hbm.xml



    
        
    
    

    
    

主键同步关系

Address.hbm.xml



    
        
        
            company
        
    
    

    
    

Company.hbm.xml



    
        
    
    

    
    

一对多

实体类

Customer.java

public class Customer {
    private Integer id;
    private String name;

    private Set orders = new HashSet<>();
    // 省略 get set
}

Order.java

public class Order {
    private Integer id;
    private String name;

    private Customer customer;
    // 省略 get set
}

映射文件

Customer.hbm.xml




    
    
        
            
        
        
        
        
            
            
        
    

Order.hbm.xml




    
    
        
            
        
        
        
    

多对多

实体类

Course.java

public class Course {
    private Integer id;
    private String name;
    private Set students = new HashSet<>();
    // 省略 get set
}

Student.java

public class Student {
    private Integer id;
    private String name;
    private Set courses = new HashSet<>();
    // 省略 get set
}

映射文件

Course.hbm.xml




    
    
        
            
        
        

        
        
            
            
        
    

Student.hbm.xml




    
    
        
            
        
        
        
        
            
            
        
    

级联

cascade 表示指定级联操作的类型。

  • save-update : 增加或更新 A 时,自动增加或更新 B。
  • delete : 删除 A 时,自动删除 B
  • all : 上面两项效果叠加
  • delete-orphan (孤儿删除) : 删除所有和当前对象解除关联关系的对象
  • all-delete-orphan : all + delete-orphan 效果叠加

    
    

6.抓取策略

检索方式

  • 立即检索:立即查询,在执行查询语句时,立即查询所有的数据。
  • 延迟检索:延迟查询,在执行查询语句之后,在需要时在查询。(懒加载)

检索策略

  • 类级别检索:当前的类的属性获取是否需要延迟。
  • 关联级别的检索:当前类 关联 另一个类是否需要延迟。

类级别检索

  • get:立即检索。get方法一执行,立即查询所有字段的数据。
  • load:延迟检索。默认情况,load方法执行后,如果只使用OID的值不进行查询,如果要使用其他属性值将查询。可以配置是否延迟检索:
    
    lazy 默认值true,表示延迟检索,如果设置false表示立即检索。
    

关联级别检索

容器 提供两个属性:fetch、lazy,用于控制关联检索。

  • fetch:确定使用sql格式
    • join:底层使用迫切左外连接
    • select:使用多个select语句(默认值)
    • subselect:使用子查询
  • lazy:关联对象是否延迟。
    • false:立即
    • true:延迟(默认值)
    • extra:极其懒惰,调用 size 时,sql 查询 count。(用于只需要获取个数的时候)

批量查询

一次加载多行数据,用于减少 sql 语句数量

比如: 当客户关联查询订单时,默认给每一个客户生产一个select语句查询订单。开启批量查询后,使用in语句减少查询订单语句个数。

默认:select * from t_order where customer_id = ?
批量:select * from t_order where customer_id in (?,?,?,?)

检索总结

检索策略| 优点| 缺点| 优先考虑使用的场合
----| ----| ----
立即检索| 对应用程序完全透明,不管对象处于持久化状态还是游离状态,应用程序都可以从一个对象导航到关联的对象| (1)select语句多
(2)可能会加载应用程序不需要访问的对象,浪费许多内存空间。| (1)类级别
(2)应用程序需要立即访问的对象
(3)使用了二级缓存
延迟检索| 由应用程序决定需要加载哪些对象,可以避免执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并节省内存空间。| 应用程序如果希望访问游离状态的代理类实例,必须保证她在持久化状态时已经被初始化。| (1)一对多或者多对多关联
(2)应用程序不需要立即访问或者根本不会访问的对象
表连接检索| (1)对应用程序完全透明,不管对象处于持久化状态还是游离状态,都可从一个对象导航到另一个对象。
(2)使用了外连接,select语句少| (1)可能会加载应用程序不需要访问的对象,浪费内存。
(2)复杂的数据库表连接也会影响检索性能。| (1)多对一或一对一关联
(2)需要立即访问的对象
(3)数据库有良好的表连接性能。

7.HQL

查询所有

//1  使用简单类名 , 存在自动导包
// * Customer.hbm.xml 
//  Query query = session.createQuery("from Customer");
//2 使用全限定类名
Query query = session.createQuery("from com.ittianyu.bean.Customer");
// 获取结果
List allCustomer = query.list();

条件查询

//1 指定数据,cid OID名称
//  Query query = session.createQuery("from Customer where cid = 1");
//2 如果使用id,也可以(了解)
//  Query query = session.createQuery("from Customer where id = 1");
//3 对象别名 ,格式: 类 [as] 别名
//  Query query = session.createQuery("from Customer as c where c.cid = 1");
//4 查询所有项,mysql--> select * from...
Query query = session.createQuery("select c from Customer as c where c.cid = 1");

Customer customer = (Customer) query.uniqueResult();

投影查询

//1 默认
//如果单列 ,select c.cname from,需要List
//如果多列,select c.cid,c.cname from ,需要List  ,list存放每行,Object[]多列
//  Query query = session.createQuery("select c.cid,c.cname from Customer c");
//2 将查询部分数据,设置Customer对象中
// * 格式:new Customer(c.cid,c.cname)
// * 注意:Customer必须提供相应的构造方法。
// * 如果投影使用oid,结果脱管态对象。
Query query = session.createQuery("select new Customer(c.cid,c.cname) from Customer c");

List allCustomer = query.list();
 
 

排序

Query query = session.createQuery("from Customer order by cid desc");
List allCustomer = query.list();

分页

Query query = session.createQuery("from Customer");
// * 开始索引 , startIndex 算法: startIndex = (pageNum - 1) * pageSize;
// *** pageNum 当前页(之前的 pageCode)
query.setFirstResult(0);
// * 每页显示个数 , pageSize
query.setMaxResults(2);

List allCustomer = query.list();

绑定参数

Integer cid = 1;

//方式1 索引 从 0 开始
//  Query query = session.createQuery("from Customer where cid = ?");
//  query.setInteger(0, cid);
//方式2 别名引用 (:别名)
Query query = session.createQuery("from Customer where cid = :xxx");
//  query.setInteger("xxx", cid);
query.setParameter("xxx", cid);

Customer customer = (Customer) query.uniqueResult();

聚合函数和分组

//1 
//  Query query = session.createQuery("select count(*) from Customer");
//2 别名
//  Query query = session.createQuery("select count(c) from Customer c");
//3 oid
Query query = session.createQuery("select count(cid) from Customer");

Long numLong = (Long) query.uniqueResult();

连接查询

//左外连接
//  List list = session.createQuery("from Customer c left outer join c.orderSet ").list();
//迫切左外链接 (默认数据重复)
//  List list = session.createQuery("from Customer c left outer join fetch c.orderSet ").list();
//迫切左外链接 (去重复)
List list = session.createQuery("select distinct c from Customer c left outer join fetch c.orderSet ").list();

命名查询

Custom.hbm.xml

...
    
    



测试

//全局
//List list = session.getNamedQuery("findAll").list();
//局部
List list = session.getNamedQuery("com.ittianyu.a_init.Customer.findAll").list();

8.QBC

查询所有

List list = session.createCriteria(Customer.class).list();

分页查询

Criteria criteria = session.createCriteria(Order.class);
criteria.setFirstResult(10);
criteria.setMaxResults(10);
List list = criteria.list();

排序

Criteria criteria = session.createCriteria(Customer.class);
//      criteria.addOrder(org.hibernate.criterion.Order.asc("age"));
criteria.addOrder(org.hibernate.criterion.Order.desc("age"));
List list = criteria.list();

条件查询

// 按名称查询:
/*Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cname", "tom"));
List list = criteria.list();*/

// 模糊查询;
/*Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cname", "t%"));
List list = criteria.list();*/

// 条件并列查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.like("cname", "t%"));
criteria.add(Restrictions.ge("age", 35));
List list = criteria.list();

离线查询

// service 层 封装与 session 无关的 criteria
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
detachedCriteria.add(Restrictions.eq("id", 4));

// dao 层
Session session = HibernateUtils.openSession();
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
List list = criteria.list();

9.其他配置

c3p0(spring 整合后直接配 dataSource)

  1. 导入 c3p0 包
  2. hibernate.cfg.xml 配置
    org.hibernate.connection.C3P0ConnectionProvider
    

log4j

  1. 导入包
    • log4j 核心包:log4j-1.2.17.jar
    • 过渡jar:slf4j-log4j12-1.7.5.jar
  2. 导入配置文件
    • log4j.properties ,此配置文件通知log4j 如何输出日志

10.事务

隔离级别

  • read uncommittd,读未提交。存在3个问题。
  • read committed,读已提交。解决:脏读。存在2个问题。
  • repeatable read ,可重复读。解决:脏读、不可重复读。存在1个问题。
  • serializable,串行化。单事务。没有问题。

hibernate 中配置

4

对照上面的分别是 1 2 4 8,0表示没有事务级别

悲观锁

采用数据库锁机制。丢失更新肯定会发生。

  • 读锁:共享锁。
    select .... from  ... lock in share mode;
    
  • 写锁:排他锁。(独占)
    select ... from  ....  for update
    

Hibernate 中使用

Customer customer = (Customer) session.get(Customer.class, 1 ,LockMode.UPGRADE);

乐观锁

在表中提供一个字段(版本字段),用于标识记录。如果版本不一致,不允许操作。丢失更新肯定不会发生

Hibernate 中使用

  1. 在PO对象(javabean)提供字段,表示版本字段。
    ...
    private Integer version;
    ...
    
  2. 在配置文件中增加 version
    
        ...
        
        ...
    

11.二级缓存

sessionFactory 级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。

由4部分构成:

  • 类级别缓存
  • 集合级别缓存
  • 时间戳缓存
  • 查询缓存(二级缓存的第2大部分,三级缓存)

并发访问策略

||
---|---
transactional| 可以防止脏读和不可重复读,性能低
read-write| 可以防止脏读,更新缓存时锁定缓存数据
nonstrict-read-write| 不保证缓存和数据库一致,为缓存设置短暂的过期时间,减少脏读
read-only| 适用于不会被修改的数据,并发性能高

应用场景

  • 适合放入二级缓存中的数据:
    很少被修改
    不是很重要的数据, 允许出现偶尔的并发问题
  • 不适合放入二级缓存中的数据:
    经常被修改
    财务数据, 绝对不允许出现并发问题
    与其他应用数据共享的数据

二级缓存提供商

  • EHCache: 可作为进程(单机)范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对 Hibernate 的查询缓存提供了支持。--支持集群。
  • OpenSymphony `:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对 Hibernate 的查询缓存提供了支持
  • SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存
  • JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存

开启二级缓存

  1. 导包 hibernate-ehcache-5.2.8.Final.jar
  2. 配置
    
    true
    org.hibernate.cache.ehcache.EhCacheRegionFactory
    

使用二级缓存

类缓存




集合缓存


查询缓存

将HQL语句 与 查询结果进行绑定。通过HQL相同语句可以缓存内容。

  1. 配置

    #hibernate.cache.use_query_cache true 启用 HQL查询缓存
    true
    
  2. 使用

    Query query = session.createQuery("from Customer");
    query.setCacheable(true);// 标记为缓存
    

你可能感兴趣的:(超全面 hibernate 复习总结笔记)