Spring Data JDBC Firebird dialect not recognized

前端 未结 5 931
谎友^
谎友^ 2021-01-13 19:28

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

相关标签:
5条回答
  • 2021-01-13 20:01

    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 from JdbcOperations, typically by inspecting Connection. You can let Spring auto-discover your Dialect by registering a class that implements org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider through META-INF/spring.factories. DialectResolver discovers dialect provider implementations from the class path using Spring’s SpringFactoriesLoader.

    To be able to use Firebird, you will need to define three things:

    1. A dialect
    2. A dialect resolver
    3. A config file for Spring to locate the dialect resolver

    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.

    0 讨论(0)
  • 2021-01-13 20:04

    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);
        }
    }
    
    0 讨论(0)
  • 2021-01-13 20:05

    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>
    
    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-01-13 20:18

    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:

    1. Implement the Dialect
    2. Provide a custom JDBC Configuration and override 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");
        }
    }
    
    0 讨论(0)
提交回复
热议问题