SQL 服务器的 Liquibase NoSuchMethodError

Liquibase NoSuchMethodError with SQL Server

当 运行 我的 Liquibase 设置时出现以下错误:

Caused by: java.lang.NoSuchMethodError: liquibase.database.Database.escapeTableName(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

我真的不知道我的初始模式文件有什么问题,有更多经验的人可以帮我找出错误吗?如果我不得不猜测它很可能是文件中的某些内容,我必须更改它以使其与 SQL 服务器兼容,但我无法找到导致异常的原因。

<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
    http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

    <property name="now" value="now()" dbms="mysql,h2"/>
    <property name="now" value="current_timestamp" dbms="postgresql"/>
    <property name="now" value="GETDATE()" dbms="mssql"/>

    <changeSet id="00000000000000" author="jhipster" dbms="postgresql">
        <createSequence sequenceName="hibernate_sequence" startValue="1000" incrementBy="1"/>
    </changeSet>

    <!--
        JHipster core tables.
        The initial schema has the '00000000000001' id, so that it is over-written if we re-generate it.
    -->
    <changeSet id="00000000000001" author="jhipster">
        <createTable tableName="JHI_USER">
            <column name="id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="login" type="varchar(50)">
                <constraints unique="true" nullable="false"/>
            </column>
            <column name="password" type="varchar(100)"/>
            <column name="first_name" type="varchar(50)"/>
            <column name="last_name" type="varchar(50)"/>
            <column name="email" type="varchar(100)">
                <constraints unique="true"/>
            </column>
            <column name="activated" type="boolean" valueBoolean="false">
                <constraints nullable="false" />
            </column>
            <column name="lang_key" type="varchar(5)"/>
            <column name="activation_key" type="varchar(20)"/>
            <column name="reset_key" type="varchar(20)"/>
            <column name="created_by" type="varchar(50)">
                <constraints nullable="false"/>
            </column>
            <column name="created_date" type="timestamp" defaultValueDate="${now}">
                <constraints nullable="false"/>
            </column>
            <column name="reset_date" type="timestamp">
                <constraints nullable="true"/>
            </column>
            <column name="last_modified_by" type="varchar(50)"/>
            <column name="last_modified_date" type="timestamp"/>
        </createTable>

        <createIndex indexName="idx_user_login"
            tableName="JHI_USER"
            unique="true">
            <column name="login" type="varchar(50)"/>
        </createIndex>

        <createIndex indexName="idx_user_email"
            tableName="JHI_USER"
            unique="true">
            <column name="email" type="varchar(100)"/>
        </createIndex>

        <createTable tableName="JHI_AUTHORITY">
            <column name="name" type="varchar(50)">
                <constraints primaryKey="true" nullable="false"/>
            </column>
        </createTable>

        <createTable tableName="JHI_USER_AUTHORITY">
            <column name="user_id" type="bigint">
                <constraints nullable="false"/>
            </column>
            <column name="authority_name" type="varchar(50)">
                <constraints nullable="false"/>
            </column>
        </createTable>

        <addPrimaryKey columnNames="user_id, authority_name" tableName="JHI_USER_AUTHORITY"/>

        <createTable tableName="JHI_PERSISTENT_TOKEN">
            <column name="series" type="varchar(255)">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="user_id" type="bigint"/>
            <column name="token_value" type="varchar(255)">
                <constraints nullable="false" />
            </column>
            <column name="token_date" type="date"/>
            <column name="ip_address" type="varchar(39)"/>
            <column name="user_agent" type="varchar(255)"/>
        </createTable>

        <addForeignKeyConstraint baseColumnNames="authority_name"
                                 baseTableName="JHI_USER_AUTHORITY"
                                 constraintName="fk_authority_name"
                                 referencedColumnNames="name"
                                 referencedTableName="JHI_AUTHORITY"/>

        <addForeignKeyConstraint baseColumnNames="user_id"
                                 baseTableName="JHI_USER_AUTHORITY"
                                 constraintName="fk_user_id"
                                 referencedColumnNames="id"
                                 referencedTableName="JHI_USER"/>

        <addForeignKeyConstraint baseColumnNames="user_id"
                                 baseTableName="JHI_PERSISTENT_TOKEN"
                                 constraintName="fk_user_persistent_token"
                                 referencedColumnNames="id"
                                 referencedTableName="JHI_USER"/>

        <ext:loadData encoding="UTF-8"
                  file="config/liquibase/users.csv"
                  separator=";"
                  tableName="JHI_USER" identityInsertEnabled="true">
            <column name="activated" type="boolean"/>
            <column name="created_date" type="timestamp"/>
        </ext:loadData>
        <dropDefaultValue tableName="JHI_USER" columnName="created_date" columnDataType="datetime"/>

        <ext:loadData encoding="UTF-8"
                      file="config/liquibase/authorities.csv"
                      separator=";"
                      tableName="JHI_AUTHORITY"
                      identityInsertEnabled="true" />

        <ext:loadData encoding="UTF-8"
                      file="config/liquibase/users_authorities.csv"
                      separator=";"
                      tableName="JHI_USER_AUTHORITY"
                      identityInsertEnabled="true" />

        <createTable tableName="JHI_PERSISTENT_AUDIT_EVENT">
            <column name="event_id" type="bigint" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="principal" type="varchar(255)">
                <constraints nullable="false" />
            </column>
            <column name="event_date" type="timestamp"/>
            <column name="event_type" type="varchar(255)"/>
        </createTable>

        <createTable tableName="JHI_PERSISTENT_AUDIT_EVENT_DATA">
            <column name="event_id" type="bigint">
                <constraints nullable="false"/>
            </column>
            <column name="name" type="varchar(255)">
                <constraints nullable="false"/>
            </column>
            <column name="value" type="varchar(255)"/>
        </createTable>
        <addPrimaryKey columnNames="event_id, name" tableName="JHI_PERSISTENT_AUDIT_EVENT_DATA"/>

        <createIndex indexName="idx_persistent_audit_event"
                     tableName="JHI_PERSISTENT_AUDIT_EVENT"
                     unique="false">
            <column name="principal" type="varchar(255)"/>
            <column name="event_date" type="timestamp"/>
        </createIndex>

        <createIndex indexName="idx_persistent_audit_event_data"
                     tableName="JHI_PERSISTENT_AUDIT_EVENT_DATA"
                     unique="false">
            <column name="event_id" type="bigint"/>
        </createIndex>

        <addForeignKeyConstraint baseColumnNames="event_id"
                                 baseTableName="JHI_PERSISTENT_AUDIT_EVENT_DATA"
                                 constraintName="FK_event_persistent_audit_event_data"
                                 referencedColumnNames="event_id"
                                 referencedTableName="JHI_PERSISTENT_AUDIT_EVENT"/>
    </changeSet>

</databaseChangeLog>

这是错误的完整堆栈跟踪:

Caused by: java.lang.NoSuchMethodError: liquibase.database.Database.escapeTableName(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    at liquibase.ext.mssql.sqlgenerator.InsertGenerator.generateSql(InsertGenerator.java:37)
    at liquibase.ext.mssql.sqlgenerator.InsertGenerator.generateSql(InsertGenerator.java:18)
    at liquibase.sqlgenerator.SqlGeneratorChain.generateSql(SqlGeneratorChain.java:30)
    at liquibase.sqlgenerator.SqlGeneratorFactory.generateSql(SqlGeneratorFactory.java:208)
    at liquibase.executor.AbstractExecutor.applyVisitors(AbstractExecutor.java:23)
    at liquibase.executor.jvm.JdbcExecutor.access0(JdbcExecutor.java:36)
    at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:304)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:55)
    at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:122)
    at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1227)
    at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1210)
    at liquibase.changelog.ChangeSet.execute(ChangeSet.java:550)
    at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:43)
    at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:73)
    at liquibase.Liquibase.update(Liquibase.java:200)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:353)
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:317)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    ... 107 more

