Была проблема — замапить два класса (родитель и наследник) на две таблицы в базе (MSSQL), связанные по id.
В первой таблице (предназначенной для родителя) id поле было indentity.
Проще говоря_ hibrnaty при вставке строки (создании нового объекта) надо было вставить строку в первую таблицуб потом select @@identity вытащить сгенерированный базой ключ и вставить во вторую таблицу запись с этим ключем.
НО был очень удивлен, когда вместо сгенерированного зачения ключа вернулся 0.
Дальнейшее расследование JDBC показало, что select @@identity не вернет ключ сгенерированный при педыдущем Inserte если не закрыть Statement этого inserta. То есть надо делать так:
Statement st = conn.createStatement();
st.executeUpdate("insert into tab(name) values ('ABCDEF')");
st.close();
Statement sta = conn.createStatement();
ResultSet rs = sta.executeQuery("select @@identity");
копание в исходниках hibernate показало, что Statement не всегда закрывается, часто он возвращается в кеш, пришлось "довести напильником" — в классе net.sf.hibernate.persister.NormalizedEntityPersister в методе
Serializable insert(Object[] fields, Object object, SessionImplementor session)
добавить закрытие Statement (statement.close(). После этого все заработало, как и полагается. Согласно документации
Вопрос — кто сталкивался с подобной проблемой, может есть другой метод, или я что-то прогдядел в настройках ?
Метод "русского программиста" конечно работает, но все-таки остается чувство беспокойства...
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, dimpon, Вы писали:
D>>не сочтите за труд попробуйте — такой код будет возвращать identity ? (первый Statement не закрывается)
D>>
D>>Statement st = conn.createStatement();
D>>st.executeUpdate("insert into tab(name) values ('ABCDEF')");
D>>//st.close();
D>>Statement sta = conn.createStatement();
D>>ResultSet rs = sta.executeQuery("select @@identity");
D>>while (rs.next()){
D>> System.out.println("identity= "+rs.getInt(1));
D>>}
D>>
B>Может реально изменения в базе ещё не закоммитились? И поэтому такой @@identity? Судя по описанному поведению очень на то похоже.
Нет, такой код тоже не работает, дело не в коммите
Statement st = conn.createStatement();
st.executeUpdate("insert into tab(name) values ('ABCDEF')");
conn.commit();
//st.close();
Statement sta = conn.createStatement();
ResultSet rs = sta.executeQuery("select @@identity");
Здравствуйте, Mishka, Вы писали:
M>Здравствуйте, dimpon:
M>А причём здесь Hibernate? Или ты получаешь соединение из Session и потом используешь?
нет, это был просто тестовый пример читстый JDBC + MSSQL
Дело в том, что в hibernate как раз используется два Statement'а, причем, второй не закрывается, а возвращается в кеш. (происходит это как раз в классе, net.sf.hibernate.persister.NormalizedEntityPersister )
и только после принудительного закрытия первого Statement все заработало.
Здравствуйте, Mishka, Вы писали:
M>Здравствуйте, dimpon, Вы писали:
D>>хм, может дело в настройках MSSQL...
M>Попробуй установить autocommit в false.
Вот уж тогда точно придется первый Statement закрывать.
Потому что MSSQL иначе ругается —
Can't start a cloned connection while in manual transaction mode
Здравствуйте, dimpon, Вы писали:
D>Вот уж тогда точно придется первый Statement закрывать. D>Потому что MSSQL иначе ругается — D>Can't start a cloned connection while in manual transaction mode
Это сообщение скорее всего выскакивает из-за того, что selectMethod не установлен в cursor. Посмотри как прописано соединение.
Здравствуйте, Mishka, Вы писали:
M>Здравствуйте, dimpon, Вы писали:
D>>Вот уж тогда точно придется первый Statement закрывать. D>>Потому что MSSQL иначе ругается — D>>Can't start a cloned connection while in manual transaction mode
M>Это сообщение скорее всего выскакивает из-за того, что selectMethod не установлен в cursor. Посмотри как прописано соединение.
О! золотые слова ! все дело было в SelectMethod=cursor и hibernate пачить не надо !