Hibernate学习(二)

目录

  1. Hibernate的持久化类介绍
  2. Hibernate持久化对象的状态
  3. Hibernate的一级缓存
  4. Hibernate的事务与并发
  5. 线程ThreadLocal绑定Session
  6. Hibernate的基本查询(HQL)

1. Hibernate持久化类

1.1 持久化类
就是普通的Java实体类,这个类通过映射文件与数据库表建立关联后就成为持久化类。

1.2 持久化类编写规则
提供无参构造函数(反射)
提供标识属性,映射数据表的主键字段
所有属性提供getter、setter方法
标识属性尽量使用基本数据类型的包装类(如Integer、Long...)

2. Hibernate持久化对象的状态

状态 描述
瞬时态(Transient Object) 没有持久化标识ID(对象刚刚创建),没有被纳入到Session对象的管理
持久态(Persistent Object) 有持久化标识ID(执行了数据库的操作,如保存或查询等),已经被纳入到Session对象的管理(持久态对象修改数据可以自动更新数据库)
脱管态(Detached Object) 有持久化标识ID,已经脱离了Session对象的管理

3. Hibernate的一级缓存

Hibernate框架提供了两种缓存:分别是一级缓存以及二级缓存,一级缓存是默认并且不可更改的,它的生命周期与session一致(session级别的缓存);二级缓存默认没有开启,需要我们手动在配置文件中添加(以后补充)是进程或集群范围内的缓存,可以在多个session中共享数据。

接下来我们编写代码,通过在同一个Session对象中进行两次查询来证明一级缓存的存在

@Test
public void twiceQueryTest()
{
    Session session = HibernateUtils.getSession();
    Transaction transaction = session.beginTransaction();

    //通过id查询一条数据
    User u1 = session.get(User.class, 1L);
    User u2 = session.get(User.class, 1L);
    //比较这两个对象的内存地址
    System.out.println(u1 == u2);

    transaction.commit();
    session.close();
}

头铁的我发现SQL只执行了一次,并且这两个对象的内存地址是相等的;这就说明了一级缓存的存在;

Hibernate学习(二)_第1张图片
image

控制Session一级缓存的方法

方法 描述
Session.clear() 清空缓存
Session.evict(Object entity) 从缓存中清除指定的对象
Session.flush() 刷出缓存, 可以强制进行从内存到数据库的同步。

4. Hibernate的事务与并发

4.1 事务描述

事务就是一组不可分割的原子操作,操作要么成功要么失败,最经典的例子就是转账了

4.2 事务的特性

  • 原子性:事务不可分割
  • 一致性:事务执行的前后数据的完整性应该保持一致
  • 隔离性:一个事务执行过程中,不应该收到其他事务的干扰
  • 持久性:事务一旦提交,数据永久保存到数据库中

4.3 如果不考虑事务的隔离性,可能引发的问题

  • 脏读:A事务读到了B事务未提交的数据
  • 不可重复读:A事务读到了B事务update更新提交的数据,导致多次查询的结果不一致
  • 虚读:A事务读到了B事务插入提交的数据,导入多次查询结构不一致

4.4 Hibernate设置隔离级别

4
隔离级别 描述
1 Read uncommitted isolation(未提交读;上面的问题都有可能出现)
2 Read committed isolation(已提交读;避免了脏读,其它两个问题有可能出现)
4 Repeatable read isolation(可重复读;避免了脏读、不可重复读,但是虚读有可能出现)
8 Serializable isolation(串行化;上面的问题都可以避免,但是效率较低)

4.5 Hibernate并发之数据丢失更新

场景:两个事务同时对一条数据进行操作

解决方法(2种):

  • 悲观锁

采用的是数据库提供的一种锁机制,当A事务操作数据是,会把该条数据锁起来,其它事务不能操作;只有当A事务提交后,释放锁才能进行操作。

//通过设置LockMode枚举
session.get(User.class,1L,LockMode.UPGRADE);
LockMode 描述(待补充)
NONE 默认模式
READ
UPGRADE 已过时
UPGRADE_NOWAIT
UPGRADE_SKIPLOCKED
WRITE
FORCE 已过时
OPTIMISTIC
OPTIMISTIC_FORCE_INCREMENT
PESSIMISTIC_READ
PESSIMISTIC_WRITE
PESSIMISTIC_FORCE_INCREMENT
  • 乐观锁

采用版本号的机制来解决问题,会给表添加一个字段verision,默认值为0,当A事务在操作该条数据提交时,首先会检查版本号,如果发现版本号的值相同时才可以提交事务,并且让version+1;当B事务也提交时,和前面说的一样,发现version变了,程序就会报错。

step1.在对应的JavaBean中添加一个属性,例如

private Integer version;
...
getter setter

step2.在实体类映射文件(User.hbm.xml)中提供标签


    
        
            
        
        
        ...
    



5. 线程ThreadLocal绑定Session

在开发中我们一般在Service中处理业务(然后Service调用Dao层处理数据库操作),开启Session的事务提交;但是我们数据库的操作是放在Dao层的,这个时候Dao层想要使用Service层的Session,只能通过方法将Session作为实参传递或者使用ThreadLocal保存在线程中;Hibernate也帮我们提供了ThreadLocal的方式

step1.hibernate.cfg.xml中配置(到处都是配置,头铁)

thread

step2. 使用SessionFactorygetCurrentSeesion方法获取Session对象,需要注意的是该Session对象线程结束会自动关闭,不需要我们手动调用Sessionclose方法。

...
//创建session对象
Session session = factory.getCurrentSession();
...

6. Hibernate的基本查询(HQL)

6.1 使用Query查询接口

...
//查询所有记录
Query query = session.createQuery("from User");
List list = query.list();
System.out.println(list);

//条件查询,使用?占位符
Query query = session.createQuery("from User where uname = ?");
query.setString(0,"许渺");
List list = query.list();
System.out.println(list);

//条件查询,使用:占位符
Query query = session.createQuery("from User where uname = :name");
query.setString("name","许渺");
List list = query.list();
System.out.println(list);
...

6.2 使用Criteria查询接口(适合做条件查询)

...
//查询所有
Criteria criteria = session.createCriteria(User.class);
List list = criteria.list();
System.out.println(list);

//条件查询
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "许渺"));
List list = criteria.list();
System.out.println(list);
...

你可能感兴趣的:(Hibernate学习(二))