JPA中实现两个表的非索引列(非主键列)关联

在做项目的时候遇到这样一个问题:

一个学生表stuInfo,一个专业表majorInfo。使用MySQL数据库,表定义如下:

表stuInfo定义
列名数据类型功能
idbigint学生信息的绝对索引,自增列,主键
stuIdvarchar(10)学号列
stuNamevarchar(10)学生姓名列
majorIdvarchar(5)学生专业ID列,由于专业ID中可能出现英文字母来区分专科专业和本科专业,因此不能使用数值类型

表majorInfo定义
列名数据类型功能
idbigint专业信息的绝对索引,自增列,主键
majorIdvarchar(5)学生专业ID列,由于专业ID中可能出现英文字母来区分专科专业和本科专业,因此不能使用数值类型
majorNamevarchar(15)专业名称列

有项目经验的人一看就知道这样建立数据库是非常不专业的,外键关联没问题,问题在于关联列的数据类型是varchar,这将非常消耗计算资源。

但是本人也没有办法,为了和原有系统兼容,尽快实现功能,也只好牺牲性能了。在这里也提醒读者,凡是涉及表关联操作的,关联列的数据类型尽量采用数值。当数据库内记录很多的时候,执行连接select语句时,使用数值类型进行关联较之使用字符类型进行关联将会产生很大的性能差异。

要求是这样的,将stuInfo表中的majorId与majorInfo表中的majorId进行关联,以实现按照学号查询学生时能显示所在专业。


开始的时候我的POJO是这样来写的

stuInfo表的POJO:

package pojo;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class StuInfo implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = -6371005564069606650L;

	@Id
	@GeneratedValue
	private Long id;

	private String stuId;

	private String stuName;

	@ManyToOne
	@JoinColumn(name="majorId")
	private MajorInfo majorInfo;

	public Long getId() {
		return id;
	}

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

	public String getStuId() {
		return stuId;
	}

	public void setStuId(String stuId) {
		this.stuId = stuId;
	}

	public String getStuName() {
		return stuName;
	}

	public void setStuName(String stuName) {
		this.stuName = stuName;
	}

	public MajorInfo getMajorInfo() {
		return majorInfo;
	}

	public void setMajorInfo(MajorInfo majorInfo) {
		this.majorInfo = majorInfo;
	}
}

majorInfo表的POJO:

package pojo;

import java.io.Serializable;

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

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

@Entity
public class MajorInfo implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 6367248158160032489L;

	@Id
	@GeneratedValue
	private Long id;
	
	@NotEmpty
	@Length(min=5, max=5)
	private String majorId;
	
	@Length(max=15)
	private String majorName;

	public Long getId() {
		return id;
	}

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

	public String getMajorId() {
		return majorId;
	}

	public void setMajorId(String majorId) {
		this.majorId = majorId;
	}

	public String getMajorName() {
		return majorName;
	}

	public void setMajorName(String majorName) {
		this.majorName = majorName;
	}
}

当我查询的学生信息的时候,控制台输出了错误,内容如下:

Unable to find pojo.MajorInfo with id 301


是这样的,我要显示的是数据库中第一条记录,然而stuInfo表中第一条记录majorID字段存储的是0301,根据提示信息,JPA自动对应的是majorInfo表中的id字段。而且把字符串varchar类型的数据”0301“自动转换成了”301“,然而majorInfo表中的数据没有id为301的记录,因此当然在关联majorInfo表记录时产生了空指向异常从而报错。问题的症结在于在StuInfo类中,指明了majorInfo属性绑定到"majorId"列,但JPA自动建立的关联目标是从表majorInfo的索引列id,这样一来难怪会出问题。


后来查阅资料,发现在StuInfo类中的majorInfo属性注解配置有问题。@JoinColumn注解的name参数只是绑定该POJO映射到表的某一列的列名,并不影响从表绑定列名,如果没有其他特别指示,JPA会自动与从表的主键进行关联。解决问题的代码就是修改这个注解为@JoinColumn(name="majorId", referencedColumnName="majorId")

这样主表的映射列与从表的映射列都特别指定了,这时候再查询,故障消失。

说了这么多,其实有含金量的就一句话:@JoinColumn(name="majorId", referencedColumnName="majorId")

最后多说一句,如果不是被逼无奈,数据库表可不能像文章开头所表述的那样建立。组织数据的方式多种多样,不要仅限于一种思路。作为一个合格的DBA也不能光想着自己工作简单,不考虑性能和后台同事在实现功能时的困难度。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值