Mysql/Grails: How entity ID is being initialized upon calling Entity.save() (without flushing) on a newly...
up vote
0
down vote
favorite
I'm using Mysql and Grails.
Suppose I have an entity class Book
, book
table in mysql has an auto_incremented
id
column.
Say the following is my service method:
@Transactional
public void someMethod() {
Book book = new Book("Book Name", "Author Name") // book.id is null here
book.save();
println book.id // id is initialized
}
When I stop on println
statement using debugger I see that book
's id
property is initialized. As I'm not flushing
anything to db the row is not inserted into db yet and hence the id
is not generated upon insertion, but some other way. One possible way the id
might be initialized seems to be that hibernate runs a query just for fetching the next auto_increment
value when the save()
method is executed on entity (not sure if it's the case). If it's the case then what about 2 concurrent transactions getting the same ID ??
java mysql hibernate grails gorm
|
show 1 more comment
up vote
0
down vote
favorite
I'm using Mysql and Grails.
Suppose I have an entity class Book
, book
table in mysql has an auto_incremented
id
column.
Say the following is my service method:
@Transactional
public void someMethod() {
Book book = new Book("Book Name", "Author Name") // book.id is null here
book.save();
println book.id // id is initialized
}
When I stop on println
statement using debugger I see that book
's id
property is initialized. As I'm not flushing
anything to db the row is not inserted into db yet and hence the id
is not generated upon insertion, but some other way. One possible way the id
might be initialized seems to be that hibernate runs a query just for fetching the next auto_increment
value when the save()
method is executed on entity (not sure if it's the case). If it's the case then what about 2 concurrent transactions getting the same ID ??
java mysql hibernate grails gorm
Doesn't@Transactional
write to the database on.save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).
– Michael - sqlbot
Nov 11 at 0:20
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
In case ofbook.save(flush: true)
the insert statement will be flushed to db in contrast tobook.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentionedwithout flushing
in my question as in case ofbook.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincrementedid
– Suren Aznauryan
Nov 11 at 14:17
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37
|
show 1 more comment
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm using Mysql and Grails.
Suppose I have an entity class Book
, book
table in mysql has an auto_incremented
id
column.
Say the following is my service method:
@Transactional
public void someMethod() {
Book book = new Book("Book Name", "Author Name") // book.id is null here
book.save();
println book.id // id is initialized
}
When I stop on println
statement using debugger I see that book
's id
property is initialized. As I'm not flushing
anything to db the row is not inserted into db yet and hence the id
is not generated upon insertion, but some other way. One possible way the id
might be initialized seems to be that hibernate runs a query just for fetching the next auto_increment
value when the save()
method is executed on entity (not sure if it's the case). If it's the case then what about 2 concurrent transactions getting the same ID ??
java mysql hibernate grails gorm
I'm using Mysql and Grails.
Suppose I have an entity class Book
, book
table in mysql has an auto_incremented
id
column.
Say the following is my service method:
@Transactional
public void someMethod() {
Book book = new Book("Book Name", "Author Name") // book.id is null here
book.save();
println book.id // id is initialized
}
When I stop on println
statement using debugger I see that book
's id
property is initialized. As I'm not flushing
anything to db the row is not inserted into db yet and hence the id
is not generated upon insertion, but some other way. One possible way the id
might be initialized seems to be that hibernate runs a query just for fetching the next auto_increment
value when the save()
method is executed on entity (not sure if it's the case). If it's the case then what about 2 concurrent transactions getting the same ID ??
java mysql hibernate grails gorm
java mysql hibernate grails gorm
edited Nov 10 at 17:42
asked Nov 10 at 17:36
Suren Aznauryan
23619
23619
Doesn't@Transactional
write to the database on.save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).
– Michael - sqlbot
Nov 11 at 0:20
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
In case ofbook.save(flush: true)
the insert statement will be flushed to db in contrast tobook.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentionedwithout flushing
in my question as in case ofbook.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincrementedid
– Suren Aznauryan
Nov 11 at 14:17
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37
|
show 1 more comment
Doesn't@Transactional
write to the database on.save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).
– Michael - sqlbot
Nov 11 at 0:20
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
In case ofbook.save(flush: true)
the insert statement will be flushed to db in contrast tobook.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentionedwithout flushing
in my question as in case ofbook.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincrementedid
– Suren Aznauryan
Nov 11 at 14:17
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37
Doesn't
@Transactional
write to the database on .save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).– Michael - sqlbot
Nov 11 at 0:20
Doesn't
@Transactional
write to the database on .save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).– Michael - sqlbot
Nov 11 at 0:20
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
In case of
book.save(flush: true)
the insert statement will be flushed to db in contrast to book.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentioned without flushing
in my question as in case of book.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincremented id
– Suren Aznauryan
Nov 11 at 14:17
In case of
book.save(flush: true)
the insert statement will be flushed to db in contrast to book.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentioned without flushing
in my question as in case of book.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincremented id
– Suren Aznauryan
Nov 11 at 14:17
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37
|
show 1 more comment
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53241653%2fmysql-grails-how-entity-id-is-being-initialized-upon-calling-entity-save-wit%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Doesn't
@Transactional
write to the database on.save()
? If the transaction is rolled back, the next record will still get a different ID even though this one was never used (as far as you can tell from looking at the database -- it will have been skipped).– Michael - sqlbot
Nov 11 at 0:20
@Transactional ensures that transaction will be committed when the method completes, so in the described case, as we are still inside the method, transaction is not committed yet
– Suren Aznauryan
Nov 11 at 6:13
Right -- but not committed != not inserted. That's the idea of database transactions, you can make changes to the database -- including inserting rows so that you have their auto increment PK value -- before actually committing the changes. Fetching the next auto increment value would be hopelessly naïve, for the reason you indicated. I am a DBA, not familiar with grails, but I can't imagine it's doing anything other than doing the insert here -- which is safe to do, since it's inside a transaction that can be rolled back implicitly by MySQL if an exception is thrown before commit.
– Michael - sqlbot
Nov 11 at 14:05
In case of
book.save(flush: true)
the insert statement will be flushed to db in contrast tobook.save()
. In the latter case hibernate will execute 'flush' just before transaction commit which will be after the method finishes its execution. That's why i have mentionedwithout flushing
in my question as in case ofbook.save(flush: true)
it is obvious that the statement will be flushed and executed in db returning the autoincrementedid
– Suren Aznauryan
Nov 11 at 14:17
Temporarily turn on the MySQL General Query Log which logs all queries as they are issued, with timestamps and the id of the thread that ran the query. Add some sleep statements between each line in your code and observe what is actually happening at the database.
– Michael - sqlbot
Nov 11 at 15:37