休眠并使用 @GeneratedValue 和 CockroachDB 导致 SQLGrammarException
Hibernate and using @GeneratedValue with CockroachDB results in SQLGrammarException
以下最小示例使用生成的 id Spring Boot、Hibernate、JpaRepository、CockroachDB 和 Kotlin 生成 org.hibernate.exception.SQLGrammarException
.
我还使用 PostgresSQL 而不是 CockroachDB 进行了测试,这很好。
|------------------------------------------------|
| | PostgresSQL | CockroachDB |
|-----------------+---------------+--------------|
| no generated id | OK | OK |
| generated id | OK | ERROR |
|------------------------------------------------|
这是重现问题的代码。
./src/main/kotlin/ThingService.kt
:
package things
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table
import javax.persistence.Column
import javax.persistence.GeneratedValue
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.data.jpa.repository.JpaRepository
import com.fasterxml.jackson.annotation.JsonIgnore
interface ThingRepository : JpaRepository<Thing, Long> {
}
@RestController
class ThingController(private val repository: ThingRepository) {
@PutMapping("/thing/")
fun save(@RequestBody t:Thing): Thing
= repository.save(t)
}
@Entity
data class Thing (
@Column(name="value")
var value: String,
@Id
@GeneratedValue
@Column(name="id")
@JsonIgnore
var id: Long = -1
)
@SpringBootApplication
class Application {
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
./src/main/resources/application.properties
:
server.port=8082
spring.datasource.url=jdbc:postgresql://localhost:26257/things_db?sslmode=disable
spring.datasource.username=root
spring.datasource.password=123
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.hibernate.ddl-auto=update
./build.gradle.kts
:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
val kotlinVersion = "1.2.20"
id("org.springframework.boot") version "2.0.0.RELEASE"
id("org.jetbrains.kotlin.jvm") version kotlinVersion
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
id("io.spring.dependency-management") version "1.0.4.RELEASE"
}
version = "1.0.0-SNAPSHOT"
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}
val test by tasks.getting(Test::class) {
useJUnitPlatform()
}
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
compile("org.hibernate:hibernate-core")
compile("org.springframework.retry:spring-retry:1.2.2.RELEASE")
compile("org.postgresql:postgresql")
compile("org.json:json:20180130")
testCompile("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
以下是重现问题的步骤。
下载并初始化 CockroachDB:
# download
wget -qO- https://binaries.cockroachdb.com/cockroach-v1.1.6.linux-amd64.tgz | tar xvz
# start
./cockroach-v1.1.6.linux-amd64/cockroach start --insecure
# leave terminal open in background
# init
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "CREATE USER root WITH PASSWORD '123';"
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "CREATE DATABASE things_db;"
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "GRANT ALL ON DATABASE things_db TO root;"
运行数据服务:
gradle bootRun
现在尝试将一个东西放入服务中:
curl -w "\n" -H 'Content-Type: application/json' -X PUT -d '{"value":"foo", "id":123}' http://localhost:8082/thing/
响应是:
{"timestamp":"2018-03-19T13:05:12.856+0000","status":500,"error":"Internal Server Error","message":"could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet","path":"/thing/"}
然而,当使用 PostgreSQL 代替 CockroachDB 时,结果很好
{"value":"foo","id":123}
知道导致问题的原因或使用 CockroachDB 时如何避免该问题吗?
这是完整的日志:
Spring 日志有以下条目:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "sequence"
Detail: source SQL:
create sequence hibernate_sequence start 1 increment 1
CockroachDB 1.x 不支持序列,但它们在 2.0 中,即 still in beta。 Beta 状态确实意味着它还没有准备好用于生产,但如果您只是在玩 CockroachDB,它可能没问题。
CockroachDB 2.0 中的序列遵循 postgres 语法和行为,但 cycle
(尚未实现)除外。这里使用的语句不用它,只用START 1 INCREMENT 1
.
您可以在 CockroachDB docs.
中找到有关序列的更多详细信息
以下最小示例使用生成的 id Spring Boot、Hibernate、JpaRepository、CockroachDB 和 Kotlin 生成 org.hibernate.exception.SQLGrammarException
.
我还使用 PostgresSQL 而不是 CockroachDB 进行了测试,这很好。
|------------------------------------------------|
| | PostgresSQL | CockroachDB |
|-----------------+---------------+--------------|
| no generated id | OK | OK |
| generated id | OK | ERROR |
|------------------------------------------------|
这是重现问题的代码。
./src/main/kotlin/ThingService.kt
:
package things
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table
import javax.persistence.Column
import javax.persistence.GeneratedValue
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.data.jpa.repository.JpaRepository
import com.fasterxml.jackson.annotation.JsonIgnore
interface ThingRepository : JpaRepository<Thing, Long> {
}
@RestController
class ThingController(private val repository: ThingRepository) {
@PutMapping("/thing/")
fun save(@RequestBody t:Thing): Thing
= repository.save(t)
}
@Entity
data class Thing (
@Column(name="value")
var value: String,
@Id
@GeneratedValue
@Column(name="id")
@JsonIgnore
var id: Long = -1
)
@SpringBootApplication
class Application {
}
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
./src/main/resources/application.properties
:
server.port=8082
spring.datasource.url=jdbc:postgresql://localhost:26257/things_db?sslmode=disable
spring.datasource.username=root
spring.datasource.password=123
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.hibernate.ddl-auto=update
./build.gradle.kts
:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
val kotlinVersion = "1.2.20"
id("org.springframework.boot") version "2.0.0.RELEASE"
id("org.jetbrains.kotlin.jvm") version kotlinVersion
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
id("io.spring.dependency-management") version "1.0.4.RELEASE"
}
version = "1.0.0-SNAPSHOT"
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}
val test by tasks.getting(Test::class) {
useJUnitPlatform()
}
repositories {
mavenCentral()
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
compile("org.hibernate:hibernate-core")
compile("org.springframework.retry:spring-retry:1.2.2.RELEASE")
compile("org.postgresql:postgresql")
compile("org.json:json:20180130")
testCompile("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "junit")
}
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
以下是重现问题的步骤。
下载并初始化 CockroachDB:
# download
wget -qO- https://binaries.cockroachdb.com/cockroach-v1.1.6.linux-amd64.tgz | tar xvz
# start
./cockroach-v1.1.6.linux-amd64/cockroach start --insecure
# leave terminal open in background
# init
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "CREATE USER root WITH PASSWORD '123';"
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "CREATE DATABASE things_db;"
./cockroach-v1.1.6.linux-amd64/cockroach sql --insecure -e "GRANT ALL ON DATABASE things_db TO root;"
运行数据服务:
gradle bootRun
现在尝试将一个东西放入服务中:
curl -w "\n" -H 'Content-Type: application/json' -X PUT -d '{"value":"foo", "id":123}' http://localhost:8082/thing/
响应是:
{"timestamp":"2018-03-19T13:05:12.856+0000","status":500,"error":"Internal Server Error","message":"could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet","path":"/thing/"}
然而,当使用 PostgreSQL 代替 CockroachDB 时,结果很好
{"value":"foo","id":123}
知道导致问题的原因或使用 CockroachDB 时如何避免该问题吗?
这是完整的日志:
Spring 日志有以下条目:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "sequence"
Detail: source SQL:
create sequence hibernate_sequence start 1 increment 1
CockroachDB 1.x 不支持序列,但它们在 2.0 中,即 still in beta。 Beta 状态确实意味着它还没有准备好用于生产,但如果您只是在玩 CockroachDB,它可能没问题。
CockroachDB 2.0 中的序列遵循 postgres 语法和行为,但 cycle
(尚未实现)除外。这里使用的语句不用它,只用START 1 INCREMENT 1
.
您可以在 CockroachDB docs.
中找到有关序列的更多详细信息