Spring Boot Kotlin集成FF4J遇BadSqlGrammarException,无法建表
Spring Boot Kotlin集成FF4J时数据库表无法自动创建问题排查
问题描述
在Spring Boot Kotlin项目中集成FF4J时,数据库架构未自动创建,调试显示数据源配置正常,但抛出BadSqlGrammarException。配置类及依赖如下:
配置类代码
@Configuration @ConditionalOnClass(FF4j::class) class FF4JConfiguration { @field:Value("\${spring.ff4j.datasource.url}") private lateinit var driverUrl: String @field:Value("\${spring.datasource.driver-class-name}") private lateinit var driverClass: String @field:Value("\${spring.datasource.username}") private lateinit var user: String @field:Value("\${spring.datasource.password}") private lateinit var password: String @Bean fun getFF4j(): FF4j { val source = MysqlDataSource() source.setURL(driverUrl) source.password = password source.user = user val fF4j = FF4j() fF4j.featureStore = FeatureStoreSpringJdbc().apply { setDataSource(source) } fF4j.propertiesStore = PropertyStoreSpringJdbc().apply { setDataSource(source) } fF4j.eventRepository = JdbcEventRepository(source) fF4j.audit(true) fF4j.autoCreate(true) return fF4j } }
依赖配置(build.gradle.kts)
implementation("org.ff4j:ff4j-core:1.8.12") implementation("org.ff4j:ff4j-web:1.8.12") implementation("org.ff4j:ff4j-store-springjdbc:1.8.12") implementation("mysql:mysql-connector-java:8.0.30")
原因分析
- FF4J版本与MySQL 8.0兼容性问题:FF4J 1.8.12是较旧版本,其Spring JDBC存储的建表SQL未适配MySQL 8.0的语法规范(比如使用了MySQL 8.0弃用的关键字、字符集配置),导致执行建表语句时触发
BadSqlGrammarException。 - 数据源未显式指定驱动类:配置中注入了
driverClass但未设置到MysqlDataSource中,虽然MySQL 8.0驱动可自动加载,但显式配置能避免潜在的版本适配问题。 autoCreate的作用误解:ff4j.autoCreate(true)仅负责特性/属性的自动创建,并不触发数据库表结构的初始化,FF4J的Spring JDBC存储不会主动执行建表脚本,需手动触发。
解决方案
1. 升级FF4J到兼容MySQL 8.0的版本
将FF4J依赖升级到2.x系列的最新稳定版,该版本已修复对MySQL 8.0的适配问题:
implementation("org.ff4j:ff4j-core:2.0.12") implementation("org.ff4j:ff4j-web:2.0.12") implementation("org.ff4j:ff4j-store-springjdbc:2.0.12")
2. 显式配置数据源驱动类
在创建MysqlDataSource时添加驱动类设置:
val source = MysqlDataSource().apply { setURL(driverUrl) password = password user = user driverClassName = driverClass // 新增此行 }
3. 手动触发表结构初始化
在配置存储时调用createSchema()方法,强制执行建表脚本:
@Bean fun getFF4j(): FF4j { val source = MysqlDataSource().apply { setURL(driverUrl) password = password user = user driverClassName = driverClass } // 初始化特性存储表 val featureStore = FeatureStoreSpringJdbc().apply { setDataSource(source) createSchema() } // 初始化属性存储表 val propertyStore = PropertyStoreSpringJdbc().apply { setDataSource(source) createSchema() } // 初始化事件存储表 val eventRepo = JdbcEventRepository(source).apply { createSchema() } return FF4j().apply { featureStore = featureStore propertiesStore = propertyStore eventRepository = eventRepo audit(true) autoCreate(true) } }
4. 使用FF4J Spring初始化器简化配置
通过FF4jSpringInitializer自动处理数据源配置与表初始化:
@Bean fun getFF4j(): FF4j { val source = MysqlDataSource().apply { setURL(driverUrl) password = password user = user driverClassName = driverClass } val initializer = FF4jSpringInitializer() initializer.setDataSource(source) initializer.createSchema() // 自动创建所有所需表 initializer.audit = true initializer.autoCreate = true return initializer.ff4j }
内容的提问来源于stack exchange,提问作者matrix
相关产品推荐
相关产品推荐

