ID生成策略(一)

摘要:
这被称为ID生成策略。Identity支持DB2、MySQL、MSSQLServer、Sybase和Hypersonic SQL的内置标识字段。Sequence在DB2、PostgreSQL、Oracle、SAPDB和McKoi中使用序列,而在Interbase中使用生成器。单独编写一个课程,作为学生的主要关键课程StudentPK Java。在主键类中,必须重写equals和hashCode方法以实现可串行化接口(为什么?另一种情况是,当内存已满时,可以使用虚拟内存。在这种情况下,可以将串行化内容临时放在硬盘上。

ID生成策略:主键手工设定很不方便,在我们实际工作中在MySQL里面用自增字段auto increment,在oracel中一般用sequence。所以把表建成auto increment,对于类里面对象的对应的值就不能指定了,得靠程序或数据库自动生成,hibernate或JPA就实现了这样的功能,我们可以通过设置告诉这个字段怎么生成,这样写程序的时候就不用设定了。这个就叫ID的生成策略。

动手实验:

使用xml时,常用<generator class="native"></generator>

native

根据底层数据库的能力选择identity, sequence 或者hilo中的一个。

identity

对DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的内置标识字段提供支持。 返回的标识符是long, short 或者int类型的。

sequence

在DB2,PostgreSQL, Oracle, SAP DB, McKoi中使用序列(sequence), 而在Interbase中使用生成器(generator)。返回的标识符是long, short或者 int类型的。

 使用annotation,使用注解@GeneratedValue默认值是auto相当于xml里面的native 

  @SequenceGenerator(name="teacherSEQ", sequenceName="teacherSEQ_DB")

  @GeneratedValue(strategy=GenerationType.SEQUENCE)

  @TableGenerator

  

联合主键:假设sutdent的id和name是它的主键。单独写一个类作为学生的主键类StudentPK.java,在主键类里面必须要重写equals、hashCode方法,实现serializable接口(为什么?),serializable把当前对象序列化,这样就可以直接写到硬盘上,也可以直接读出来,也可以直接传送。为什么要序列化呢?作为Student这个对象来说,它在数据库表里可能存在多条记录,如果把这多条记录放到内存里就是多个Student对象,每个对象都有一个主键StudentPK对象。系统做集群,好多个服务器,如果这台服务器当机了,可以把这台服务器里的对象传给另外一台服务器,就需要实现序列化,但是这种情况并不多见。还有一种情况,加入内存满了,可以使用虚拟内存(把硬盘上一块空间作为内存使用)。这种情况下就可以把序列化了的那一部分内容先暂时放到硬盘上去。主键类为什么要重写equals和hashCode呢?是为了保证唯一性,不仅 在数据库中保证唯一性,我们还要把数据放到内存中,好多student对象,里面都有自己的studentpK,那么每个对象之间怎么区分开来?数据库里面用主键做区分,那么内存里面也应该用这种逻辑来做区分,不然和数据库内容就不匹配了,所以用联合主键就应该重写equals和hashCode。从数据库的角度想,主键相同就返回true,从内存角度想主键相同就是id和name相同。为什么重写hashCode呢?如果我们的对象装到了hash表里面,查找里面的对象,首先是查找hashcode。所以最终代码如下:

package hjj.lch.hibernate.model;

import java.io.Serializable;

public class StudentPK implements Serializable{
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj){
        if(obj instanceof StudentPK){
            StudentPK pk = (StudentPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName())){
                return true;
            }
        }
        return false;
    }
    
    @Override
    public int hashCode(){
        return this.name.hashCode();
    }
}

在Student.java里面就不用写id和name了,但是需要记录一个主键类的对象,这样才能唯一的记录当前的student。

package hjj.lch.hibernate.model;

public class Student {

    private StudentPK pk;
    private int age; // 年龄
    
    public StudentPK getPk() {
        return pk;
    }
    public void setPk(StudentPK pk) {
        this.pk = pk;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}


配置文件里面表名主键,组件作为联合标志符

<?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>

    <!-- 以下是表的映射, 此处若不写 table="student" ,
         则表示实体类名字和表名一样,数据库表名捕区分大小写-->
    <class name="hjj.lch.hibernate.model.Student">
    
    <!-- 以下为字段的映射 -->
        <composite-id name="pk" class="hjj.lch.hibernate.model.StudentPK">
            <key-property name="id"></key-property>
            <key-property name="name"  length="16"></key-property>
        </composite-id>
        <!-- 普通属性 -->
        <property name="age"></property>
    </class>
</hibernate-mapping>

一开始利用HibernateExportUtil在控制台生成的建表语句在Mysql Commend Client中执行,会出现以下错误

Specified key was too long; max key length is 767 bytes。意思就是主键太长了.解决办法在student.hbm.xml文件中设置那两个字段的长度,所以加了length="16"。

下面说annotation的联合主键用法,将主键类TeacherPK.java注为@Embeddable,并且把主键的属性注解为@Id

package hjj.lch.hibernate.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class TeacherPK implements Serializable{
    
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(name="name", length=16)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public boolean equals(Object obj){
        if(obj instanceof TeacherPK){
            TeacherPK pk = (TeacherPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName()));
            return true;
        }
        return false;
    }
    
