zoukankan      html  css  js  c++  java
  • hibernate主键生成策略,一级缓存,一对多关系配置

    hibernate持久化类

      Persistent Object  (PO) PO=POJO+hbm映射配置

    对于hibernate中的PO编写规则:

      1.必须提供一个无参数的public构造方法
      2.所有属性要private,对外提供public的get/set方法
      3.在PO类必须提供一个标识属性,让它与数据库中的主键对应,我们叫OID
      4.PO类中的属性尽量使用基本数据类型的包装类
      5.PO类它不能使用final修饰

    OID的作用:

      OID指的是与数据库中标的主键对应的属性
      hibernate框架它是通过OID来区分不同的PO对象,如果在内存中有相同的OID,那么hibernate认为它是同一个对象

    PO类使用包装类型:

      使用基本数据类型是没有办法去描述不存在概念,如果使用包装类型,它就是一个对象,对于对象它的默认值是null.

    get和load的区别

      get直接得到了一个持久化类型对象,它就是立即查询操作
      load它得到的是持久化类开的代理类型对象(子类对象)。它采用了一种延迟策略来查询数据。

      


      get方法在查询时,如果不存在返回null
      load方法在查询时,如果 不存在,会产生异常ObjectNotFoundException.
      所以不可以使用final修饰

    Hibernate主键生成策略

      自然主键:具有业务含义 字段 作为主键,比如:学号、身份证号
      代理主键:不具有业务含义 字段作为主键(例如 自增id),比如:mysql自增主键,oracle序列生成的主键、uuid()方法生成的唯一序列串

      increment:代理主键。由hibernate维护一个变量,每次生成主键时自动以递增。
      问题:如果有多个应用访问一个数据库,由于每个应用维护自己的主键,所以此时主键可能冲突。建议不采用。
      优点:可以方便跨平台
      缺点:不适合高并发访问

      identity:代理主键。由底层数据库生成表识符。条件是数据库支持自动增长数据类型。比如:mysql的自增主键,oracle不支持主键自动生成。
      如果数据库支持自增建议采用。
      优点:由底层数据库维护,和hibernate无关
      缺点:只能对支持自动增长的数据库有效,例如mysql

      sequence:代理主键。Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。比如oracle的序列。
      如果数据库支持序列建议采用。
      优点:由底层数据库维护,和hibernate无关
      缺点:数据库必须支持sequence方案例如oracle

      native:代理主键。根据底层数据库对自动来选择identity、sequence、hilo
      由于生成主键策略的控制权由hibernate控制,所以不建议采用。
      优点:在项目中如果存在多个数据库时使用
      缺点:效率比较低

      uuid:代理主键。Hibernate采用128bit位的UUID算法来生成标识符。该算法

    能够在网络环境中生成唯一的字符串标识符。

      此策略可以保证生成主键的唯一性,并且提供了最好的数据库插入性能和数据库平台的无关性。建议采用。
      优点:与数据库无关,方便数据库移植,效率高,不访问数据库就可以直接生成主键值,并且它能保证唯一性。
      缺点:uuid长度大(32位),占用空间比较大,对应数据库中类型 char varchar

      assigned:自然主键。由java程序负责生成标识符。

      不建议采用。

      尽量在操作中避免手动对主键操作

    Hibernate持久化对象状态(具有自动更新数据库的能力)

      1. 瞬时态:也叫做临时态或自由态,它一般指我们new出来的对象,它不存在OID,与hibernate session无关联,在数据库中也无记录。它使用完成后,会被jvm直接回收掉,它只是用于信息携带。
    简单说:无OID 与数据库中的信息无关联,不在session管理范围内。

      2. 持久态:在hibernate session管理范围内,它具有持久化标识OID它的特点,在事务未提交前一直是持久态,当它发生改变时,hibernate是可以检测到的。

      3. 托管态:也叫做游离态或离线态,它是指持久态对象失去了与session的关联,托管态对象它存在OID,在数据库中有可能存在,也有可能不存在。
    对于托管态对象,它发生改变时hibernet不能检测到。

    Hibernate一级缓存

      Hibernate的一级缓存就是指session缓存

      在session中定义了一系列的集合来存储数据,它们构成session缓存。
      只要session没有关闭,它就会一直存在。
      当我们通过hibernate中的session提供的一些API例如 save get update等进行操作时,就会将持久化对象保存到session中,当下一次在去查询缓存中具有的对象(OID值来判断),
    就不会去从数据库查询,而是直接从缓存中获取。
      Hibernate的一级缓存存在的目的就是为了减少对数据库访问。

      在hibernate中还有一个二级缓存,它是SessionFactory级别缓存。

    一级缓存特点:

      1. 当我们通过session的save,update saveOrupdate进行操作时,如果一级缓存中没有对象,会将这些对象从数据库中查询到,存储到一级缓存。

      2. 当我们通过session的load,get,Query的list等方法进行操作时,会先判断一级缓存中是否存在,如果没有才会从数据库获取,并且将查询的数据存储到一级缓存中。

      3. 当调用session的close方法时,session缓存清空。

      clear 清空一级缓存.
      evict 清空一级缓存中指定的一个对象。
      refresh重新查询数据库,用数据库中信息来更新一级缓存与快照

    Hibernate关联映射--数据对象三种关系

      数据库中表与表之间存在着三种关系,也就是系统设计中的三种实体关系

    一对一:

    1. 唯一外键对应:在任意一方添加外键来描述对应关系
    2. 主键对应:一方的主键作为另一方的主键

    一对多(多对一):

    客户与订单之间一对多关系(多对一)
    建表原则:在多的一方添加外键来描述关联关系

    多对多:

    例如学生与老师
    建表原则:通过一张中间表来描述其对应关系

    下面举个一对多的例子

    public class Customer {
        
        private Integer id;
        private String name;
        //描述一个客户可以有多个订单
        private Set<Order> orders = new HashSet<>();
        public Customer(Integer id, String name, Set<Order> orders) {
            super();
            this.id = id;
            this.name = name;
            this.orders = orders;
        }
        public Customer() {
            super();
            // TODO Auto-generated constructor stub
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Set<Order> getOrders() {
            return orders;
        }
        public void setOrders(Set<Order> orders) {
            this.orders = orders;
        }
        @Override
        public String toString() {
            return "Customer [id=" + id + ", name=" + name + ", orders=" + orders + "]";
        }
        
    }
    public class Order {
        private Integer id;
        private String name;
        
        private Customer customer;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Customer getCustomer() {
            return customer;
        }
    
        public void setCustomer(Customer customer) {
            this.customer = customer;
        }
        
        
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        <hibernate-mapping package="com.learn.domain">
            <class name="Order" table="t_order">
                <id name="id" column="o_id">
                    <generator class="identity"></generator>
                </id>
                <property name="name" column="c_name"></property>
                <!-- 多对一 -->
                <!-- 
                    name属性是order类的一的一方的属性名称
                    class代表一的一方的类型
                    column描述多的一方的外键名称
                 -->
                <many-to-one name="customer" class="Customer" column="c_customer_id">
                    <!-- <column name="c_customer_id"></column> -->
                </many-to-one>
            </class>
        </hibernate-mapping>
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        <hibernate-mapping package="com.learn.domain">
            <class name="Customer" table="t_customer">
                <id name="id" column="c_id">
                    <generator class="identity"></generator>
                </id>
                <property name="name" column="c_name"></property>
                <!-- 一个客户有多个订单 -->
                <!-- 
                    set来表示一的一方关联多的一方
                    name就是set集合的名称
                    key:与多的一方的外键一致
                    one-to-many:描述集合类型
                 -->
                <set name="orders">
                    <key column="c_customer_id"/>
                    <one-to-many class="Order"/>
                </set>
            </class>
        </hibernate-mapping>

    当执行了下面的测试代码就会在数据库中创建一对多的表

        @Test
        public void test() {
            //获得session
            Session session = HibernateUtils.openSession();
            //打开事物
            session.beginTransaction();
            
            Customer c = new Customer();
            
            c.setName("张三");
            //保存对象
            session.save(c);
            //事物提交
            session.getTransaction().commit();
            session.close();
        }

    当然,这个测试只是单向操作,在执行多项操作时我们需要保存订单的同时还保存客户,那么可以只保存订单或客户就完成操作吗

    这是程序会报错:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.itheima.oneToMany.Customer

    测试单向关联保存:

      这表示一个持久化对象关联了一个瞬时对象
      我们可以使用级联操作来解决上述的问题.
      只需在hbm配置文件中配置:
      cascade="save-update"(两个hbm都需要配置)

    双向关联维护: 

      我们在开发中要配置双向关联配置。---------可以通过任意一方来操作对方
      在操作代码,尽量来要进行单向关联。------可以尽量资源浪费。
      我们可以使用inverse属性来设置,双向关联时由哪一方来维护表与表之间的关系。
      Inverse它的值如果为true代表,由对方来维护外键。
      Inverse它的值如果为false代表,由本方来维护外键。

    关于inverse的取值:

      外键在哪一个表中,我们就让哪一方来维护外键。

                <set name="orders" inverse="true">
                    <key column="c_customer_id"/>
                    <one-to-many class="Order"/>
                </set>    

    级联删除:

      我们在删除客户时,也要删除订单,如果没有做级联,那么这个操作是不允许。

    为了维护数据完整性想要完成操作:我们可以在客户中添加cascade=”delete”;

    对于cascade:

      none这是一个默认值
      save-update,当我们配置它时,底层使用save update或save-update完成操作,级联保存临时对象,如果是游离对象,会执行update.
      delete 级联删除
      delete-ophan 删除与当前对象解除关系的对象。
      all 它包含了save-update delete操作
      all-delete-orphan 它包信了delete-orphan与all操作

  • 相关阅读:
    1434. Buses in Vasyuki 夜
    SAP
    目标
    组合数
    KM算法模板
    网络流
    CodeForces 43E
    B. Unsorting Array codeforces 127
    Colorful Rainbows 127
    C. Anagram codeforces
  • 原文地址:https://www.cnblogs.com/learnjfm/p/7111087.html
Copyright © 2011-2022 走看看