赏金后编辑:

我 运行 使用 Spring 引导配置,运行 使用 jHipster

我的数据库配置在这里:

Spring开机Application.java

@ComponentScan
@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
public class Application {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    @Inject
    private Environment env;

    /**
     * Initializes winserver.
     * <p/>
     * Spring profiles can be configured with a program arguments --spring.profiles.active=your-active-profile
     * <p/>
     * <p>
     * You can find more information on how profiles work with JHipster on <a href="http://jhipster.github.io/profiles.html">http://jhipster.github.io/profiles.html</a>.
     * </p>
     */
    @PostConstruct
    public void initApplication() throws IOException {
        if (env.getActiveProfiles().length == 0) {
            log.warn("No Spring profile configured, running with default configuration");
        } else {
            log.info("Running with Spring profile(s) : {}", Arrays.toString(env.getActiveProfiles()));
            Collection activeProfiles = Arrays.asList(env.getActiveProfiles());
            if (activeProfiles.contains("dev") && activeProfiles.contains("prod")) {
                log.error("You have misconfigured your application! " +
                    "It should not run with both the 'dev' and 'prod' profiles at the same time.");
            }
            if (activeProfiles.contains("prod") && activeProfiles.contains("fast")) {
                log.error("You have misconfigured your application! " +
                    "It should not run with both the 'prod' and 'fast' profiles at the same time.");
            }
            if (activeProfiles.contains("dev") && activeProfiles.contains("cloud")) {
                log.error("You have misconfigured your application! " +
                    "It should not run with both the 'dev' and 'cloud' profiles at the same time.");
            }
        }
    }

