10 15 Hibernate之复合主键映射

2022-08-09,,,

文章目录

  • 1 基于HBM文件的配置
  • 2 Annotation配置

首先在开发之中复合主键是一中强烈不建议使用的技术,在任何一张数据表里面如果要设置主键应该只设置一个字段,但是复合主键毕竟属于标准的SQL语法,所以在Hibernate或者是JPA之中也都有复合主键的定义支持。
范例:数据库脚本

-- 删除数据表
DROP TABLE IF EXISTS member;
-- 创建数据表
CREATE TABLE member(
	mid VARCHAR(50),
	mname VARCHAR(50),
	mage INT,
	CONSTRAINT pk_mid_name PRIMARY KEY(mid,name)
);

此时设置了两个主键,但是一定要记住一点,主键不应该重复,所以在随后生成Hibernate操作的时候就要观察它生成类的形式。

1 基于HBM文件的配置

范例:定义MemberId类

@SuppressWarnings("serial")
public class MemberId implements java.io.Serializable {

	// Fields

	private String mid;
	private String mname;
}

为了能够确定唯一,在这个MemberId类里面必须要覆写equals()和hashCode()两个方法。
范例:在Member类里面利用MemberId来描述复合主键

@SuppressWarnings("serial")
public class Member implements java.io.Serializable {

	// Fields

	private MemberId id;
	private Integer mage;
}

随后需要观察Member.hbm.xml文件的组成。

<?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">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="org.lks.pojo.Member" table="member" catalog="hedb">
    	<!-- 取代的是id元素,表示此时的id是一个复合主键 -->
        <composite-id name="id" class="org.lks.pojo.MemberId">
            <key-property name="mid" type="java.lang.String">
                <column name="mid" length="50" />
            </key-property>
            <key-property name="mname" type="java.lang.String">
                <column name="mname" length="50" />
            </key-property>
        </composite-id>
        <property name="mage" type="java.lang.Integer">
            <column name="mage" />
        </property>
    </class>
</hibernate-mapping>

范例:测试代码

package org.lks.test;

import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;

public class TestMemberInsert {

	public static void main(String[] args) {
		MemberId id = new MemberId();
		id.setMid("3161301220");
		id.setMname("lks");
		Member vo = new Member();
		vo.setId(id);
		vo.setMage(23);
		HibernateSessionFactory.getSession().save(vo);
		HibernateSessionFactory.getSession().beginTransaction().commit();
		HibernateSessionFactory.closeSession();
		System.exit(0);
	}
}

Hibernate: 
    insert 
    into
        hedb.member
        (mage, mid, mname) 
    values
        (?, ?, ?)

此时信息可以正常保存(复合主键不重复)。

当然在进行数据查询的时候也有一些需要注意的概念,既然ID不能够重复,所以在数据查询中使用的get()方法来讲就必须考虑到复合主键不能重复的特点,所以才覆写了hashCode()以及equals()方法。
范例:数据查询

package org.lks.test;

import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;

public class TestMemberGet {

	public static void main(String[] args) {
		MemberId id = new MemberId();
		id.setMid("3161301220");
		id.setMname("lks");
		Member vo = (Member)HibernateSessionFactory.getSession().get(Member.class, id);
		System.out.println(vo);
		HibernateSessionFactory.closeSession();
		System.exit(0);
	}
}

Hibernate: 
    select
        member0_.mid as mid1_0_0_,
        member0_.mname as mname2_0_0_,
        member0_.mage as mage3_0_0_ 
    from
        hedb.member member0_ 
    where
        member0_.mid=? 
        and member0_.mname=?
org.lks.pojo.Member@3d7fa3ae

所有的类的属性都会自动的根据配置进行不同类型的关系组成。

2 Annotation配置

虽然复合主键出现较少,但是在JPA的开发标准中依然支持了复合主键映射,并且这个复合主键的映射与之前的细粒度划分不同,它可以完美的配置。
范例:观察生成的MemberId程序类

package org.lks.pojo;

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

/**
 * MemberId entity. @author MyEclipse Persistence Tools
 */
@SuppressWarnings("serial")
@Embeddable

public class MemberId implements java.io.Serializable {

	// Fields

	private String mid;
	private String mname;

	// Constructors

	/** default constructor */
	public MemberId() {
	}

	/** full constructor */
	public MemberId(String mid, String mname) {
		this.mid = mid;
		this.mname = mname;
	}

	// Property accessors

	@Column(name = "mid", nullable = false, length = 50)

	public String getMid() {
		return this.mid;
	}

	public void setMid(String mid) {
		this.mid = mid;
	}

	@Column(name = "mname", nullable = false, length = 50)

	public String getMname() {
		return this.mname;
	}

	public void setMname(String mname) {
		this.mname = mname;
	}

	public boolean equals(Object other) {
		if ((this == other))
			return true;
		if ((other == null))
			return false;
		if (!(other instanceof MemberId))
			return false;
		MemberId castOther = (MemberId) other;

		return ((this.getMid() == castOther.getMid())
				|| (this.getMid() != null && castOther.getMid() != null && this.getMid().equals(castOther.getMid())))
				&& ((this.getMname() == castOther.getMname()) || (this.getMname() != null
						&& castOther.getMname() != null && this.getMname().equals(castOther.getMname())));
	}

	public int hashCode() {
		int result = 17;

		result = 37 * result + (getMid() == null ? 0 : this.getMid().hashCode());
		result = 37 * result + (getMname() == null ? 0 : this.getMname().hashCode());
		return result;
	}

}

范例:观察Member.java类

package org.lks.pojo;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * Member entity. @author MyEclipse Persistence Tools
 */
@SuppressWarnings("serial")
@Entity
@Table(name = "member", catalog = "hedb")

public class Member implements java.io.Serializable {

	// Fields

	private MemberId id;
	private Integer mage;

	// Constructors

	/** default constructor */
	public Member() {
	}

	/** minimal constructor */
	public Member(MemberId id) {
		this.id = id;
	}

	/** full constructor */
	public Member(MemberId id, Integer mage) {
		this.id = id;
		this.mage = mage;
	}

	// Property accessors
	@EmbeddedId

	@AttributeOverrides({
			@AttributeOverride(name = "mid", column = @Column(name = "mid", nullable = false, length = 50)),
			@AttributeOverride(name = "mname", column = @Column(name = "mname", nullable = false, length = 50)) })

	public MemberId getId() {
		return this.id;
	}

	public void setId(MemberId id) {
		this.id = id;
	}

	@Column(name = "mage")

	public Integer getMage() {
		return this.mage;
	}

	public void setMage(Integer mage) {
		this.mage = mage;
	}

}

由于有开发工具的支持,使用复合主键比较方便。

本文地址:https://blog.csdn.net/weixin_43762330/article/details/107139357

《10 15 Hibernate之复合主键映射.doc》

下载本文的Word格式文档,以方便收藏与打印。