How to specify utf8 encoding for db and tables, using embedded database MariaDB in Spring application? - spring

Developing web application I'd like to use an embedded database to store data. However instead of proposed in-memory databases I`d like to prefer to use custom one. My choice is MariaDB. I have been ruled with this article how to get MariaDB as embedded database in my project, everything is fine, database appears, except one thing: I cannot change an encoding for my tables values.
I tried to set additional application properties in my application.yml file, tried to complete connection string with parameters of specifying encoding, but all those stuff didn't work unfortunately :(
May any of you have ever faced with such problem and can help me? Thank you in advance!
My current application.yml is following:
mariaDB4j:
dataDir: ./localMariaDB
port: 3307
databaseName: embeddedDB
spring:
datasource:
url: jdbc:mariaDB://localhost:3307/
username: root
password:
driver-class-name: org.mariadb.jdbc.Driver
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate:
ddl-auto: create
And finally I get exception bellow:
Caused by: java.sql.SQLException: Incorrect string value: '\xD0\x92 \xD1\x80\xD0...' for column 'current_status' at row 1
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readErrorPacket(AbstractQueryProtocol.java:1688) ~[mariadb-java-client-2.6.2.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readPacket(AbstractQueryProtocol.java:1550) ~[mariadb-java-client-2.6.2.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.getResult(AbstractQueryProtocol.java:1513) ~[mariadb-java-client-2.6.2.jar:na]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:318) ~[mariadb-java-client-2.6.2.jar:na]
... 121 common frames omitted
By the way, when I run the application, the connection string which I get looks like jdbc:mysql://localhost:3307/embeddedDB.
I am confused why there is :mysql: instead of :mariadb: as specified in my connection properties. Does it have an influence on my database behavior?

So, I have found the resolution to my issue.
It appeared as usual very simple :)
To change standard character encoding, which MariaDB proposes, I had to specify additional configuration properties before setting up the MariaDB's DataSource.
As this source provides to configure MariaDBSpringService entity to further use in DataSourceconfiguration, it is necessary to extend it (MariaDBSpringService) with some character encoding description utils. So, to specify custom encoding (i.e. to change standard one) I've just added the following lines of code to MariaDBSpringService bean:
service.getConfiguration().addArg("--character-set-server=utf8mb4");
service.getConfiguration().addArg("--collation-server=utf8mb4_general_ci");
In general, the full bean declaration is below:
#Bean
public MariaDB4jSpringService mariaDB4jSpringService(){
MariaDB4jSpringService service = new MariaDB4jSpringService();
service.getConfiguration().addArg("--character-set-server=utf8mb4");
service.getConfiguration().addArg("--collation-server=utf8mb4_general_ci");
return service;
}
Hope, this will help somebody, who further can possibly face with such issue))
Thanks to everybody, who tried to help me!

Related

Spring Boot error with multiple data-sources :: dataSource or dataSourceClassName or jdbcUrl is required

I can see following error in my Intellij local for sometime now.
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
I have multiple data-sources configured for my project. Something similar as given below.
dataSource-1:
driverClassName: oracle.jdbc.OracleDriver
jdbc-url: so-and-so
datasource-2:
driver-class-name: org.postgresql.Driver
url: so-and-so
As you notice above, somewhere I'm using driverClassName, somewhere the 3 words are separated by hyphens.
So do I need to maintain the same standard in Spring-boot 2.0 across the entire yml file?
By standard, I mean,
driverClassName word would be the same in all places (driver-class-name)
jdbc-url/url text also need to be the same jdbcUrl in all places
This link in stackOverFlow discusses the same.
Please note, the hikari-config setter methods read the values properly in all the config classes wherever they are used, no issues with that.
Any help would be welcome.

H2: globally_quoted_identifiers seems not be taken into account

I use spring-boot 2.7.6 and H2 2.1.214.
To fix an issue due to the name of some columns that are also keywords in liquibase files (loaded to initialize the H2 database for tests) and entities, I tried to use the globally_quoted_identifiers property as defined here: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#_quoting_options
So I did it like this:
spring:
jpa:
properties:
hibernate:
globally_quoted_identifiers: true
But I still have the same errors due to keywords (org.h2.jdbc.JdbcSQLSyntaxErrorException) so I do not know if I use it correctly?
As a workaround I have to use NON_KEYWORDS=VALUE,KEY but I would like to manage all keywords globally.

Spring stateMachine persistance with Jpa