    /**
     * Main method, used to run the application.
     */
    public static void main(String[] args) throws UnknownHostException {
        SpringApplication app = new SpringApplication(Application.class);
        app.setShowBanner(false);
        SimpleCommandLinePropertySource source = new SimpleCommandLinePropertySource(args);
        addDefaultProfile(app, source);
        addLiquibaseScanPackages();
        Environment env = app.run(args).getEnvironment();
        log.info("Access URLs:\n----------------------------------------------------------\n\t" +
            "Local: \t\thttp://127.0.0.1:{}\n\t" +
            "External: \thttp://{}:{}\n----------------------------------------------------------",
            env.getProperty("server.port"),
            InetAddress.getLocalHost().getHostAddress(),
            env.getProperty("server.port"));

    }

    /**
     * If no profile has been configured, set by default the "dev" profile.
     */
    private static void addDefaultProfile(SpringApplication app, SimpleCommandLinePropertySource source) {
        if (!source.containsProperty("spring.profiles.active") &&
                !System.getenv().containsKey("SPRING_PROFILES_ACTIVE")) {

            app.setAdditionalProfiles(Constants.SPRING_PROFILE_DEVELOPMENT);
        }
    }

    /**
     * Set the liquibases.scan.packages to avoid an exception from ServiceLocator.
     */
    private static void addLiquibaseScanPackages() {
        System.setProperty("liquibase.scan.packages", Joiner.on(",").join(
            "liquibase.change", "liquibase.database", "liquibase.parser",
            "liquibase.precondition", "liquibase.datatype",
            "liquibase.serializer", "liquibase.sqlgenerator", "liquibase.executor",
            "liquibase.snapshot", "liquibase.logging", "liquibase.diff",
            "liquibase.structure", "liquibase.structurecompare", "liquibase.lockservice",
            "liquibase.ext", "liquibase.changelog"));
    }
}

DatabaseConfiguration.java

