Oracle->MSSQL: How to set identifier generator? - java

I'm migrating OracleDB11g to MSSQL2014.
Currently getting following error when trying to save new data:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Cannot
insert the value NULL into column 'ID', table 'testDB.FILE_SETTINGS';
column does not allow nulls. INSERT fails.
My interpretation is that this is caused as the "native" ID generator differs between Oracle & MSSQL (Sequence vs. Identity).
In Oracle we had small customization to HIBERNATE_SEQUENCE:
alter sequence hibernate_sequence increment by 5;
...but thats all.
hibernate-mapping is originally like this:
<id name="id" column="ID" type="java.lang.Long">
<generator class="native">
</generator>
</id>
In MSSQL I have tried it like this with no luck:
<id name="id" column="ID" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">HIBERNATE_SEQUENCE</param>
</generator>
</id>
And in MSSQL server I have sequence (migration tool created):
HIBERNATE_SEQUENCE in testDB->Views->sys.sequences
Also found in (migration tool created):
testDB->Views->INFORMATION_SCHEMA.SEQUENCES
How should this be done properly as I want to retain the same way to generate identity as was in Oracle? Something wrong in MSSQL or in hibernate settings?
Hibernate version is quite old: 2.1.8

Your interpretation of the error is wrong. This error tells you nothing about sequence. It tells you that your testDB.FILE_SETTINGS has id column defined as NOT NULL but you try to insert NULL value here.
I don't see your code but I think there is something like this:
create table dbo.MyTbl_wrong (id int NOT NULL, col1 varchar(100) );
insert into dbo.MyTbl_wrong(col1) values ('1 str'), ('2 str'), ('3 str');
Cannot insert the value NULL into column 'id', table
'db2.dbo.MyTbl_wrong'; column does not allow nulls. INSERT fails. The
statement has been terminated.
What you should do instead is to use sequence in the default for your id column like this:
create sequence dbo.MySeq
start with 1;
create table dbo.MyTbl (id int NOT NULL default(next value for dbo.MySeq), col1 varchar(100) );
insert into dbo.MyTbl(col1) values ('1 str'), ('2 str'), ('3 str');
--select *
--from dbo.MyTbl;
-------
--id col1
--1 1 str
--2 2 str
--3 3 str

Answering own question if some day someone has similar issues:
Apparently there was nothing wrong with the settings I mentioned in original question, only that hibernate 2.1.8 seemed not to support the SEQUENCE id genererator. Also old hibernate obviously did not support the needed SQLServer2012Dialect.
Ended up updating the hibernate version to 4.3.11 (with its dependencies). This version got selected as it required the least amount of refactoring.
I had some issues with the dependencies as this old project was not using Maven.
Also faced this error as any DB query was attempted:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
I found out that new hibernate version was defaulted to use lazy loading which was not supported in the old version. So I ended up fixing it with setting "lazy=false" in hibernate setting files.
You may see "org.hibernate.LazyInitializationException: could not initialize proxy - no Session" while upgrading from hibernate 2.1 to hibernate 3.0. You will suddenly find yourself puzzling what happened, it was working before update. Reasons is, Hibernate 3 introduced lazy loading as the default i.e. lazy="true". If you want it to work the same as before you can mark everything as lazy="false". Alternatively you'll have to start eagerly initialising your entities and associations.
Read more: http://javarevisited.blogspot.com/2014/04/orghibernatelazyinitializationException-Could-not-initialize-proxy-no-session-hibernate-java.html#ixzz56ahBmiBl

Related

Liquibase always generating changesets for creating/dropping index

I am just starting to use Liquibase and I am wondering: why is it that when I run ./mvnw compile liquibase:diff are change sets generated to first drop existing indexes and then recreate them if they already exist?
Ex:
<changeSet author="me (generated)" id="1486157347995-13">
<dropIndex indexName="my_idx" tableName="notification"/>
<createIndex indexName="my_idx" tableName="notification">
<column name="index_col"/>
</createIndex>
</changeSet>
Probably out of "laziness".
This is a simple way to make sure the index created is the same (not only the name, but the columns used) than the one in the reference database.
It handles two diff cases in one:
missing index name in the target db,
same index name but with a different definition.

Hibernate configuration hbm2ddl.auto

I have such hibernate.cfg.xml:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:postgresql://host:5432/app-dev</property>
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="hbm2ddl.auto">validate</property>
...many mappings
</session-factory>
And the problem is that it's trying to update my database schema, but I want to disable that feature.
log from my application:
2015-08-29 16:29:57 ERROR SchemaUpdate:261 - HHH000388: Unsuccessful: create table myschema.public.mytable (id int4 not null, count int4, anotherid int4, onemoreid int4, primary key (id))
2015-08-29 16:29:58 ERROR SchemaUpdate:262 - ERROR: syntax error at or near "-" <<(mydatabase name contains "-" sign)
Position: 27
I also tried to leave hbm2ddl.auto tag empty or include 'none' value in it.
Remove the property <property name="hbm2ddl.auto">validate</property> entirely.
By default all options will be false and hibernate will not attempt to do any updates.
Remove Hibernatehbm2ddl.auto defaults to Hibernate not doing anything.
From the docs
The hbm2ddl.auto option turns on automatic generation of database
schemas directly into the database. This can also be turned off by
removing the configuration option, or redirected to a file with the
help of the SchemaExport Ant task.
Validate is the default property of hbm2ddl.auto, even if you dont specify hbm2ddl.auto property, then also it is by default validate. Secondly there is no such value as "none", there are only 4 options :
validate- it simply checks that table and its columns are existing in database or not an if a table does not exist or any column does not exist than Exception is thrown.
create - If the value is create than hibernate drops the table if it already exist and then creates a new table and executes the operation, this is not used in real time as the old data is lost from database.
update - If the values is update than hibernate uses existing table and if the table does not exist than creates a new table and executes operation. This is mostly and often used in real time and it is recommended.
create-drop - if the value is create-drop than hibernate creates a new table and after executing the operation it drops the table, this value is used while testing hibernate code.
Thanks
Njoy Coding

