I\'m trying to connect to Firebird database using Spring Data JDBC and Spring Boot. I\'ve created a simple app using Spring Tools. Spring Data JDBC doesn\'t recognize the di
The Spring Data JDBC library itself does not contain a Firebird dialect out of the box, so you need to provide one yourself. How to do this is documented in Annotation-based Configuration of the Spring Data JDBC documentation:
Dialects are resolved by
JdbcDialectResolver
fromJdbcOperations
, typically by inspectingConnection
. You can let Spring auto-discover yourDialect
by registering a class that implementsorg.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider
throughMETA-INF/spring.factories
.DialectResolver
discovers dialect provider implementations from the class path using Spring’sSpringFactoriesLoader
.
To be able to use Firebird, you will need to define three things:
The dialect can be something like (note, this dialect assumes Firebird 3 or higher):
package spring.firebird;
import org.springframework.data.relational.core.dialect.AnsiDialect;
import org.springframework.data.relational.core.dialect.ArrayColumns;
import org.springframework.data.relational.core.dialect.LockClause;
import org.springframework.data.relational.core.sql.LockOptions;
public class FirebirdDialect extends AnsiDialect {
public static final FirebirdDialect INSTANCE = new FirebirdDialect();
@Override
public LockClause lock() {
return LOCK_CLAUSE;
}
@Override
public ArrayColumns getArraySupport() {
return ArrayColumns.Unsupported.INSTANCE;
}
private static final LockClause LOCK_CLAUSE = new LockClause() {
@Override
public String getLock(LockOptions lockOptions) {
return "WITH LOCK";
}
@Override
public Position getClausePosition() {
return Position.AFTER_ORDER_BY;
}
};
}
A dialect resolver to return the dialect if the connection is to a Firebird database.
package spring.firebird;
import org.springframework.data.jdbc.repository.config.DialectResolver;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcOperations;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Locale;
import java.util.Optional;
public class FirebirdDialectResolver implements DialectResolver.JdbcDialectProvider {
@Override
public Optional<Dialect> getDialect(JdbcOperations operations) {
return Optional.ofNullable(
operations.execute((ConnectionCallback<Dialect>) FirebirdDialectResolver::getDialect));
}
private static Dialect getDialect(Connection connection) throws SQLException {
DatabaseMetaData metaData = connection.getMetaData();
String name = metaData.getDatabaseProductName().toLowerCase(Locale.ROOT);
if (name.contains("firebird")) {
return FirebirdDialect.INSTANCE;
}
return null;
}
}
Finally, you need to define a resource in META-INF
with the name spring.factories
, this file must contain the line:
org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=spring.firebird.FirebirdDialectResolver
This allows Spring Data JDBC to discover the dialect resolver and use it.
Working solution for MariaDB / MySQL with Spring Boot 2.3.1.RELEASE
create directory/file if not exists: resources/META-INF/spring.factories
org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=com.yourapp.config.MariaDbDialectResolver
create class:
package com.yourapp.config;
import org.springframework.data.jdbc.repository.config.DialectResolver;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.MySqlDialect;
import org.springframework.jdbc.core.JdbcOperations;
import java.util.Optional;
public class MariaDbDialectResolver implements DialectResolver.JdbcDialectProvider {
@Override
public Optional<Dialect> getDialect(JdbcOperations jdbcOperations) {
return Optional.of(MySqlDialect.INSTANCE);
}
}
I Solve the problem with my colleague,my solution is (remove the dependency spring-boot-stater-data-jdbc keep the dependency spring-boot-starter-jdbc)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
I'm facing similar issues, but using Oracle DB.
The change I did in my project was simpler (I don't know if it will solve your problem with Spring Boot and Firebase)
Just replace HikariCP dependency with tomcat-jdbc in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
<!-- HikariCP doesn't deals with jdbcDialect properly -->
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
<!-- Dependency removed -->
</dependency>
<!-- Dependency to tomcat-jdbc to deal with jdbcDialect -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
<!--...-->
Good luck for you.
I found myself facing the same issue after upgrading to SB 2.3.0. Mark's excellent answer (which btw has found itself to Spring Data migration docs), helped me solve it, but I found that adding the extra configuration to META-INF
less than ideal.
My solution, extending from the original answer:
jdbcDialect()
:@Configuration
public class SpringDataJdbcConfiguration extends AbstractJdbcConfiguration {
@Override
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
return operations.getJdbcOperations().execute((ConnectionCallback<Dialect>)
connection -> isInformix(connection) ? InformixDialect.INSTANCE : super.jdbcDialect(operations));
}
private boolean isInformix(Connection connection) throws SQLException {
return connection.getMetaData().getDatabaseProductName().toUpperCase().contains("INFORMIX");
}
}