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 ??










share|improve this question
























  • 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 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















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 ??










share|improve this question
























  • 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 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













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 ??










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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


















  • 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 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
















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

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















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






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














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





















































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







Popular posts from this blog

Xamarin.iOS Cant Deploy on Iphone

Glorious Revolution

Dulmage-Mendelsohn matrix decomposition in Python