@Configuration
@EnableJpaRepositories("com.winserver.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
@EnableTransactionManagement
public class DatabaseConfiguration implements EnvironmentAware {

    private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);

    private RelaxedPropertyResolver propertyResolver;

    private Environment env;

    @Autowired(required = false)
    private MetricRegistry metricRegistry;

    @Override
    public void setEnvironment(Environment env) {
        this.env = env;
        this.propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");
    }

    @Bean(destroyMethod = "shutdown")
    @ConditionalOnMissingClass(name = "com.winserver.config.HerokuDatabaseConfiguration")
    @Profile("!" + Constants.SPRING_PROFILE_CLOUD)
    public DataSource dataSource() {
        log.debug("Configuring Datasource");
        if (propertyResolver.getProperty("url") == null && propertyResolver.getProperty("databaseName") == null) {
            log.error("Your database connection pool configuration is incorrect! The application" +
                    " cannot start. Please check your Spring profile, current profiles are: {}",
                    Arrays.toString(env.getActiveProfiles()));

            throw new ApplicationContextException("Database connection pool is not configured correctly");
        }
        HikariConfig config = new HikariConfig();
        config.setDataSourceClassName(propertyResolver.getProperty("dataSourceClassName"));
        if(StringUtils.isEmpty(propertyResolver.getProperty("url"))) {
            config.addDataSourceProperty("databaseName", propertyResolver.getProperty("databaseName"));
            config.addDataSourceProperty("serverName", propertyResolver.getProperty("serverName"));
        } else {
            config.addDataSourceProperty("url", propertyResolver.getProperty("url"));
        }
        config.addDataSourceProperty("user", propertyResolver.getProperty("username"));
        config.addDataSourceProperty("password", propertyResolver.getProperty("password"));

        //MySQL optimizations, see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
        if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(propertyResolver.getProperty("dataSourceClassName"))) {
            config.addDataSourceProperty("cachePrepStmts", propertyResolver.getProperty("cachePrepStmts", "true"));
            config.addDataSourceProperty("prepStmtCacheSize", propertyResolver.getProperty("prepStmtCacheSize", "250"));
            config.addDataSourceProperty("prepStmtCacheSqlLimit", propertyResolver.getProperty("prepStmtCacheSqlLimit", "2048"));
        }
        if (metricRegistry != null) {
            config.setMetricRegistry(metricRegistry);
        }
        return new HikariDataSource(config);
    }

    @Bean
    public SpringLiquibase liquibase(DataSource dataSource) {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog("classpath:config/liquibase/master.xml");
        liquibase.setContexts("development, production");
        if (env.acceptsProfiles(Constants.SPRING_PROFILE_FAST)) {
            if ("org.h2.jdbcx.JdbcDataSource".equals(propertyResolver.getProperty("dataSourceClassName"))) {
                liquibase.setShouldRun(true);
                log.warn("Using '{}' profile with H2 database in memory is not optimal, you should consider switching to" +
                    " MySQL or Postgresql to avoid rebuilding your database upon each start.", Constants.SPRING_PROFILE_FAST);
            } else {
                liquibase.setShouldRun(false);
            }
        } else {
            log.debug("Configuring Liquibase");
        }
        return liquibase;
    }

    @Bean
    public Hibernate4Module hibernate4Module() {
        return new Hibernate4Module();
    }
}

申请-dev.yml

server:
    port: 8080

spring:
    profiles:
        active: dev
    datasource:
        driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
        dataSourceClassName: com.microsoft.sqlserver.jdbc.SQLServerDataSource
        url: jdbc:sqlserver://localhost:1433;databaseName=test
        databaseName:
        serverName:
        username: user
        password: supersecretpassword
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true

    jpa:
        database-platform: org.hibernate.dialect.SQLServerDialect
        database: SQLServer
        openInView: false
        show_sql: true
        generate-ddl: false
        hibernate:
            ddl-auto: none
            naming-strategy: org.hibernate.cfg.EJB3NamingStrategy
        properties:
            hibernate.cache.use_second_level_cache: true
            hibernate.cache.use_query_cache: false
            hibernate.generate_statistics: true
            hibernate.cache.region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
    messages:
        cache-seconds: 1
    thymeleaf:
        mode: XHTML
        cache: false

metrics:
    jmx.enabled: true
    spark:
        enabled: false
        host: localhost
        port: 9999
    graphite:
        enabled: false
        host: localhost
        port: 2003
        prefix: winserver

cache:
    timeToLiveSeconds: 3600
    ehcache:
        maxBytesLocalHeap: 16M

请检查您的 liquidbase 配置,尤其是负责 mssql 集成的 jar 文件。 liquidbase git 存储库上可用的 mssql 集成与 liquibase 3.X 不兼容,应该抛出 NoSuchMethodError。

有关较新的集成,请参阅 https://liquibase.jira.com/wiki/display/CONTRIB/MS+SqlServer+Extensions

或者,尝试在所有 loadData 中设置 identityInsertEnabled='false'。

编辑: 在@Eric 将他的决议作为评论发布在下面之后,我要再次强调,以前的过时版本的 liquidbase-mssql.jar 可能潜伏在类路径中的某个地方。