Hibernate学习第二天:主键生成策略--一级缓存--事务管理

1、持久化类的编写规则

1.1 什么是持久化类

1.1.1 持久化:将内存中的一个对象持久化到数据库中过程。Hibernate框架就是用来进行持久化的框架。
1.1.2 持久化类:一个java对象与数据库的表建立了映射关系,那么这个类在Hibernate中成为持久化类。

1.2 持久化类的编写规则

  • 对持久化类提供一个无参的构造
    • Hibernate的底层需要使用反射来生成实例。
  • 属性要私有,对私有属性提供public的set和get方法
    • Hibernate中获取,设置对象的值
  • 对持久化类提供一个唯一的标识OID与数据库主键对应
    • java中通过对象的地址来区分是否是同一个对象,数据库中通过主键来确定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
  • 持久化类中属性尽量使用包装类类型(Integer,Long,Double等等)
    • 因为基本数据类型默认值是0,那么0就会有很多歧义。包装类的默认是null。
  • 持久化类不要使用final进行修饰
    • 延迟加载本身是Hibernate一个优化的手段。最后返回的是一个代理对象(Javassist可以对没有实现接口的类产生代理-->使用了非常底层的字节码增强技术,继承这个类进行代理)。如果不能被继承,不能产生代理对象,延迟加载也就失效。load方法和get方法一致。

2、主键生成策略

2.1 主键的分类

2.1.1 自然主键

  • 主键的本身表中的一个字段(实体中的一个具体的属性)。
    • 创建一个人员表,人员都有一个身份证号码(唯一的不可重复的),使用了身份证号码作为主键,这种主键成为自然主键。

2.1.2 代理主键

  • 主键本身不是表中必须的字段(不是实体中的某个具体的属性)
    • 创建一个人员表,没有使用人员中的身份证号码,用了一个与这个表不相关的字段ID:(PNO).这种主键就成为代理主键。
  • 在实际开发中,尽量使用代理主键。
    • 一旦自然主键参与到业务逻辑中,后期可能需要修改源代码。
      • 好的程序的设计要满足OCP原则:对程序的扩展是open的,对修改源码是close的。

2.1.3 主键的生成策略(主要修改Customer.hbm.xml中generator即可)

  • 在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多种的主键的生成策略。
    • increment :Hibernate中提供的自动增长机制,适用short,int,long类型的主键。在单线程程序中适用。
    • identity :适用于short,int,long类型的主键,适用的是数据库底层的自动增长机制,适用于有自动增长机智的数据库(MySQL,MSSSQL...注意:Oracle没有自动增长机制)。
    • sequence :适用于short,int,long类型的主键,采用的是序列的方式,也是必须得序列的数据库(Oracle等,注意:MySQL不支持序列化,所以无法适用)。
    • UUID :适用于字符串类型的主键,使用hibernate中的随机方式生成字符串主键。
    • native :本地策略,可以在identity和sequence之间自动切换。
    • assigned :hibernate放弃外键的管理,需要通过手动编写程序或者用户自己设置。

3、持久化类的三种状态

3.1 三种状态

Hibernate是持久化层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理持久化类,将持久化类分成了三种状态。

3.1.1 瞬时态

  • 这种对象没有唯一的标识OID,没有被Session管理,称为是瞬时态对象。
    • 持久化类的持久态的对象,可以自动更新数据库。

3.1.2 持久态

  • 这种对象有唯一的标识OID,也被Session管理,称为持久态对象。

3.1.3 脱管态

  • 这种对象有唯一的标识OID,但没有被Session管理,称为脱管态对象。

3.2 区分三种状态对象

public void demo01() {
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();

    Customer  customer = new Customer();    //瞬时态对象:没有唯一标识OID,还没有被Session管理
    customer.setCust_name("萨拉伊丁");

    Serializable id = session.save(customer);   //持久态对象:有唯一标识OID,被Session管理

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

    System.out.println("客户的名称"+customer.getCust_name());//脱管态对象:有唯一的标识OID,但没有被Session管理
}

3.3 持久化类的状态转换

3.3.1 瞬时态对象

  • 获得
Customer customer = new Customer();
  • 状态转换
    • 瞬时态---->持久态
      • save(Object obj)
      • saveOrUpdate(Object obj)
    • 瞬时态---->脱管态
      • customer.setCust_id(1l);

3.3.2 持久态对象

  • 获得
    • get()
      • session.get(Customer.class,1l)
    • load()
    • find()
    • iterate()
  • 状态转换
    • 持久态--->瞬时态
      • delete()
    • 持久态--->脱管态
      • close()
        • session.close()
      • clear()

3.3.3 持久态对象

  • 获得
Customer customer = new Customer();customer.setCust_id(1l);
  • 状态转换
    • 脱管态--->持久态
      • update(Object obj)
      • saveOrUpdate(Object obj)
    • 脱管态--->瞬时态
      • custom.setCust_id(null);

3.3.4 持久态对象的特性

持久化类持久态对象自动更新数据库。