    @Override
    public int hashCode(){
        return this.name.hashCode();
    }

}

报错Specified key was too long; max key length is 767 bytes的时候限制字段长度就好, @Column(name="name", length=16)

package hjj.lch.hibernate.model;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Teacher {
    
    private TeacherPK pk;
    private String title; // 职称
    
    @Id
    public TeacherPK getPk() {
        return pk;
    }
    public void setPk(TeacherPK pk) {
        this.pk = pk;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

这是第一种方法,下面做第二种方法是在Teacher.java中将teacherpk组件注解为@EmbeddedId。TeacherPK.java中就不用注解了

package hjj.lch.hibernate.model;

import java.io.Serializable;

import javax.persistence.Column;

public class TeacherPK implements Serializable{
    
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(name="name", length=16)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public boolean equals(Object obj){
        if(obj instanceof TeacherPK){
            TeacherPK pk = (TeacherPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName()));
            return true;
        }
        return false;
    }
    
    @Override
    public int hashCode(){
        return this.name.hashCode();
    }

}
package hjj.lch.hibernate.model;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

@Entity
public class Teacher {
    
    private TeacherPK pk;
    private String title; // 职称
    
    @EmbeddedId
    public TeacherPK getPk() {
        return pk;
    }
    public void setPk(TeacherPK pk) {
        this.pk = pk;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

再做第三种将类注解为@IdClass,并将该实体类中所有属于主键的属性都注解为@Id,TeacherPK.java里面就不用写那些了。

package hjj.lch.hibernate.model;

import java.io.Serializable;

import javax.persistence.Column;

public class TeacherPK implements Serializable{
    
    private int id;
    private String name;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(name="name", length=16)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public boolean equals(Object obj){
        if(obj instanceof TeacherPK){
            TeacherPK pk = (TeacherPK)obj;
            if(this.id == pk.getId() && this.name.equals(pk.getName()));
            return true;
        }
        return false;
    }
    
    @Override
    public int hashCode(){
        return this.name.hashCode();
    }

}
package hjj.lch.hibernate.model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;

@Entity
@IdClass(TeacherPK.class)
public class Teacher {
    
    private int id;
    private String name;
    private String title; // 职称
    
    @Id
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Id
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

第二种和第三种比较常用,但是联合主键就不常用!!!哈哈

免责声明:文章转载自《ID生成策略(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇unity创建Android原生插件Bootstrap Table 中文文档(完整翻译版)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

k8s的yaml说明

理解k8s里的几个概念 Kubernetes 通过各种 Controller 来管理 Pod 的生命周期。为了满足不同业务场景,Kubernetes 开发了 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等多种 Controller。最常用的 Deployment用来建立Pod,以下是它的步骤 kube...

Java 注解入门

1.什么是注解 注解的语法: @注解名称; 注解的作用: 用来替代 xml 配置文件; 在 Servlet 3.0 中就可以使用注解来代替配置文件; 注解是由框架来读取使用的; 所有的注解都是 Annotation 的子类; 简单说, 注解是给程序(框架)看到, 而注释是给人看的. 2. 注解的使用 定义注解类: 框架的工作; 语法: public...

Equinox OSGi系列之 创建自己的OSGi应用项目

1、摘要 前述文档我向大家展示了Equinox OSGi环境及其搭建配置。从本文开始,我们将详细讨论Bundle的开发及OSGi应用构建。 2、OSGi相关概念 在正式进入Bundle的设计与开发之前,我们先来熟悉一下OSGi框架中的一些概念。用户在设计Bundle时必须要深入理解这些实体概念。 实体概念 实体概念说明 Bundle - 安装到OS...

C# 将内存中的datatable数据导出为Excel(方法二,创建Excel对象导出)【转载】

上次写了一个用文件流方式将Datatable导出Excel的方法,这个方法有局限性,比如没法对Excel进行一些增加列颜色等简单的操作,现在,给大家介绍另外一种方法,用微软的Excel类。既然要用到类,那必须是你的机子要装上Excel才行呢。 public void DataTabletoExcel(System.Data.DataTable[] tmp...

解析数据库连接字符串 (将Data Source、Initial Catalog、User ID、Password取出)

private void AnalysisConnectionstring() { string tempStr = “Data Source=192.168.2.123;Initial Catalog=caxastat;Persist Security Info=True;User ID=sa;Passwor...

Java中获取当前路径

1. 获取当前路径(绝对路径) package p01; import java.io.File; import java.io.IOException; import java.net.URL; public class Hello01 { public static void main(String[] args) { S...