day27HibernateDay02(持久化类 悲乐观锁 事务 session一级缓存 Criteria接口查询)

持久化类
    就是一个Java类(编写的JavaBean),这个Java类与表建立了关系就可以成为持久化类
        持久化类 = JavaBean + xxx.hbm.xml

持久化类的编写规则
1、提供一个无参数 public访问控制符的构造器       底层需要进行反射
2、提供一个标识属性,映射数据表主键字段            唯一标识OID,数据库中通过主键。Java对象通过地址确定对象,持久化类通过唯一标识OID确定记录
3、所有属性提供public访问控制符的 set或者get方法
4、标识属性应尽量使用基本数据类型的包装类型

区分自然主键和代理主键
1、创建表的时候
    自然主键:对象本身的一个属性,创建一个人员表,每个人都有一个身份证号(唯一的)使用身份证号作为表的主键,自然主键(开发不会用 因为可能重复)

    代理主键:不是对象本身的一个属性,创建一个人员表,为每个人员单独创建一个字段,用这个字段作为主键,代理主键(推荐使用)

2、创建表的时候尽量使用代理主键创建表

主键的生成策略
1、increment:适用于short,int,long作为主键,不是使用的数据库自动增长机制
    Hibernate中提供的一种增长机制
        先进行查询 select max(id) from user
        再进行插入 获得最大值+1作为新的记录的主键
    问题:不能在集群环境下或者有并发访问的情况下使用

2、identity:适用于short,int,long作为主键,但是这个必须使用在有自动增长数据库中,才有的是数据库底层的自动增长机制
    底层使用的是数据库的自动增长(auto_increment)像Oracle数据库没有自动增长

3、sequence:适用于short,int,long作为主键,底层使用的是序列的增长方式
    Oracle数据库底层没有自动增长,想自动增长需要使用序列

4、uuid:适用于char,varchar类型的作为主键
    使用随机的字符串作为主键

5、native:本地策略,根据底层的数据库不同,自动选择适用于该种数据库的生成策略(short,int,long)
    如果底层使用的是MySQL的数据库,相当于identity
    如果底层使用的是Oracle数据库,相当于sequence

6、assigned:主键的生成不用Hibernate管理了,必须手动设置主键

持久化对象的状态
1、Hibernate的持久化类
    持久化类:Java类与数据库的某个表建立了映射关系,这个表就称之为持久化类
        持久化类=Java类+hbm的配置文件

2、Hibernate的持久化类的状态
    Hibernate为了管理持久化类:将持久化类分成了三个状态
        瞬时态:Transient Object
            没有持久化标识OID,没有被纳入到Session对象的管理

        持久态:Persistent Object
            有持久化标识OID,已经被纳入到Session对象的管理
            注意:持久化持久态的对象有自动更新数据库的能力

        脱管态:Detached Object
            有持久化标识OID,没有被纳入到Session对象的管理

持久化对象的状态的转换
    1、瞬时态Transient      没有oid没有被session管理
        获得瞬时态的对象
            User user = new User();
        瞬时态对象转换成持久态
            save()/saveOrUpdate()
        瞬时态对象转换成脱管态
            user.setId(1)
    2、持久态Persistent         有持久化标识的OID,已经被纳入到Session对象的管理
        获得持久态的对象
            get()/load()
        持久态转换成瞬时态对象
            delete()    比较有争议的,进入特殊的状态(删除态:Hibernate中不建议使用的)
        持久态对象转换成脱管对象
            session的close()/evict()/clear()
    3、脱管态Detached           有持久化标识OID,没有被纳入到Session对象的管理
        获得脱管态对象,不建议直接获得脱管态的对象
            User user = new User();
            user.setId(1);
        脱管态对象转换成持久态对象
            update()/saveOrUpdate()/lock()
        脱管态对象转换成瞬时态对象
            user.setId(null)
    4、持久态对象有自动更新数据库的能力

Session对象的一级缓存
1、什么是缓存
    其实就是一块内存空间,将数据源(数据库或文件)中的数据放到缓存中,再次获取的时候,直接从缓存中获取,可以提升程序的性能

2、Hibernate框架提供了两种缓存
    一级缓存        自带的不可卸载的,一级缓存的生命周期与session一致,一级缓存称为session级别的缓存
    二级缓存        默认没有开启,需要手动配置才可以使用的,二级缓存可以在多个session中共享数据,二级缓存称为是sessionFactory级别的缓存

3、Session对象的缓存概述
    Session接口中,有一系列的java的集合,这些java集合构成了Session级别的缓存(以及缓存),将对象存入到一级缓存中,
    session没有结束生命周期,那么对象在session中存放着

    内存中包含session实例->Session的缓存(一些集合)->集合中包含的是缓存对象

4、证明一级缓存的存在,编写查询的代码即可证明
    在同一个session对象中查询两次,可以证明用了缓存

5、Hibernate框架是如何做到数据库发生包含时进行同步操作
    使用get方法查询User对象
    然后设置User对象的一个属性,注意:没有做update的操作 却发现数据库中的记录也改变了
    利用快照机制来完成的(SnapShot)

Session接口中与以及缓存相关的方法
    Session.clear()                清空缓存
    Session.evict(Object entiyty)  从一级缓存中清除指定的实体对象
    Session.flush()                刷出缓存

事务的概念
1、什么是事务
    事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全部成功,要么全部失败
    转账的 扣钱和加钱 两个操作组成了一个事情

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

3、如果不考虑隔离性,引发一些读的问题
    脏读          一个事务读到另一个事务未提交的数据
    不可重复读       一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致
    虚读          一个事务读到了另一个事务已经提交的insert数据,导致多次查询结果不一致

4、通过设置数据库的隔离级别来解决读的问题
    未提交读:以上的读的问题都有可能发生
    已提交读:避免脏读,但是不可重复读,虚读都有可能发生
    可重复读:避免脏读、不可重复读,但是虚读可能发生
    串行化:以上读的情况都可以避免

5、如果要在Hibernate的框架中设置隔离级别,需要在hibernate.cfg.xml的配置文件中通过标签来配置
    通过hibernate.connection.isolation = 4来配置
    取值
        1-Read uncommitted isolation
        2-Read committed isolation oracle默认
        4-Repeatable read isolation mysql默认
        8-Serializable isolation

丢失更新的问题
1、如果不考虑隔离性,也会产生写入数据的问题,这一类类的问题叫丢失更新的问题
2、例如:两个事务同时对某一条记录做修改,就会引发丢失更新的问题
    A事务和B事务同时获取到一条数据,同时再做修改
    如果A事务修改完成后,提交了事务
    B事务修改完成后,不管是提交还是回滚,如果不做处理,都会对数据产生影响

3、解决方案
    悲观锁
        才有的是数据库提供的一种锁机制,如果采用了这种机制,在SQL语句后面添加for update子句
            当A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的
            只有当A事务提交后,锁释放了,其他事务才能操作该条记录
    乐观锁
        采用版本号的机制来解决的,会给表结构添加一个字段version=0,默认值是0
            当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发现版本号的值相同时,才可以提交事务。同时会更新版本号version=1
            当B事务操作完该条记录,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误

4、使用Hibernate框架来解决丢失更新的问题
    悲观锁
        使用session.get(Customer.class,1.LockMode.UPGRADE)方法
    乐观锁
        1、在对应的JavaBean中添加一个属性,名称可以是任意的。例如:private Integer version ;提供get和set方法
        2、在映射的配置文件中,提供<version name="version"/>标签即可

绑定本地的Session
1、JavaWeb的事务,需要在业务层使用Connection来开启事务
    一种是通过参数的方式传递下去
    另一种是把Connection绑定到ThreadLocal对象中
2、现在的Hibernate框架中使用session对象来开启事务,所以需要传递session对象,框架提供了ThreadLocal的方式
    需要在hibernate.cfg.xml的配置文件中提供配置
        <property name="hibernate.current_session_context_class">thread</property>

    重新HibernateUtil工具类,使用SessionFactory的getCurrentSession()方法,获取当前Session对象,并且该session对象不用手动关闭。
    线程结束了,会自动关闭
        public static Session getCurrentSession(){
            return factory.getCurrentSession();
        }

        想使用getCurrentSession()方法,必须先配置才能使用

Query查询接口
1、具体的查询代码:
    //1、查询所有记录
    Query query = session.createQuery("from Customer");
    List<Customer> list = query.list();
    System.out.println(list);
    //2、条件查询
    Query query = session.createQuery("from Customer where name=?");
    query.setString(0,"l");
    List<Customer> list = query.list();
    System.out.println(list);
    //3、条件查询
    Query query = session.createQuery("from Customer where name = :aaa and age =:bbb");
    query.setString("aaa","run");
    query.setInteger("bbb",12);
    List<Customer> list = query.list();
    System.out.println(list);

Criteria(做条件查询非常合适)查询接口
1、具体的查询代码
    //1、查询所有记录
    Criteria criteria = session.createCriteria(Customer.class)
    List<Customer> list = criteria.list();
    syso(list)

    //2、条件查询
    Criteria criteria = session.crateCriteria(Customer.class)
    criteria.add(Restrictions.eq("name","abc"));
    List<Customer> list = criteria.list();
    syso(list);

    //3、条件查询
    Criteria criteria = session.createCriteria(Customer.class);
    criteria.add(Restrictions.eq("name","ll"));
    criteria.add(Restrictions.eq("age",11));
    List<Customer> list = criteria.list();
    syso(list); 

 hibernate.cfg.xml

<?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>
	<!-- 先配置sessionFactory标签 一个数据库对应一个sessionFactory标签 -->
	<session-factory>
		<!-- 必须配置的五个参数 -->
		<!-- 四大参数 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day01</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">123456</property>
		<!-- 数据库的方言 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

		<!-- 可选配置 -->
		<!-- 显示SQL语句 -->
		<property name="hibernate.show_sql">true</property>
		<!-- SQL语句格式化 -->
		<property name="hibernate.format_sql">true</property>

		<!-- 生成数据库的表结构<property name="hibernate.hbm2ddl.auto">create</property> -->

		<!-- 映射配置文件,需要引入映射的配置文件 -->
		<mapping resource="com/lingnet/domain/Customer.hbm.xml" />
	</session-factory>
</hibernate-configuration>

猜你喜欢

转载自blog.csdn.net/Entermomem/article/details/84286597