• Hibernate系列之ID生成策略


    一、概述

      hibernate中使用两种方式实现主键生成策略,分别是XML生成id和注解方式(@GeneratedValue),下面逐一进行总结。

    二、XML配置方法

      这种方式是在XX.hbm.xml文件中对generator进行配置,eg:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.test.demo">
    
        <class name="Student">
            <id name="id">
                <generator class="native"></generator>
            </id>
            <property name="name"></property>
            <property name="age"></property>
        </class>
    </hibernate-mapping>

      常用的生成策略有以下几种:

      identity:对DB2,Mysql,MS SQL Server等的内置标识字段提供支持,返回的标识符是long,short或者int类型

      native:可以是identity类型、sequence类型或者hilo类型,取决于不同的底层数据库

      sequence:在Oracle,SAP DB中使用序列(sequence)

      uuid:使用一种128位的UUID算法产生的字符类型标识,像IP地址一样全网唯一

    三、注解方式生成ID:@GeneratorValue

      标准的annotation方式的主键生成策略如下:

    • AUTO:可以是identity类型或者是sequence类型或者是table类型,取决于底层的数据库
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    
    @Entity
    public class Person
    {
        private String name;
        private int age;
        private int id;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
    }
    View Code
    • TABLE:使用表保存id值,即会为应用的表创建一张专门保存id的表
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.TableGenerator;
    
    @Entity
    public class Person
    {
        private String name;
        private int age;
        private int id;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        @Id
        @TableGenerator(name="personID",table="personID_DB",pkColumnName="key_value",pkColumnValue="pk_value",valueColumnName="person",allocationSize=1)
        @GeneratedValue(strategy=GenerationType.TABLE,generator="personID")
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
    }
    View Code
    • IDENTITY:identity column
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.TableGenerator;
    
    @Entity
    public class Person
    {
        private String name;
        private int age;
        private int id;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        @Id
        
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
    }
    View Code
    • SEQUENCE:sequence

    四、联合主键生成策略

      有的时候我们需要将一个实体的2个或多个字段联合起来作为主键,就是说,不能有2个或多个对象的这几个字段值都相同的情况发生。现在我们要将Person字段的id和name字段联合作为主键:

    @Entity
    public class Person
    {
        //现在id和name组成联合主键
        private int id;
        private String name;
        private int age;
        ...
    }
    1. 首先将联合主键的属性提取出来,重新编写一个pojo类(原pojo类中的id,name要删除 并新加入属性“PersonPK”)
    2. 新建pojo类必须实现 java.io.Serializable 序列化接口
    3. 新pojo类要重写equals和hashCode方法
    public class PersonPK implements Serializable
    {
        private String name;
        private int id;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
        @Override
        public int hashCode()
        {
            return this.name.hashCode();
        }
        @Override
        public boolean equals(Object obj)
        {
            if(obj instanceof PersonPK) {
                PersonPK pk = (PersonPK)obj;
                if(this.id == pk.getId() && this.name.equals(pk.getName())) {
                  return true;
                }
            }
            return false;
    
        }
    }

       联合主键生成策略XML配置方法:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.test.demo">
    
        <class name="Person">
            <composite-id name="personPK" class="com.test.demo.PersonPK">
                    <key-property name="id"></key-property>
                    <key-property name="name"></key-property>
                </composite-id>
                <property name="age" />    
        </class>
    </hibernate-mapping>

      联合主键ID生成策略的Annotation版本,共有三种方式,前三步骤一样,另外:

      方法1、在新类PersonPK前写@Embeddable,在原Person类的新属性PersonPK的get方法前写@id

    @Embeddable
    public class PersonPK implements Serializable
    {
        private static final long serialVersionUID = -7068850328521576106L;
        private String name;
        private int id;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
        @Override
        public int hashCode()
        {
            return this.name.hashCode();
        }
        @Override
        public boolean equals(Object obj)
        {
            if(obj instanceof PersonPK) {
                PersonPK pk = (PersonPK)obj;
                if(this.id == pk.getId() && this.name.equals(pk.getName())) {
                  return true;
                }
            }
            return false;
    
        }
    }

      Person类中:

    @Entity
    public class Person
    {
        private PersonPK personPK;
        private int age;
        
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        @Id
        public PersonPK getPersonPK()
        {
            return personPK;
        }
        public void setPersonPK(PersonPK personPK)
        {
            this.personPK = personPK;
        }
    }

       方法2、新类无需添加注解,只需在原类Person新属性PersonPK的get方法前写@EmbeddID即可

    @Entity
    public class Person
    {
        private PersonPK personPK;
        private int age;
        
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        @EmbeddedId
        public PersonPK getPersonPK()
        {
            return personPK;
        }
        public void setPersonPK(PersonPK personPK)
        {
            this.personPK = personPK;
        }
    }

      方法3、新pojo类无需加注解,原pojo类的id,name属性保留不变,也无需新增“TercherPK”属性。 只在id,name的get方法前都加@Id,并在原pojo类前加@IdClass(PersonPK.class):

      原类Person:

    @Entity
    @IdClass(PersonPK.class)
    public class Person
    {
        private int age;
        private String name;
        private int id;
        @Id
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        @Id
        public int getId()
        {
            return id;
        }
        public void setId(int id)
        {
            this.id = id;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
    }

      运行测试程序(针对上述三种方法,测试用例需要稍作修改,这里不在赘述):

    public class PersonTest
    {
        private static SessionFactory sf=null;
        @BeforeClass
        public static void beforeClass()
        {
            sf=new AnnotationConfiguration().configure().buildSessionFactory();
        }
        @Test
        public void test()
        {
            PersonPK personPK=new PersonPK();
            personPK.setId(1);
            personPK.setName("xujian");
            Person p=new Person();
            p.setAge(23);
            p.setPersonPK(personPK);
            Session session=sf.openSession();
            session.beginTransaction();
            session.save(p);
            //提交事物
            session.getTransaction().commit();
            session.close();
            sf.close();
        }
        @AfterClass
        public static void afterClass()
        {
            sf.close();
        }
    }

      可以看到:

      生成的Person表中id和name组成联合主键

      

      

      

      

      

      

  • 相关阅读:
    android学习地址
    Android获取屏幕高度、标题高度、状态栏高度详解
    学习地址(杂)
    获取控制台应用程序自己的文件名
    学习地址
    如何分配数据库角色权限
    android 近百个源码项目
    深入理解默认构造函数
    深入理解拷贝构造函数
    读权限和执行权限的差别
  • 原文地址:https://www.cnblogs.com/xujian2014/p/4799415.html
Copyright © 2020-2023  润新知