为什么80%的码农都做不了架构师?>>>
工作需要,现在已转入了java的 ssh 框架开发,上个星期给了我一个BUG,看似很能简单,但着实费了我一天的时间才解决,记录一下。
背景:原来的数据库表结构中,有一个ID字段,毫无疑问,这也自然充当了hibernate实体的@ID。在原有的环境中,没有问题。功能也是相当的基础:查看列表,双击一列,打开修改窗口,修改完成,点击保存。如教课书般的增删改查。
问题:现在有两个同样系统的数据,要合并,在合并后的数据库中表中,就出得了ID重复现在,自然,操作者们删掉了ID的主键,使得数据正常合并,现在要以ID 字段和另一个叫着SSDS的字段合并来确定唯一项(只是口头上告诉我们这样做)。现在的问题来了,但测试人员在保存一个修改的条目时,系统报错。
头大:这个想想都知道,并库出现的问题,没有考试到并库带来的问题。单步 debug,发现在保存的action中,先get(id) 了这条记录(代码是以前人写的,我也不清楚为什么这样做),因为现在只有一个id,不能唯一确定一值,所以hibernater报出了非唯一项错误。情理之中,但头大的问题来了,为什么打开编辑页面的时候,也有调用同样的方法get(id),却没有报错呢?整整一下午,没找到问题出在哪。
继续头大:今天上午,继续解决这个头大的问题,发现这样一个情况, 在打开编辑窗口的action中,大get(id),有一个getAllList()(也不明白,当时为什么要这样做),正是因为这一句,导致后一句get(id)不会出错,返回的是符合条件的第一件,而且,无论我怎么修改get 方法中的hql(加上 ssds = XXXX), 都没有生效,它只返回id对应的第一条记录。为什么,不得而知,我想是hibernate的缓存吧,也不会报错,只给我一个错误的结果。
解决:那接下来的情况就好办了,复合主键。
我用的是@IdClass,大致步骤如下:
1. 新建 复合主键的类 必须实现Serializable接口。
必须有默认的public无参数的构造方法。
必须覆盖equals和hashCode方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity 时,是根据equals的返回值来判断的。本例中,只有对象的name和email值完全相同时或同一个对象时则返回true,否则返回false。 hashCode方法返回当前对象的哈希码,生成的hashCode相同的概率越小越好。
2.通过@IdClass注释在实体中标注复合主键
如: @IdClass(CustomerPK.class)
在两个字段的属性都加上 @Id
大致就是如此了... ...