因为在Oracle数据库中,容许没有主键的存在,而hibernate体系又不容许没有主键,这在逻辑上是有冲突的。事实上,表不须要主键。表没有显式键对数据库没有任何影响,由于数据库中的每一行都有一个隐式的惟一数据点,Oracle将其用于存储和某些内部引用,即rowid伪列。rowid是惟一标识数据库中每一行的一段数据。严格来讲,没有必要把钥匙放在桌子上。好比如今的项目中,使用的oracle10g数据库有超过1000个系统表,它们没有主键或者说在各自的表上有惟一键。dba和开发人员均可以决定如何在数据库表上建立密钥。然而在开发过程当中老是建立主键,这个估计是开发框架致使的,而框架才无论它们是否有用或健全。但做为优秀dba,他们只在有意义的地方建立键。
不少时候线上和线下开发是彻底隔离开的,线下开发后的测试环境也不可能那么完美的贴合生产环境,笔者的项目中所使用数据库为marridb,而生产环境中使用的数据库为Oracle,这个联调过程当中产生的bug也真的是不可多得:),我这边获取到测试数据确实是来自生产环境,然而这个是经过select
语句而来的,这就直接致使这个表是没有主键的。以后把这些测试数据导入到marridb。java
如今的状况就是数据库一个没有主键的表,然而经过springboot所建立实体却要求配置主键,这跟数据库中的配置不相符,此外因为实体类中所定义的主键,在数据库中重复出现。spring
这其实是违背了数据库中主键的定义惟一地标识表中的每一行,经过它可强制表的实体完整性,致使出现这样表的缘由是,在Oracle中容许没有主键的定义,经过多表联查汇总到一张表中,而后将这张表导入到marridb中,才会出现这么尴尬的结果数据库
致使的结果就是搜索到某一个uuid,其结果有17条,经过jpa取结果整个list长度确实为17,然而,数据展开以后会发现,里面几乎都是重复数据express
2019-12-09 19:39:20.411 WARN 26340 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bussiness' defined in file [/xxx/yyy/zzz/service/Bussiness.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'alarmStatisticServiceImpl' defined in file [xxx/yyy/zzz/service/impl/AlarmStatisticServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'processAccountRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List xxx.yyy.zzz.repository.ProcessAccountRepository.getAllData()!
没法建立一个bean,而其实是因为某一类是未指定标识符的实体,主要缘由是hibernate在进行扫描实体的时候,未发现其主键标识。因此就在其类上添加主键标识。由于个人这个类比较特殊,须要添加联合主键。springboot
联合主键用Hibernate注解映射方式主要有三种:oracle
1. 将联合主键的字段单独放在一个类中,该类须要实现java.io.Serializable接口并重写equals和hascode,再将该类注解为@Embeddable,最后在主类中(该类不包含联合主键类中的字段)保存该联合主键类的一个引用,并生成set和get方法,以后将该引用注解为@Id
框架
@Entity @Table(name = "Process_Account") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public class ProcessAccount { @Id private ProcessAccountPk priAccountpk; }
主键类: ide
@Embeddable public class ProcessAccountPk implements Serializable { @Column(name = "UUID") private String uuid; @Column(name = "xxx") private String priAccount; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ProcessAccountPk)) return false; ProcessAccountPk that = (ProcessAccountPk) o; return Objects.equals(getUuid(), that.getUuid()) && Objects.equals(getPriAccount(), that.getPriAccount()); } @Override public int hashCode() { return Objects.hash(getUuid(), getPriAccount()); } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getPriAccount() { return priAccount; } public void setPriAccount(String priAccount) { this.priAccount = priAccount; } }
@Entity @Table(name="Process_Account") public class ProcessAccount { @Id @Column(name = "RESUUID") private String uuid; @Id @Column(name = "xxx") private String priAccount; @EmbeddedId private ProcessAccountPk processAccountPk ; }
这个时候ProcessAccountPk为普通Java类便可。测试
3、将联合主键的字段单独放在一个类中,该类须要实现java.io.Serializable接口并要重写equals和hashcode.最后在主类中(该类包含联合主键类中的字段)将联合主键字段都注解为@Id,并在该类上方将上这样的注解:@IdClass(联合主键类.class),通过踩坑,我用了这个方法:),中间的判断过程就一笔带过吧,有问题私聊ui
@Entity @Table(name = "Process_Account") @IdClass(ProcessAccountPk.class) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public class ProcessAccount { @Id @Column(name = "RESUUID") private String uuid; @Id @Column(name = "xxx") private String priAccount; }
ProcessAccountPk 继承自Serializable类
public class ProcessAccountPk implements Serializable { private String uuid; private String priAccount; public ProcessAccountPk() { } public ProcessAccountPk(String uuid, String priAccount) { this.uuid = uuid; this.priAccount = priAccount; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ProcessAccountPk)) return false; ProcessAccountPk that = (ProcessAccountPk) o; return Objects.equals(getUuid(), that.getUuid()) && Objects.equals(getPriAccount(), that.getPriAccount()); } @Override public int hashCode() { return Objects.hash(getUuid(), getPriAccount()); } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getPriAccount() { return priAccount; } public void setPriAccount(String priAccount) { this.priAccount = priAccount; } }
至此,问题解决了,我取出来的数据不会因为uuid或者bussinessName致使数据重复,两个字段同时做为主键进行查询就能够解决这个问题