Hibernate slqjdbc4 column with spaces

I need to map in Java with hibernate a table in sqlserver that has spaces in the column names.
I use Sqlserver 2008 jre7 com.microsoft.sqlserver.sqljdbc4 with Hibernate 3.3.2
I found a lot of similar questions in different forums but none of the solutions I read worked.
I tried using the backtick
<property name="nameSpaces" type="string" >
<column name="`Name with spaces`" not-null="false" />
</property>
this is the error
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '`'.
I also tried to use the [] brakets but hibernate converted it in ` again.
<column name="[Name with spaces]" not-null="false" />
com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '`'.
Finally I also tried both of them
<column name="`[Name with spaces]`" not-null="false" />
or
without success.
Can someone help me? Is there any hibernate configuration I can change to work with these column names.
Thanks
The answer (by BilalDja) is hidden above in a comment. I found his answer helpful so I thought I would add the answer here for others with the same problem.
This issue is hard to debug, I had to dig really deep into the hibernate and jdbc code to finally find the "real" SQL statement that is created to get data from the database. I then copied its value and ran it manually on my SQL Server database. Straight away the syntax error was obvious and sure enough it was cause by a space in a column name.
To fix this I just escaped the double quotes around the problematic column name as explained in BilalDja's comments and expanded slightly here...
#Column(name = "\"Column name\"")
private String variableColumnWillMapTo;
That's it, problem solved, no more syntax error.

Liquibase + H2 + Junit Primary Key Sequence starts over

I managed to integrate Liquibase into our Maven build to initialize a H2 inmemory database with a few enrys. Those rows have the primary key generated using a sequence table which works as expected (BigInt incremented values starting from 1).
My issue is that when i try to persist a new entity into that table from within a Junit integration test i get a "unique key constraint violation" because that new entity has the same primary key as the very first row inserted using the Liquibase changelog-xmls.
So the initialisation works perfectly fine as expected. The maven build uses the liquibase changelog-xmls
For now i just wipe the according tables completly before any integration tests with an own Runner... but that wont be a possibility in the furture. Its currently quite a chalange to investigate such issues since there is not yet much specific information on Liquibase available.
Update Workaround
While id prefer below answer using H2 brings up the problem that below changeset wont work because the required minValue is not supported.
<changeSet author="liquibase-docs" id="alterSequence-example">
<alterSequence
incrementBy="1"
maxValue="371717"
minValue="40"
ordered="true"
schemaName="public"
sequenceName="seq_id"/>
As a simple workaround i now just drop the existing sequence that was used to insert my testdata in a second changeSet:
<changeSet id="2" author="Me">
<dropSequence
sequenceName="SEQ_KEY_MY_TBL"/>
<createSequence
sequenceName="SEQ_KEY_MY_TBL"
incrementBy="1"
startValue="40"/>
</changeSet>
This way the values configured in the changelog-*.xml will be inserted using the sequence with an initial value of 1. I insert 30 rows so Keys 1-30 are used. After that the sequence gets dropped and recreated with a higher startValue. This way when persisting entities from within a Junit based integration Test the new entities will have primary keys starting from 40 and the previous unique constraint problem is solved.
Not H2 will probably soon release a version supporting minValue/maxValue since the according patch already exists.
Update:
Maybe we should mention this still is just a Workaround, anyone knows if H2 supports a Sequence with Liquibase that wont start over after DB-Init?
You should instruct liquibase to set the start value for those sequences to a value beyond those you have used for the entries you created. Liquibase has an alterSequence element for this. You can add such elements at the end of your current liquibase script.

Java/Hibernate + HSQLDB java.sql.BatchUpdateException: data exception: string data, right truncation

I am testing an application locally using a memory-based HSQLDB.
So far everything went fine, however, when executing a testcase with a String bigger than 256 chars I ran into an error.
Caused by: java.sql.BatchUpdateException: data exception: string data, right truncation; table: TABLENAME column: COLNAME
at org.hsqldb.jdbc.JDBCPreparedStatement.executeBatch(Unknown Source)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 30 more
I gathered that the cause of this error is usually an "overflow" of the datatype one is using.
What bothers me is that I explicitly defined the column to be 4000 chars big, using the hbm.xml files.
<property name="translation" type="java.lang.String" length="4000">
<column name="COLNAME" not-null="false" />
</property>
When I cut the test string down to 256 chars or less everything starts working again. 257+ chars and the error is thrown. I don't really see the reason why this is happening. Why would HSQLDB define this column as length="256", when I explicitly state that it's supposed to be 4000...
Can anyone help?
Best regards,
daZza
Well, for whatever reason HSQLDB seems to do a bad mapping for certain types and values specified in the config file to the real tables it creates.
I was able to fix the issue by changing the "type" attribute to type=text. Now everything works perfectly. I just hope that after I finish testing the application it still works with the original MSSQL DB and maps text to a varchar then...

Categories