简体   繁体   English

为什么Hibernate在没有插入子行的情况下插入带有外键的父行?

[英]Why does Hibernate insert a parent row with a foreign key without inserting the child row?

I'm hoping someone has run into this problem before and can help me out. 我希望有人之前遇到过这个问题,可以帮助我。 Basically, Hibernate is inserting a parent row (with an ID pointing to a child row), but not inserting that child row with the associated ID, which leaves the database in a bad state. 基本上,Hibernate插入父行(ID指向子行),但不插入具有关联ID的子行,这使数据库处于错误状态。 Here's an example of the exception that's thrown when Hibernate tries to load the improperly saved object: 这是Hibernate尝试加载未正确保存的对象时抛出异常的示例:

27 Jun 2011 13:55:31,380 ERROR [scheduler_Worker-4] - 
Job DEFAULT.queryScrubJobDetail threw an unhandled Exception: 
org.springframework.scheduling.quartz.JobMethodInvocationFailedException: 
Invocation of method 'doIt' on target class [XXX] failed; nested exception is
org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException: 
No row with the given identifier exists: 
[XXX.DataProviderTransaction#60739703]; nested exception is org.hibernate.ObjectNotFoundException: 
No row with the given identifier exists: 
[com.idology.persist.DataProviderTransaction#2]

This part of the application has three entities: 这部分应用程序有三个实体:

  • Query , which is a parent of DataProviderTransactionReference and DataProviderTransaction Query ,它是DataProviderTransactionReference和DataProviderTransaction的父级
  • DataProviderTransaction , which is a child of Query and a parent of DataProviderTransactionReference DataProviderTransaction ,它是Query的子项,也是DataProviderTransactionReference的父项
  • DataProviderTransactionReference , which has foreign keys pointing to DataProviderTransaction and Query DataProviderTransactionReference其外键指向DataProviderTransaction和Query

Here are the mappings: 以下是映射:

From Query : 来自查询

@OneToMany(mappedBy = "query", cascade =
    { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.LAZY)
@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
@JoinColumn(name = "query_id")
public List<DataProviderTransactionReference> getDataProviderTransactionReferences()

From DataProviderTransaction : 来自DataProviderTransaction

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "query_id")
public Query getQuery()

From DataProviderTransactionReference : 来自DataProviderTransactionReference

@ManyToOne(cascade =
    { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER)
@JoinColumn(name = "data_provider_transaction_id")
@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
public DataProviderTransaction getDataProviderTransaction()
{
    return mDataProviderTransaction;
}

The schema looks like this (leaving out the queries table since it has no foreign keys): 模式看起来像这样(省略查询表,因为它没有外键):

data_provider_transaction

+------------------+---------------+------+-----+---------+----------------+
| Field            | Type          | Null | Key | Default | Extra          |
+------------------+---------------+------+-----+---------+----------------+
| id               | bigint(20)    | NO   | PRI | NULL    | auto_increment |
| query_id         | bigint(20)    | YES  | MUL | NULL    |                |
+------------------+---------------+------+-----+---------+----------------+

data_provider_txn_refs

+------------------------------+------------+------+-----+---------+----------------+
| Field                        | Type       | Null | Key | Default | Extra          |
+------------------------------+------------+------+-----+---------+----------------+
| id                           | bigint(20) | NO   | PRI | NULL    | auto_increment |
| created_at                   | datetime   | YES  |     | NULL    |                |
| data_provider_transaction_id | bigint(20) | YES  | MUL | NULL    |                |
| query_id                     | bigint(20) | YES  | MUL | NULL    |                |
+------------------------------+------------+------+-----+---------+----------------+

So once we're done running a query (represented by the Query object), we save it using Spring and Hibernate using the following: 所以一旦我们完成了运行查询(由Query对象表示),我们使用Spring和Hibernate使用以下命令保存它:

getHibernateTemplate().saveOrUpdate(aQuery);

The Query is saved along with the associated DataProviderTransaction and DataProviderTransactionReference entities. Query与相关的DataProviderTransaction和DataProviderTransactionReference实体一起保存。 Except that sometimes it saves a Query and a DataProviderTransactionReference without the associated DataProviderTransaction. 除此之外,它有时会保存Query和DataProviderTransactionReference,而不会保存关联的DataProviderTransaction。 It does put an ID in the data_provider_transaction_id but it points to a row that does not exist in the data_provider_transaction table. 它确实在data_provider_transaction_id中放置了一个ID,但它指向data_provider_transaction表中不存在的行。

The next step is to add a foreign key constraint to cause the problem to occur when we do the initial save rather than when we try to load the object later. 下一步是添加外键约束以在我们执行初始保存时发生问题,而不是在我们稍后尝试加载对象时。

We're using Spring 2.5.6, Hibernate 3.3.2, and MySQL 5.0. 我们使用的是Spring 2.5.6,Hibernate 3.3.2和MySQL 5.0。 I've seen the problem occur over the years with earlier versions of Spring and Hibernate, though. 我已经看到多年来早期版本的Spring和Hibernate出现了这个问题。

Anyone ever seen/solved this problem? 有谁见过/解决了这个问题?

This sounds like a problem with your id allocation with MySQL. 这听起来像是你的MySQL id分配问题。 Hibernate can get confused if the generators are not declared correctly, or if you are doing strange things with your code. 如果未正确声明生成器,或者您使用代码执行奇怪的操作,Hibernate可能会感到困惑。

Do you have orphan DataProviderTransactions or DataProviderTransactionReferences, A DataProviderTransaction which has a query id which does not exist, or point to the wrong Query? 你有孤儿DataProviderTransactions或DataProviderTransactionReferences,一个DataProviderTransaction,它有一个不存在的查询ID,或者指向错误的查询?

Are your generators declared as identity for your ids? 您的发电机是否被声明为您的ID的身份? (see Chapter 5. Basic O/R Mapping, section 5.1.4 id . Normally, this should be enough, but there may be other things you're doing which confuse hibernate. (参见第5章基本O / R映射,第5.1.4节id 。通常,这应该足够了,但是你可能还有其他的事情会混淆休眠。

So, for instance: 所以,例如:

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)

To really track this down, you need to know why this is happening, who is inserting these rows. 要真正跟踪这一点,您需要知道为什么会发生这种情况,谁正在插入这些行。 You need a foreign key constraint in the database. 您需要数据库中的外键约束。 It's also possible that something is deleting the DataProviderTransaction and the database isn't complaining because there is no foreign key. 也有可能是某些东西正在删除DataProviderTransaction并且数据库没有抱怨,因为没有外键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM