i18n data inserten met Spring framework via jdbTemplate

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
Hey,

het gaat over test automation code. De DB code is opgezet door een dev die niet meer in het team zit en spijtig genoeg heb ik weinig Spring kennis.
Ik heb problemen om via mijn code Chinese characters in de DB te inserten.
VALUELOCDESC kolom is een NCHAR in de Oracle 19c tabel.

Dit is mijn code om een DataSource bean te configureren:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public DataSource dataSourceBis() {
        logger.debug("Spring bean 'dataSource' created, configured in the testing module");
        String dbHost = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("db.host");
        String dbUser = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("db.bis.user");
        String dbPassword = EnvironmentSpecificConfiguration.from(environmentVariables).getProperty("db.bis.password");

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(oracle.jdbc.driver.OracleDriver.class.getName());
        dataSource.setUrl(dbHost);
        dataSource.setUsername(dbUser);
        dataSource.setPassword(dbPassword);
        Properties properties = new Properties();
        properties.setProperty("spring.datasource.hikari.data-source-properties.useUnicode", "yes");
        properties.setProperty("spring.datasource.hikari.data-source-properties.characterEncoding", "UTF-8");
        properties.setProperty("spring.datasource.hikari.data-source-properties.sqlScriptEncoding", "UTF-8");
        dataSource.setConnectionProperties(createUnicodeProperties());
        return dataSource;
    }

Regels 13-16 heb ik toegevoegd om unicode to the laten, maar geen succes, bleef omgekeerde vraagtekens hebben na de insert.

Dan heb ik mijn query aangepast om de Chinese characters juist te gebruiken:

Java:
1
2
3
4
5
6
7
8
9
10
11
        SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(parameterI18N);

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID, CHANGETS" +
                ") VALUES (" +
                ":parameter, unistr(:value), :description, :updatedById, :updatedTimestamp)";


        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
       getNamedParameterJdbcTemplate().update(insertSql, namedParameters, keyHolder, generatedIdFields);


unistr() lustte hij ook niet, gaf me altijd omgekeerde vraagtekens.

In DBeaver lukte deze query wel:
SQL:
1
INSERT INTO TBS085 (PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID) VALUES ('TEST1', N'点燃式四冲程', 'Parameter of Auto Test', 'MJORDAN')


Dus met een N voor de Chinese characters, daarop mijn java code aangepast:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(parameterI18N);

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID" +
                ") VALUES ('" +
                parameterI18N.getParameter() + "', " +
                "N'" + parameterI18N.getValue() + "', '" +
                parameterI18N.getDescription() + "', '" +
                parameterI18N.getUpdatedById() + "')";


        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getJdbcTemplate().update(insertSql, keyHolder, generatedIdFields);


Maar dat geeft me de volgende error bij runnen:
SQL state [99999]; error code [17004]; Invalid column type; nested exception is java.sql.SQLException: Invalid column type

Ik denk dat ik dus mijn code ergens wijs moet maken dat VALUELOCDESC een NCHAR type is, maar hoe?

Alle reacties


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 22:11

Creepy

Tactical Espionage Splatterer

Kan je de strings eens explicitiet utf8 maken? Ik heb hier geen Oracle bij de hand maar als de default locale van de machine waar je code draait geen utf8 is, dan kan ik me voorstellen dat het mis gaat.

Zie bij https://www.baeldung.com/java-string-encode-utf-8

