插入多行错误,LAST_INSERT_ID()返回0

时间:2022-09-21 21:26:27

I am using NHibernate/Fluent NHibernate in an ASP.NET MVC app with a MySQL database. I am working on an operation that reads quite a bit of data (relative to how much is inserted), processes it, and ends up inserting (currently) about 50 records. I have one ISession per request which is created/destroyed in the begin/end request event handlers (exactly like like http://ayende.com/Blog/archive/2009/08/06/challenge-find-the-bug-fixes.aspx), and I am reading in data and adding new objects (as in section 16.3 at https://www.hibernate.org/hib_docs/nhibernate/html/example-parentchild.html), and finally calling Flush() on the session to actually run all the inserts.

我在ASP中使用NHibernate/Fluent NHibernate。带有MySQL数据库的MVC app。我正在进行一个操作,该操作读取相当多的数据(相对于插入的数据数量),对其进行处理,最后插入(当前)大约50条记录。我有一个ISession /end request事件处理程序中创建/销毁的每个请求(类似于http://ayende.com/blog/archive/2009/08/06/challenge - fing -fixes.aspx),我正在读取数据并添加新的对象(如第16.3节https://www.nate.org / hib_家长式会话)。

Getting data out and lazy loading work fine, and when I call Flush exactly 2 new records are being inserted (I am manually checking the table to find this out), and then I get the following error:

取出数据和延迟加载工作正常,当我调用Flush时正好插入了2条新记录(我正在手动检查表以找出这个),然后我得到以下错误:

NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 0, of entity: ...

NonUniqueObjectException:具有相同标识符值的另一个对象已经与entity:…的session: 0关联。

I am new to NHibernate and while searching for a solution have tried explicitly setting the Id property's generator to both Native and Identity (it is a MySQL database and the Id column is an int with auto_increment on), and explicitly setting the unsaved value for the Id property to 0. I still get the error, however.

我新NHibernate和寻找解决方案试图明确设置Id属性的发电机原生和身份(这是一个MySQL数据库,与auto_increment int Id列),并显式地设置未保存的Id属性的值为0。然而,我仍然得到了错误。

I have also tried calling Flush at different times (effectively once per INSERT) and I then get the same error, but for an identity value other than 0 and at seemingly random points in the process (sometimes I do not get it at all in this scenario, but sometimes I do at different points).

我也试过打电话冲在不同的时间(每插入一次有效),然后我得到同样的错误,但对于身份价值除了0和看似随机点过程中(有时我不得到它在这个场景中,但有时我做在不同的点)。

I am not sure where to go from here. Any help or insight would be greatly appreciated.

我不知道从这里到哪里去。如有任何帮助或见解,我们将不胜感激。

EDIT: See the answer below.

编辑:参见下面的答案。

1 个解决方案

#1


2  

EDIT: I originally posted a different "answer" that did not actually solve the problem, but I want to document my findings here for anyone else who may come across it.

编辑:我最初发布了一个不同的“答案”,实际上并没有解决问题,但是我想把我的发现记录在这里,以供任何可能遇到它的人参考。

After several days of trying to figure out the problem and resolve this issue, and being extremely frustrated because the issue seemed to go away for awhile and then come back intermittently (causing me to think multiple times that a change I made fixed it, when in fact it did not), I believe I have tracked down the real issue.

几天后,试图找出问题并解决这个问题,和非常沮丧,因为这个问题似乎消失了一段时间,然后回来间歇性地(让我认为多次改变我固定它,但事实上它并没有),我相信我已经找到了真正的问题。

A few times after I turned the log4net level for NHibernate up to DEBUG, the problem went away, but I was finally able to get the error with that log level. Included in the log were these lines:

在我将NHibernate的log4net级别转换为DEBUG之后,有几次,问题就消失了,但是我最终能够得到那个日志级别的错误。日志中包括以下几行:

Building an IDbCommand object for the SqlString: SELECT LAST_INSERT_ID()
...
NHibernate.Type.Int32Type: 15:10:36 [8] DEBUG NHibernate.Type.Int32Type: returning '0' as column: LAST_INSERT_ID()
NHibernate.Id.IdentifierGeneratorFactory: 15:10:36 [8] DEBUG NHibernate.Id.IdentifierGeneratorFactory: 
Natively generated identity: 0

And looking up just a few lines I saw:

抬头只看到几行字:

NHibernate.AdoNet.ConnectionManager: 15:10:36 [8] DEBUG NHibernate.AdoNet.ConnectionManager: aggressively releasing database connection
NHibernate.Connection.ConnectionProvider: 15:10:36 [8] DEBUG NHibernate.Connection.ConnectionProvider: Closing connection

It seems that while flushing the session and performing INSERTs, NHibernate was closing the connection between the INSERT statement and the "SELECT LAST_INSERT_ID()" to get the id that was generated by MySQL for the INSERT statement. Or rather, I should say it was sometimes closing the connection which is one reason I believe the problem was intermittent. I can't find the link now, but I believe I also read in all my searching that MySQL will sometimes return the correct value from LAST_INSERT_ID() even if the connection is closed and reopened, which is another reason I believe it was intermittent. Most of the time, though, LAST_INSERT_ID() will return 0 if the connection is closed and reopened after the INSERT.

似乎在刷新会话并执行插入时,NHibernate关闭了INSERT语句和“SELECT LAST_INSERT_ID()”之间的连接,以获取MySQL为INSERT语句生成的id。或者更确切地说,我应该说,它有时会关闭连接,这是我认为问题是间歇性的原因之一。我现在找不到链接,但我相信我在所有的搜索中都看到,MySQL有时会返回LAST_INSERT_ID()的正确值,即使连接已经关闭并重新打开,这也是我认为它是间歇性的另一个原因。但是,大多数时候,如果在插入之后关闭连接并重新打开连接,那么LAST_INSERT_ID()将返回0。

It appears there are 2 ways to go about fixing this issue. First is a patch available here that looks like it will make it into NHibernate 2.1.1, or which you can use to make your own build of NHibernate, which forces the INSERT and SELECT LAST_INSERT_ID() to run together. Second, you can set the connection.release_mode to on_close as described in this blog post which prevents NHibernate from closing the connection until the ISession is explicitly closed.

看来解决这个问题有两种方法。首先,这里有一个补丁,看起来它将使它成为NHibernate 2.1.1,或者您可以使用它来构建自己的NHibernate,它强制INSERT并选择LAST_INSERT_ID()一起运行。其次,可以设置连接。在此博客文章中描述的release_mode可以阻止NHibernate关闭连接,直到显式关闭为止。

I took the latter approach, which is done in FluentNHibernate like this:

我采用了后一种方法,在FluentNHibernate中是这样做的:

Fluently.Configure()
    ...
    .ExposeConfiguration(c => c.Properties.Add("connection.release_mode", "on_close"))
    ...

This also had the side effect of drastically speeding up my code. What was taking 20-30 seconds to run (when it just so happened to work before I made this change) is now running in 7-10 seconds, so it is doing the same work in ~1/3 the time.

这也有一个副作用,就是大大加快了我的代码。运行时间为20-30秒(在我进行此更改之前恰好工作)现在运行时间为7-10秒,所以在大约1/3的时间内进行同样的工作。

#1


2  

EDIT: I originally posted a different "answer" that did not actually solve the problem, but I want to document my findings here for anyone else who may come across it.

编辑:我最初发布了一个不同的“答案”,实际上并没有解决问题,但是我想把我的发现记录在这里,以供任何可能遇到它的人参考。

After several days of trying to figure out the problem and resolve this issue, and being extremely frustrated because the issue seemed to go away for awhile and then come back intermittently (causing me to think multiple times that a change I made fixed it, when in fact it did not), I believe I have tracked down the real issue.

几天后,试图找出问题并解决这个问题,和非常沮丧,因为这个问题似乎消失了一段时间,然后回来间歇性地(让我认为多次改变我固定它,但事实上它并没有),我相信我已经找到了真正的问题。

A few times after I turned the log4net level for NHibernate up to DEBUG, the problem went away, but I was finally able to get the error with that log level. Included in the log were these lines:

在我将NHibernate的log4net级别转换为DEBUG之后,有几次,问题就消失了,但是我最终能够得到那个日志级别的错误。日志中包括以下几行:

Building an IDbCommand object for the SqlString: SELECT LAST_INSERT_ID()
...
NHibernate.Type.Int32Type: 15:10:36 [8] DEBUG NHibernate.Type.Int32Type: returning '0' as column: LAST_INSERT_ID()
NHibernate.Id.IdentifierGeneratorFactory: 15:10:36 [8] DEBUG NHibernate.Id.IdentifierGeneratorFactory: 
Natively generated identity: 0

And looking up just a few lines I saw:

抬头只看到几行字:

NHibernate.AdoNet.ConnectionManager: 15:10:36 [8] DEBUG NHibernate.AdoNet.ConnectionManager: aggressively releasing database connection
NHibernate.Connection.ConnectionProvider: 15:10:36 [8] DEBUG NHibernate.Connection.ConnectionProvider: Closing connection

It seems that while flushing the session and performing INSERTs, NHibernate was closing the connection between the INSERT statement and the "SELECT LAST_INSERT_ID()" to get the id that was generated by MySQL for the INSERT statement. Or rather, I should say it was sometimes closing the connection which is one reason I believe the problem was intermittent. I can't find the link now, but I believe I also read in all my searching that MySQL will sometimes return the correct value from LAST_INSERT_ID() even if the connection is closed and reopened, which is another reason I believe it was intermittent. Most of the time, though, LAST_INSERT_ID() will return 0 if the connection is closed and reopened after the INSERT.

似乎在刷新会话并执行插入时,NHibernate关闭了INSERT语句和“SELECT LAST_INSERT_ID()”之间的连接,以获取MySQL为INSERT语句生成的id。或者更确切地说,我应该说,它有时会关闭连接,这是我认为问题是间歇性的原因之一。我现在找不到链接,但我相信我在所有的搜索中都看到,MySQL有时会返回LAST_INSERT_ID()的正确值,即使连接已经关闭并重新打开,这也是我认为它是间歇性的另一个原因。但是,大多数时候,如果在插入之后关闭连接并重新打开连接,那么LAST_INSERT_ID()将返回0。

It appears there are 2 ways to go about fixing this issue. First is a patch available here that looks like it will make it into NHibernate 2.1.1, or which you can use to make your own build of NHibernate, which forces the INSERT and SELECT LAST_INSERT_ID() to run together. Second, you can set the connection.release_mode to on_close as described in this blog post which prevents NHibernate from closing the connection until the ISession is explicitly closed.

看来解决这个问题有两种方法。首先,这里有一个补丁,看起来它将使它成为NHibernate 2.1.1,或者您可以使用它来构建自己的NHibernate,它强制INSERT并选择LAST_INSERT_ID()一起运行。其次,可以设置连接。在此博客文章中描述的release_mode可以阻止NHibernate关闭连接,直到显式关闭为止。

I took the latter approach, which is done in FluentNHibernate like this:

我采用了后一种方法,在FluentNHibernate中是这样做的:

Fluently.Configure()
    ...
    .ExposeConfiguration(c => c.Properties.Add("connection.release_mode", "on_close"))
    ...

This also had the side effect of drastically speeding up my code. What was taking 20-30 seconds to run (when it just so happened to work before I made this change) is now running in 7-10 seconds, so it is doing the same work in ~1/3 the time.

这也有一个副作用,就是大大加快了我的代码。运行时间为20-30秒(在我进行此更改之前恰好工作)现在运行时间为7-10秒,所以在大约1/3的时间内进行同样的工作。