public void demo02() {
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();

    //获得持久态对象
    Customer customer = session.get(Customer.class, 1l);
    customer.setCust_name("musapir");   //如果传入的值跟数据库的一样,就不发update()请求语句,不一样就发update()
    //session.update(customer); //不用写也能更新数据库,因为持久态对象有自动更新数据库的特性

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

4、Hibernate的一级缓存

4.1 什么是缓存

缓存:是一种优化的方式,将数据载入到内存中,使用的时候直接从缓存中获取,不用通过存储源获取。

4.2 Hibernate的缓存

4.2.1 Hibernate的一级缓存

Hibernate框架中提供了优化手段:缓存、抓取策略。Hibernate中提供了两种缓存机制:一级缓存、二级缓存。 
Hibernate的一级缓存:称为Session级别的缓存,一级缓存生命周期与Session一致(一级缓存是由Session中的一系列的Java集合构成)。一级缓存是自带的不可卸载的。(Hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存)。

4.2.2 证明一级缓存的存在

public void demo01() {
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();

    /*
     * Customer customer1 = session.get(Customer.class, 1l); //发送SQL语句
     * System.out.println(customer1);
     * 
     * Customer customer2 = session.get(Customer.class, 1l); //不发送SQL语句 ,从缓存里面获取
     * System.out.println(customer2);
     * 
     * System.out.println(customer1==customer2);
     */

    Customer customer = new Customer();
    customer.setCust_name("Muhammad");
    Serializable id = session.save(customer);   //发送SQL语句
    Customer customer2 = session.get(Customer.class, id);//不发送SQL语句(在保存操作时就把数据缓存到内存中,再次查询就直接从缓存中获取数据)
    System.out.println(customer2);

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

4.3 Hibernate的一级缓存的结构

4.3.1 一级缓存中特殊区域:快照区

public void demo02() {
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.beginTransaction();

    Customer customer = session.get(Customer.class, 1l);//发送SQL语句查询,同时将查询结果放入到一级缓存当中,然后把结果进行快照,放到一个map集合中
    customer.setCust_name("张三");    //当数据变化的时候,会修改一级缓存中的数据,快照区的数据不会发生变化

    transaction.commit();   //当提交事务的时候,会将一级缓存中的数据与快照区的数据进行比较,如果数据相同,则不发送SQL语句,如果有变化,就发送SQL语句更新数据
    session.close();
}

持久态对象之所以能自动更新数据库,就是因为有了快照区,能够进行判断数据有没有变化。

5.Hibernate的事务管理

5.1 事务的回顾

5.1.1 什么是事务

事务:指的是逻辑上的一组操作,组成这组操作的各个逻辑但愿要么全都成功,要么全都失败。

5.1.2 事务的特性

  • 原子性 :代表事务不可分割
  • 一致性 :代报事务执行的前后,数据的完整性保持一致。
  • 持久性 :代表事务执行完成后,数据就持久到数据库中。
  • 隔离性 :代表一个事务执行的过程中,不应该受到其他事务的干扰。

5.1.3 如果不考虑隔离性,引发安全性问题

  • 读问题
    • 脏读 :一个事务读到另一个事务为提交的数据
    • 不可重复读 :一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致。
    • 虚读 :一个事务读到另一个事务提交的insert的数据,导致在前一个事务多次查询结果不一致。
  • 写问题
    • 引发两类丢失更新

5.1.4 读问题的解决

  • 设置事务的隔离级别
    • read uncommitted :以上的读问题都会发生
    • read committed :可以解决脏读,但是不可重复读和虚读有可能会发生
    • repeatable read :解决脏读和不可重复读,但虚读可能会发生
    • serializable :解决所有读问题

5.2Hibernate中设置事务的隔离级别

在核心配置文件hibernate.cfg.xml中设置隔离级别

<!-- 设置事务隔离级别 -->
<property name="hibernate.connection.isolation">4</property>

5.3 Service 层事务

5.3.1 Hibernate解决service的事务管理

  1. 改写工具类

    public Session getCurrentSession() {
        return sf.getCurrentSession();
    }
    
  2. 改写核心配置文件

    <!-- 配置当前线程绑定的Session -->
    <property name="hibernate.current_session_context_class">thread</property>
    
  3. 测试

public void demo01() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    Customer customer = session.get(Customer.class, 1l);
    customer.setCust_name("李四");

    session.save(customer);
    System.out.println(customer);
    transaction.commit();
    //不能关闭session,不然就会报错
}

6、Hibernate的其他API

6.1 Query

  • Query接口用于接收HSQL,查询多个对象。

    • HQL:Hibernate Query Language,Hibernate查询语言,这种语言与SQL的语法及其类似,面向对象的查询语言。

 public  void demo01() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //简单查询
    //String hql = "from Customer";

    //条件查询
    //String hql = "from Customer where cust_name like ?";//低版本中这么写,新版本中找如下写,不然会报错
    //String hql = "from Customer where cust_name like ?0";
    //分页查询
    String hql = "from Customer";
    //通过Session 获得Query接口
    Query query = session.createQuery(hql);
    //query.setParameter(0, "m%");
    //设置分页
    query.setFirstResult(0);    //从第几条开始
    query.setMaxResults(2); //每页显示数据条数
    List<Customer> list = query.list();
    for (Customer customer : list) {
        System.out.println(customer);
    }
    transaction.commit();
}

6.2 Criteria

criteria:QBC(Query By Criteria)

  • 更加面向对象的一种查询方法

 public  void demo02() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //通过Session获得Criteria的对象
    /*
     * Criteria criteria = session.createCriteria(Customer.class); List<Customer>
     * list = criteria.list();
     */

    Criteria criteria = session.createCriteria(Customer.class);
    criteria.add(Restrictions.like("cust_name", "m",MatchMode.ANYWHERE));//第三个参数是查询类型,也可以不写,第二个参数中直接用%
    //分页
    criteria.setFirstResult(0);
    criteria.setMaxResults(2);
    List<Customer> list = criteria.list();
    for (Customer customer : list) {
        System.out.println(customer);
    }

    transaction.commit();
}

6.3 SQLQuery

  • 用于接收SQL语句,特别复杂情况下使用SQL。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值