话不多说,直接上错误
ERROR: HHH000346: Error during managed flush [could not execute statement]
org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112)
….
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
at luoqi.com.Bid.ff(Bid.java:81)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)…..
Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`rocky`.`bid`, CONSTRAINT `bidders` FOREIGN KEY (`bidder`) REFERENCES `representative` (`account`) ON DELETE CASCADE ON UPDATE CASCADE)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2870)
其中的 at luoqi.com.Bid.ff(Bid.java:81) 错误对应代码如下:
即transaction实例ts,对数据库的操作使用commit()函数提交
这是在数据库插入一条bid数据时出现的问题
一共涉及到三个表:
投标表:bid(主键id) 公司代表表:representative(主键id) 总账户表:sum_acccount(主键id)
其中bid.bidders属性拥有外键,对应representative.acccount
同时representative.account属性也拥有外键,对应sum_account.id
这个bug改了一天,现在整理一下bug修复历程:
1.因为使用Hibernate自动生成的dao类
其中有save(),delete(),findxxx()等函数,封装了对数据库的操作,而且对数据库的操作也是基于hql的,面向对象的数据库操作。在这个对bid插入数据的操作中,用sumAccount对象替代了representative的account属性,用representative对象替代了bid的bidder对象。由于对这个dao类生成方法的不熟悉,起初怀疑时hql语句本身的设计问题,因为也没有报hql语句错误之类的信息
2.之后在网上找了许多解决方法,但是没有适用的。其中针对root error的翻译,解释是对子表进行操作时,建立外键的值,在父表中不可找到。但是本身bid表中的Bidder属性就是使用父类对象替代的,这就很矛盾,挣扎了半天,最后选择先做其他的。
3.寻找身边的朋友,最后找到问题的根源,就是数据库设计的问题。在bid连接外键向representative表的时候,对应属性不是representative的主键,而是account。虽然account和id在实际上都是唯一的,在设计数据库表的时候就没有想太多,导致了这个概念上的错误,不满足基本范式要求。
4.大佬也提供了一种思路,将representative的account属性建立索引,并且设置unique属性,希望通过索引时值的唯一性来获得将bidder的外键连接到representative主键的同样效果
总结:
1.针对这个错误,明白添加数据时要顾及父表中是否存在对应数据,而且数据库设计要满足基本要求,外键的设置必须是对应父表的主键
2.不要习惯性的相信类似的代码在不同机子上跑出的结果一样。起初,做注册的朋友说他的representative注册可以正常用,也就是代表表和账户表之间的连接没有问题,我就想当然的认为投标表和代表表的连接同样也不会有问题。应该时刻保持怀疑的态度谨慎对待这类问题,找出其中的不同