[ Voor 13% gewijzigd door Creepy op 11-12-2021 10:32 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Creepy schreef op zaterdag 11 december 2021 @ 10:31:
Kan je de strings eens explicitiet utf8 maken?
Dat is nergens voor nodig.

https://niels.nu


Acties:
  • +2 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
@Chris_147 Sowieso wat je nu doet, gewoon inserts aan elkaar concatenaten, is gewoon absoluut niet hoe je dit wil doen. Je kunt de parameters gewoon in een key -> parameter map meegeven. Je moet die insert SQL dus terugzetten naar wat het was want dat stuk heb je nu echt kapot gemaakt.
Chris_147 schreef op vrijdag 10 december 2021 @ 16:45:
De DB code is opgezet door een dev die niet meer in het team zit en spijtig genoeg heb ik weinig Spring kennis.
En dat maakt uitleggen wat je precies moet doen nogal lastig.

https://www.baeldung.com/...ies-with-named-parameters

[ Voor 39% gewijzigd door Hydra op 12-12-2021 13:14 ]

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
@Hydra named parameters had ik eerst, maar hoe moet die dan in UTF-8 krijgen?

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Chris_147 schreef op zondag 12 december 2021 @ 15:10:
@Hydra named parameters had ik eerst, maar hoe moet die dan in UTF-8 krijgen?
Strings supporten gewoon utf-8 in Java, hoef je niks speciaals voor te doen. Het issue is waarschijnlijk de config van de Oracle driver. Probeer eens iets als useUnicode=yes&characterEncoding=UTF-8.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 22:11

Creepy

Tactical Espionage Splatterer

Of de default locale van de server. Vandaar mijn suggestie om ze bewust utf8 te maken zodat je daar niet afhankelijk van bent.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Creepy schreef op zondag 12 december 2021 @ 16:42:
Of de default locale van de server.
Locale heeft niks met UTF-8 support te maken in Java.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
Hydra schreef op zondag 12 december 2021 @ 15:14:
[...]


Strings supporten gewoon utf-8 in Java, hoef je niks speciaals voor te doen. Het issue is waarschijnlijk de config van de Oracle driver. Probeer eens iets als useUnicode=yes&characterEncoding=UTF-8.
Graag mijn eerste post lezen en ook de code, dat doe ik namelijk reeds.
Misschien foutief, geen idee hoe ik dat kan controleren. Ik zet het en krijg geen foutmeldingen daarover of bij het inserten, enkel wordt niet juist geinsert.

Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 22:27
Chris_147 schreef op zondag 12 december 2021 @ 19:04:
[...]


Graag mijn eerste post lezen en ook de code, dat doe ik namelijk reeds.
Misschien foutief, geen idee hoe ik dat kan controleren. Ik zet het en krijg geen foutmeldingen daarover of bij het inserten, enkel wordt niet juist geinsert.
Maar in regel 13 tm 15 maak je properties die je niet aan je datasource koppelt. Tenminste... Je gebruikt ze niet als input parameter voor setConnectionProperties().

Wat doet die aanroep in regel 16 precies? Die gebruikt niet je properties blijkbaar.

Deze methode bedoel ik dan:
code:
1
createUnicodeProperties()


Ik zou eerder
code:
1
dataSource.setConnectionProperties(properties);

verwachten op regel 16.


Edit:
Had je dit ook al geprobeerd? Het tweede antwoord lijkt het probleem bij de Oracle driver te leggen en op te lossen met een extra lib. https://stackoverflow.com...stead-of-unicode/44992955

[ Voor 14% gewijzigd door Merethil op 12-12-2021 20:30 ]


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
Oh sorry, createUnicodeProperties is eigenlijk gewoon die 3 regels voorgaande regels. Had ik zo in mijn code staan, maar expliciet gezet om het code voorbeeld kleiner te maken, echter regel 16 vergeten aan te passen.

Ivm je edit: ik ga die orai18n.jar eens opzoeken, bedankt

Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
Lukt nog niet.
In mijn POM heb ik de orai18n dependency toegevoegd:
XML:
1
2
3
4
5
6
7
8
9
10
        <dependency>
            <groupId>oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.ojdbc</groupId>
            <artifactId>orai18n</artifactId>
            <version>19.3.0.0</version>
        </dependency>


In mijn code heb ik het eerst geprobeerd met expliciet UTF-8 te maken:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        ByteBuffer valueBuffer = StandardCharsets.UTF_8.encode(parameterI18N.getValue());
        String valueUtf8 = StandardCharsets.UTF_8.decode(valueBuffer).toString();

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID" +
                ") VALUES ('" +
                parameterI18N.getParameter() + "', '" +
                valueUtf8 + "', '" +
                parameterI18N.getDescription() + "', '" +
                parameterI18N.getUpdatedById() + "')";


        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getJdbcTemplate().update(insertSql, keyHolder, generatedIdFields);


Nog steeds error: Caused by: java.sql.SQLException: Invalid column type
Ik denk dus nog steeds dat ik op een of andere manier duidelijk moet maken dat dit een NCHAR kolom is.


Dan heb ik zoals @Hydra zegt dat ik het moet doen (en zoals ik eerst al deed):

Java:
1
2
3
4
5
6
7
8
        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID, CHANGETS" +
                ") VALUES (" +
                ":parameter, unistr(:value), :description, :updatedById, :updatedTimestamp)";

        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getNamedParameterJdbcTemplate().update(insertSql, namedParameters, keyHolder, generatedIdFields);


Dan heb ik weer in mijn tabel: ¿¿¿¿¿¿
Dat is ook met orai18n in de pom file.
Het lijkt me dat UTF-8 tekst gewoon wordt omgezet in iets anders.

Acties:
  • 0 Henk 'm!

  • The Eagle
  • Registratie: Januari 2002
  • Nu online

The Eagle

I wear my sunglasses at night

Altijd leuk dit soort dingen.
Die tabel die je met dbeaver gebruikt is een andere dan in je scripts. Leg ze qua definitie eens naast elkaar, zit daar wellicht een fout?

Verder: doe een canary test. Dus gewoon een simpele insert laten werken van een enkel veld. En dan pas verder bouwen.

Al is het nieuws nog zo slecht, het wordt leuker als je het op zijn Brabants zegt :)


Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 22:27
Chris_147 schreef op maandag 13 december 2021 @ 08:41:
Lukt nog niet.
In mijn POM heb ik de orai18n dependency toegevoegd:
XML:
1
2
3
4
5
6
7
8
9
10
        <dependency>
            <groupId>oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.ojdbc</groupId>
            <artifactId>orai18n</artifactId>
            <version>19.3.0.0</version>
        </dependency>


