1.关系数据库按主键区分不同的记录
1.1.把主键定义为自动增长标识符类型
eg . MySql中,把表的主键设为auto_increment类型:
create table CUSTOMERS(ID int auto_increment primary key not null,NAME varchar(15))
MS SQL Server中,把表的主键设为identity类型:
create table CUSTOMERS(ID int identity(1,1) primary key not null,NAME varchar(15))
1.2.从序列(Sequence)中获取自动增长的标识符
eg. Oracle数据库中,为表的主键创建一个单独的序列,从序列中获得自动增长的标识符,赋值给主键:
create sequence CUSTOMER_ID_SEQ increment by 1 start with 1;
create table CUSTOMERS(ID int primary key not null,NAME varchar(15));
insert into CUSTOMERS valus(CUSTOMER_ID_SEQ.curval,'Tom');
insert into CUSTOMERS valus(CUSTOMER_ID_SEQ.nextval,'Mike');
2.Java按内存地址区分不同的对象
"=="运算符就是比较的内存地址,在Object类中定义的equals(Object o)方法,也是按内存地址进行比较的。
Java API中的一些类覆盖了Object;类的equals(Object o)方法,实现按值比较,这些类包括:String类和Date类;Java包装类:Byte、Integer、Short、Character、Long、Float、Double和Boolean。
3.Hibernate用对象标识符(OID)来区分对象
OID是关系数据库的主键在Java对象模型中的等价物。
在对象-关系映射文件中,<id>元素用来设置对象标识符,<generator>子元素用来设定标识符生成器:
<id name="id" type="long" column="ID">
<generator class="increment" />
</id>
Hibernate提供的内置标识符生成器:
increment:适用于代理主键。由Hibernate自动以递增的方式生成标识符,每次增量为1。
identity:适用于代理主键。由底层数据库生成标识符,前提条件是递增数据库支持自动增长字段类型,如DB2、MySQL、MS SQL Server、Sybase和HypersonicSQL。
sequence:适用于代理主键。Hibernate根据底层数据库的序列来生成标识符,前提条件是底层数据库支持序列,如DB2、PostgreSQL、Oracle和SAP DB。
hilo:适用于代理主键。Hibernate根据high/low算法来生成标识符,Hibernate把特定表的字段作为"high"值,在默认情况下选用hibernate_unique_key表的next_hi字段。
native:适用于代理主键。根据底层数据库对自动生成标识符的支持能力,来选择identity、sequence或hilo。
uuid.hex:适用于代理主键。Hibernate采用128位的UUID(Universal Unique Identification)算法来生成标识符。UUID算法能够在网络环境中生成唯一的字符串标识符。
assigned:适用于自然主键。由Java应用程序辅助生成标识符,为了能让Java应用程序设置OID,不能把setID()声明为private类型。
select:适用于遗留数据库中的代理主键或自然主键。由数据库中的触发器来生成标识符。
foreign:用另一个关联的对象的标识符来作为当前对象的标识符,主要适用于一对一关联的场合。
4.Hibernate内置标识符生成器的用法
4.1.increment
不依赖底层数据库系统,适用于所有的数据库系统。
适用于只有单个Hibernate应用进程访问用一个数据库的场合,集群环境下不推荐使用。
<id name="id" type="long" column="ID">
<generator class="increment" />
</id>
4.2.identity
要求底层数据库必须支持自动增长类型。OID必须为long、int或short类型。
<id name="id" type="long" column="ID">
<generator class="identity" />
</id>
MySQL:
create table CUSTOMERS(ID bigint auto_increment primary key not null);
MS SQL Server:
create table CUSTOMERS(ID bigint identity primary key not null);
4.3.sequence
要求底层数据库必须支持序列。OID必须为long、int或short类型。
<id name="id" type="long" column="ID">
<generator class="sequence">
<param name="sequence">CUSTOMER_ID_SEQ</param>
</generator>
</id>
Oracle:
create sequence CUSTOMER_ID_SEQ;
create table CUSTOMERS(ID bigint primary key not null);
4.4.hilo
不依赖底层数据库系统,适用于所有的数据库系统。OID必须为long、int或short类型。
high/low算法生成的标识符只能在一个数据中保持唯一。
当用户为Hibernate自行提供数据库连接,或HIbernate通过JTA从应用服务器的数据源获得数据库连接时无法使用hilo。
<id name="id" type="long" column="ID">
<generator class="hilo">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
create table CUSTOMERS(ID bigint primary key not null);
create table hi_value(next_value integer);
4.5.native
能够根据底层数据库系统的类型,自动选择合适的标识符生成器,很适合于跨数据平台开发。
OID必须为long、int或short类型。
<id name="id" type="long" column="ID">
<generator class="native" />
</id>
MySQL:
create table CUSTOMERS(ID bigint auto_increment primary key not null);
MS SQL Server:
create table CUSTOMERS(ID bigint identity primary key not null);
5.映射自然主键
5.1.映射单个自然主键
eg. CUSTOMERS表中没有定义ID代理主键,而是以NAME字段作为主键,则在Customer类中不必定义id属性,Customer的OID为name属性,映射文件为:
<id name="name" column="NAME" type="string">
<generator class="assigmed" />
</id>
...
<version name="version" column="VERSION" unsaved-value="null" />
5.2.映射符合自然主键
eg. CUSTOMERS表中没有定义ID代理主键,而是以NAME字段和COMPANY_ID字段作为复合主键,则在Customer类中不必定义id属性,Customer的OID为name属性和companyId属性,映射文件为:
<composite-id>
<key-property name="name" column="NAME" type="string" />
<kry-property name="companyId" column="COMPANY_ID" type="long" />
</composite-id>
...
<version name="version" column="VERSION" unsaved-value="null" />
另一种方式是定义单独的主键类:
CustomerId.java:
public class CustomerId implements Serializable{
private final String name;
private final Long companyId;
Constructor...;getter...;setter...;
public boolean equals(Object o){...}
public int hashCode(){...}
}
在Customer类中,不必定义name和companyId属性,而是定义customerId属性:
private CustomerId customerId;
映射文件:
<class name="mypack.Customer" table="CUSTOMERS">
<composite-id name="customerId" class="mypack.CustomerId">
<key-property name="name" column="NAME" type="string" />
<kry-property name="companyId" column="COMPANY_ID" type="long" />
</composite-id>
...
<version name="version" column="VERSION" unsaved-value="null" />
</class>