I got a problem with persister configuration. The problem is similar to Spring State machine - Table Scripts , but I dont want to generate tables by myself or with liquibase. So I'd like to use StateMachineJpaRepositoriesAutoConfiguration but I can't find info how I should enable it.
I already tried to use #ImportAutoConfiguration and do some stuff in property file, for example:
spring:
statemachine:
data:
jpa:
repositories:
enabled: true
But, unfortunately It didn't work for me, and I still get the error:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException:
Schema-validation: missing table [action]
Maybe the way with StateMachineJpaRepositoriesAutoConfiguration is not suitable here, so I'm needed any advice
Tried to use embedded H2 and all the tables was created. So the problem was in my spring.jpa.hibernate settings.
So it should be spring.jpa.generate-ddl=true and spring.jpa.hibernate.ddl-auto=create

Why is the placeholder not set properly in hikari.data-source-properties

I am setting the hikari.data-source-properties with a placeholder, but the placeholder value does not get substituted. It is a spring-boot 2.1.4.RELEASE based application. My intention is to set the Session properties so the DBAs can identify my application. Currently I get a default JDBC Thin Client for my connection when I run SELECT PROGRAM FROM V$SESSION from the DB
Below is what I have in my application.yml file
spring:
datasource:
url: "jdbc:oracle:thin:#machine:1521:service_name"
driver-class-name: "oracle.jdbc.driver.OracleDriver"
hikari.data-source-properties:
v$session.program:${spring.application.name}
Below is what I have in my bootstrap.yml file
spring:
application:
name: ms-db-service
When I query the Oracle DB, I notice that the value for program is literally ${spring.application.name}, instead of the expected value ms-db-service
I have tried the below, with same logical result:
Tried redefining the spring.application.name again in the application.yml
Tried using a different locally defined key ${name}
Added the following bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Tried specifying the property as such: spring.datasource.hikari.data-source-properties: v$session.program=${spring.application.name}
I tried the below items to gain more knowledge of the situation:
I tried using a placeholder for spring.datasource.url and that worked fine
I tried to read the value manually using the below code, and that shows the correct values: #Value("${spring.datasource.hikari.data-source-properties}") String propVal;
My conclusion is that HikariCp reads these values before the placeholder substitution is done. I don't understand the relative timing of when the substitution and datasource bean creation happen in the spring-boot bean life-cycle
I am trying to avoid using a bean for hikaricp datasource (not sure if that will even solve the issue), as I don't want to manually build the whole datasource as hikari supports huge number of properties.
So, how can I set the spring.datasource.hikari.data-source-properties in application.yml using a placeholder. And, is there any other way to assign spring.application.name to identify my current db connection?
You have to use it like this:
spring:
datasource:
hikari:
data-source-properties:
"[v$session.program]": ${spring.application.name}

Spring Boot: failed to load JNDI variables into yml configuration file

According to Spring Boot documentation about Externalized configuration, I tried to load a JNDI variable into my yml configuration file, like this:
spring:
# Show or not log for each sql query
jpa:
show-sql: java:global/bc-api-immop/hibernate/show_sql
And it doesn't work.
I have my variable in my JNDI context:
I also tried this:
spring:
# Show or not log for each sql query
jpa:
show-sql
jndi-name: java:global/bc-api-immop/hibernate/show_sql
But, still the same result.
Do you have any idea what I'm doing wrong?
As weird as it sounds, I also have this code, and it works:
spring:
# Set here configurations for the database connection
datasource:
jndi-name: java:jboss/datasources/bc-appli-as400-ds
Edit: When I do this, it works to (so my issue really comes from getting my JNDI variable):
spring:
# Show or not log for each sql query
jpa:
show-sql: true
The way you have written your yaml is the real problem here
The general concept is key: value so by writing show-sql spring boot expects a value of true or false as it appears on Appendix A. Common application properties so it is normal that your property configuration fails and I am pretty sure that this is showing up somewhere in your log files.
On the first example when you write show-sql: java:global/bc-api-immop/hibernate/show_sql you are actually answering the question "Should I show you the generated SQL statements" with "Hi spring Boot this is your datasource" which we both understand it makes no sence to spring boot :)
Your last statement, on the other hand, is correct. You are defining under the yaml collection item datasource the property jndi-name: with value java:jboss/datasources/bc-appli-as400-ds
I would also suggest spending 10 minutes to read this article Learn X in Y minutes
So a correct approach would probably be
spring:
# Set here configurations for the database connection
datasource:
jndi-name: java:jboss/datasources/bc-appli-as400-ds
jpa:
show-sql: true
Let me know if I can help you more

Resources