In mijn code heb ik het eerst geprobeerd met expliciet UTF-8 te maken:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        ByteBuffer valueBuffer = StandardCharsets.UTF_8.encode(parameterI18N.getValue());
        String valueUtf8 = StandardCharsets.UTF_8.decode(valueBuffer).toString();

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID" +
                ") VALUES ('" +
                parameterI18N.getParameter() + "', '" +
                valueUtf8 + "', '" +
                parameterI18N.getDescription() + "', '" +
                parameterI18N.getUpdatedById() + "')";


        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getJdbcTemplate().update(insertSql, keyHolder, generatedIdFields);


Nog steeds error: Caused by: java.sql.SQLException: Invalid column type
Ik denk dus nog steeds dat ik op een of andere manier duidelijk moet maken dat dit een NCHAR kolom is.


Dan heb ik zoals @Hydra zegt dat ik het moet doen (en zoals ik eerst al deed):

Java:
1
2
3
4
5
6
7
8
        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID, CHANGETS" +
                ") VALUES (" +
                ":parameter, unistr(:value), :description, :updatedById, :updatedTimestamp)";

        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getNamedParameterJdbcTemplate().update(insertSql, namedParameters, keyHolder, generatedIdFields);


Dan heb ik weer in mijn tabel: ¿¿¿¿¿¿
Dat is ook met orai18n in de pom file.
Het lijkt me dat UTF-8 tekst gewoon wordt omgezet in iets anders.
Heb je wel nog steeds UTF-8 in je properties voor de connectie staan? Eventueel vervangen door de meer generieke datasource properties zodat ze ook werken als je per ongeluk géén hikari pool gebruikt:

code:
1
2
3
spring.datasource.sqlScriptEncoding=UTF-8
spring.datasource.characterEncoding
spring.datasource.useUnicode=yes


Edit:
De link in mijn vorige post linkte weer door naar deze pagina van Oracle:
https://docs.oracle.com/d...DBC/global.htm#JJDBC28646
Hier geven ze aan om een specifieke property voor drivers op versie 10.1+ aan te zetten:
The default value of defaultNChar is false. If the value of defaultNChar is false, then you must call the setFormOfUse(<column_Index>, OraclePreparedStatement.FORM_NCHAR) method for those columns that specifically need national-language characters. For example:
code:
1
2
3
4
5
6
PreparedStatement pstmt =
conn.prepareStatement("insert into TEST values(?,?,?)");
pstmt.setFormOfUse(1, OraclePreparedStatement.FORM_NCHAR);
pstmt.setString(1, myUnicodeString1); // NCHAR column
pstmt.setFormOfUse(2, OraclePreparedeStatement.FORM_NCHAR);
pstmt.setString(2, myUnicodeString2); // NVARCHAR2 column

...

If you prefer, then you can also specify defaultNChar as a connection property and access NCHAR, NVARCHAR2, or NCLOB data.
code:
1
2
3
4
5
Properties props = new Properties();
props.put(OracleConnection.CONNECTION_PROPERTY_DEFAULTNCHAR, "true");
// set URL, username, password, and so on.
...
Connection conn = DriverManager.getConnection(props);


If the value of defaultNChar is true, then you should call the setFormOfUse(<column_Index>, FORM_CHAR) for columns that do not need national-language characters. For example:
code:
1
2
3
4
PreparedStatement pstmt =
conn.prepareStatement("insert into TEST values(?,?,?)");
pstmt.setFormOfUse(3, OraclePreparedStatement.FORM_CHAR);
pstmt.setString(3, myString); // CHAR column
Het volgende lijkt mij dus nodig in jouw geval:
code:
1
properties.put(OracleConnection.CONNECTION_PROPERTY_DEFAULTNCHAR, "true");

[ Voor 25% gewijzigd door Merethil op 13-12-2021 09:07 ]


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
OK, mijn idee dat de code een verkeerde kolom type nam, was juist.
Ik heb de code als volgt aangepast:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        MapSqlParameterSource namedParameters = new MapSqlParameterSource();
        namedParameters.addValue("parameter", parameterI18N.getParameter(), Types.CHAR);
        namedParameters.addValue("value", parameterI18N.getValue(), Types.NCHAR);
        namedParameters.addValue("description", parameterI18N.getDescription(), Types.VARCHAR);
        namedParameters.addValue("updatedById", parameterI18N.getUpdatedById(), Types.CHAR);
        namedParameters.addValue("updatedTimestamp", parameterI18N.getUpdatedTimestamp(), Types.TIMESTAMP);

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID, CHANGETS" +
                ") VALUES (" +
                ":parameter, :value, :description, :updatedById, :updatedTimestamp)";

        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getNamedParameterJdbcTemplate().update(insertSql, namedParameters, keyHolder, generatedIdFields);

Nu zet ik dus expliciet NCHAR voor de value klom en dan krijg ik wel netjes mijn Chinese tekst in de tabel.
Geen idee hoe ik een SqlParameterSource wijs kan maken wat te kolomtypes zijn. Daar heb je namelijk geen addValue methode.

Toch bedankt allemaal voor het meedenken!

Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 22:27
Chris_147 schreef op maandag 13 december 2021 @ 09:13:
OK, mijn idee dat de code een verkeerde kolom type nam, was juist.
Ik heb de code als volgt aangepast:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        MapSqlParameterSource namedParameters = new MapSqlParameterSource();
        namedParameters.addValue("parameter", parameterI18N.getParameter(), Types.CHAR);
        namedParameters.addValue("value", parameterI18N.getValue(), Types.NCHAR);
        namedParameters.addValue("description", parameterI18N.getDescription(), Types.VARCHAR);
        namedParameters.addValue("updatedById", parameterI18N.getUpdatedById(), Types.CHAR);
        namedParameters.addValue("updatedTimestamp", parameterI18N.getUpdatedTimestamp(), Types.TIMESTAMP);

        String insertSql = "INSERT INTO TBLI18N (" +
                "PARAMID, VALUELOCDESC, PARAMETERDESC, ICDSID, CHANGETS" +
                ") VALUES (" +
                ":parameter, :value, :description, :updatedById, :updatedTimestamp)";

        KeyHolder keyHolder = new GeneratedKeyHolder();
        String[] generatedIdFields = {"NIDTBLI18N"};
        getNamedParameterJdbcTemplate().update(insertSql, namedParameters, keyHolder, generatedIdFields);

Nu zet ik dus expliciet NCHAR voor de value klom en dan krijg ik wel netjes mijn Chinese tekst in de tabel.
Geen idee hoe ik een SqlParameterSource wijs kan maken wat te kolomtypes zijn. Daar heb je namelijk geen addValue methode.

Toch bedankt allemaal voor het meedenken!
Waarschijnlijk doet jouw code nu expliciet wat er in mijn eerste codefragment van mijn laatste edit staat. Ik gok dat hij het wel snapt met SqlParameterSource als je de property omzet voor de oracle driver, maar dan zou het kunnen dat je weer expliciet non-NCHAR aan moet geven bij de overige velden :+

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Graag als iemand je probeert te helpen iets vriendelijker reageren.

https://niels.nu


Acties:
  • 0 Henk 'm!

  • Chris_147
  • Registratie: Juni 2005
  • Laatst online: 25-07 15:43
Hydra schreef op maandag 13 december 2021 @ 09:40:
[...]


Graag als iemand je probeert te helpen iets vriendelijker reageren.
Hey, bedankt voor je hulp, maar geef gewoon toe dat je mijn eerste post niet goed had gelezen en dat enkel NamedParameters niet de oplossing was.

Persoonlijk vond ik mijn reactie niet onvriendelijk. Dat jij die als onvriendelijk opvatte is niet mijn fout.
Maar soit, nogmaals bedankt voor je tijd, wordt zeker geapprecieerd, echt waar!

Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Chris_147 schreef op maandag 13 december 2021 @ 10:48:
Hey, bedankt voor je hulp, maar geef gewoon toe dat je mijn eerste post niet goed had gelezen en dat enkel NamedParameters niet de oplossing was.
Ik had je post prima gelezen en heb aangegeven dat je niet de code moest aanpassen maar dat het probleem de driver settings waarschijnlijk waren dan dat je dus zeker moest weten dat de uiteindelijke JDBC URL (dus niet je Hikari settings!!) correct was, als een begin. Ik wou eerst dat je die code terug ging zetten omdat je het hiermee nogal stuk had gemaakt en als je overal dingen aan gaat passen, het voor iedereen onduidelijk wordt waar het probleem nu zit.

Het probleem is 100% database / driver settings. Dat probeerde ik je duidelijk te maken.

https://niels.nu

Pagina: 1