gpt4 book ai didi

postgresql - Spring Boot+Kotlin+Postgres 和 JSON : "org.hibernate.MappingException: No Dialect mapping for JDBC type"

转载 作者:行者123 更新时间:2023-12-02 12:15:10 26 4
gpt4 key购买 nike

我一直在咨询许多方法/帖子/stackoverflow 问题,以便在运行 Kotlin/SpringBoot 应用程序时处理以下错误(完整堆栈跟踪):

2020-04-22 18:33:56.823 ERROR 46345 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 2118910070
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1803)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at app.ApplicationKt.main(Application.kt:13)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 2118910070
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:378)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1799)
... 21 common frames omitted
Caused by: org.hibernate.MappingException: No Dialect mapping for JDBC type: 2118910070
at org.hibernate.dialect.TypeNames.get(TypeNames.java:71)
at org.hibernate.dialect.TypeNames.get(TypeNames.java:103)
at org.hibernate.dialect.Dialect.getTypeName(Dialect.java:369)
at org.hibernate.mapping.Column.getSqlType(Column.java:238)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateColumnType(AbstractSchemaValidator.java:156)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:143)
at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)
at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:192)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:320)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1249)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
... 25 common frames omitted
问题在于用 Hibernate 映射 PostgreSQL 的 JSONB 数据类型。
我广泛尝试和调试的两种方法如下:
  • 实现自定义 Hibernate 映射并为 JSONB 创建自定义 UserType。引用文献:here , here , herehere
  • 使用休眠类型。引用文献是here , herehere

  • 我在这两个方面都进行了大量尝试,但没有任何运气,我很想了解我哪里出错了以及我遗漏了什么。
    方法一
    我的实体:
    @Entity
    @TypeDef(name = "JsonUserType", typeClass = JsonUserType::class)
    @Table(name = "entity")
    data class MyEntity(
    @Column(nullable = false)
    val id: UUID,
    @Column(nullable = false)
    @Enumerated(value = EnumType.STRING)
    @Column(nullable = false)
    val type: Type,
    @Type(type = "JsonUserType")
    @Column(columnDefinition = "jsonb")
    @Basic(fetch = FetchType.LAZY)
    var event_data: Event
    ) : SomeEntity<UUID>(), SomeOtherStuff {
    override fun getName(): String {
    return id
    }
    }


    enum class Type(val value: String) {
    TYPE1("Type1"),
    TYPE2("Type2")
    }
    我的POJO:
    data class Event(
    val someContent: String,
    val someBoolean: Boolean
    ) : Serializable { //equals, hashcode etc are omitted }
    我的自定义休眠方言:
    class CustomPostgreSQLDialect : PostgreSQL95Dialect {
    constructor() : super() {
    this.registerColumnType(Types.JAVA_OBJECT, "jsonb")
    }
    }
    我的自定义类型(抽象类)
    abstract class JsonDataUserType : UserType {

    override fun sqlTypes(): IntArray? {
    return intArrayOf(Types.JAVA_OBJECT)
    }

    override fun equals(value1: Any?, value2: Any?): Boolean {
    return value1 == value2
    }

    override fun hashCode(value1: Any?): Int {
    return value1!!.hashCode()
    }

    override fun assemble(value1: Serializable?, value2: Any?): Any {
    return deepCopy(value1)
    }

    override fun disassemble(value1: Any?): Serializable {
    return deepCopy(value1) as Serializable
    }

    override fun deepCopy(p0: Any?): Any {
    return try {
    val bos = ByteArrayOutputStream()
    val oos = ObjectOutputStream(bos)
    oos.writeObject(p0)
    oos.flush()
    oos.close()
    bos.close()
    val bais = ByteArrayInputStream(bos.toByteArray())
    ObjectInputStream(bais).readObject()
    } catch (ex: ClassNotFoundException) {
    throw HibernateException(ex)
    } catch (ex: IOException) {
    throw HibernateException(ex)
    }
    }

    override fun replace(p0: Any?, p1: Any?, p2: Any?): Any {
    return deepCopy(p0)
    }

    override fun nullSafeSet(p0: PreparedStatement?, p1: Any?, p2: Int, p3: SharedSessionContractImplementor?) {
    if (p1 == null) {
    p0?.setNull(p2, Types.OTHER)
    return
    }
    try {
    val mapper = ObjectMapper()
    val w = StringWriter()
    mapper.writeValue(w, p1)
    w.flush()
    p0?.setObject(p2, w.toString(), Types.OTHER)
    } catch (ex: java.lang.Exception) {
    throw RuntimeException("Failed to convert Jsonb to String: " + ex.message, ex)
    }
    }
    override fun nullSafeGet(p0: ResultSet?, p1: Array<out String>?, p2: SharedSessionContractImplementor?, p3: Any?): Any {
    val cellContent = p0?.getString(p1?.get(0))
    return try {
    val mapper = ObjectMapper()
    mapper.readValue(cellContent?.toByteArray(charset("UTF-8")), returnedClass())
    } catch (ex: Exception) {
    throw RuntimeException("Failed to convert String to Jsonb: " + ex.message, ex)
    }
    }

    override fun isMutable(): Boolean {
    return true
    }

    }
    此类类(class)取自此 Stackoverflow question
    我的具体类(class):
    class JsonType : JsonDataUserType() {
    override fun returnedClass(): Class<Event> {
    return Event::class.java
    }
    }
    我的 application.yml jpa 休眠属性
    jpa.properties.database.database-platform: org.hibernate.dialect.PostgreSQL95Dialect
    jpa.properties.hibernate.dialect: org.myapp.util.CustomPostgreSQLDialect
    方法二
    Hibernate 属性与 PoJo 类完全相同,不包含自定义映射器。
    实体
    @Entity
    @TypeDef(
    name = "jsonb",
    typeClass = JsonBinaryType::class
    )
    @Table(name = "entity")
    data class MyEntity(
    @Column(nullable = false)
    val id: UUID,
    @Column(nullable = false)
    @Enumerated(value = EnumType.STRING)
    @Column(nullable = false)
    val type: Type,
    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    @Basic(fetch = FetchType.LAZY)
    var event_data: Event
    ) : SomeEntity<UUID>(), SomeOtherStuff {
    override fun getName(): String {
    return id
    }
    }


    enum class Type(val value: String) {
    TYPE1("Type1"),
    TYPE2("Type2")
    }
    自定义方言(使用休眠类型):
    class CustomPostgreSQLDialect : PostgreSQL95Dialect {
    constructor() : super() {
    this.registerHibernateType(Types.OTHER, JsonNodeBinaryType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonStringType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonBinaryType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonNodeBinaryType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonNodeStringType::class.java.name)
    }
    }
    请注意,我也尝试过只使用:
    this.registerHibernateType(Types.OTHER, "jsonb")
    以及在我的实体或它扩展的基础实体中拥有所有这些(就此而言没有变化):
    @TypeDefs({
    @TypeDef(name = "string-array", typeClass = StringArrayType.class),
    @TypeDef(name = "int-array", typeClass = IntArrayType.class),
    @TypeDef(name = "json", typeClass = JsonStringType.class),
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
    @TypeDef(name = "jsonb-node", typeClass = JsonNodeBinaryType.class),
    @TypeDef(name = "json-node", typeClass = JsonNodeStringType.class),
    })
    我在这两种方法中都做错了什么吗?我无法让它工作,并且不确定是否有任何相关性,JDBC type: No Dialect mapping 之后的数值总是不同的。我添加这个是因为我看到一些 id 与某些类别的错误相关。
    你能帮我吗?
    谢谢
    编辑:
    我想提供更多关于 jpa、postgres 和 hibernate 版本的信息。我目前正在处理以下问题:
  • postgres:10- Alpine
  • PostgreSQL JDBC 驱动程序 JDBC 4.2 » 42.2.8
  • org.springframework.boot:spring-boot-starter-data-jpa:2.2.1.RELEASE
  • org.hibernate:hibernate-core:5.4.8.Final
    其中是否存在任何特定的版本问题?

  • 编辑 2
    我一直在尝试成功使用休眠类型(方法 2 如上所述)。我根据 Postgres 版本 (10) 进行了以下更改:
    class CustomPostgreSQLDialect : PostgreSQL10Dialect {
    constructor() : super() {
    this.registerHibernateType(Types.OTHER, StringArrayType::class.java.name)
    this.registerHibernateType(Types.OTHER, IntArrayType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonStringType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonBinaryType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonNodeBinaryType::class.java.name)
    this.registerHibernateType(Types.OTHER, JsonNodeStringType::class.java.name)
    }
    }
    然后在我的实体中我有
    @TypeDefs({
    @TypeDef(name = "string-array", typeClass = StringArrayType.class),
    @TypeDef(name = "int-array", typeClass = IntArrayType.class),
    @TypeDef(name = "json", typeClass = JsonStringType.class),
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
    })
     @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    @Basic(fetch = FetchType.LAZY)
    var event_data: Event
    然后我调试了 TypeNames 中的 get 方法,错误来自:
    public String get(final int typeCode) throws MappingException {
    final Integer integer = Integer.valueOf( typeCode );
    final String result = defaults.get( integer );
    if ( result == null ) {
    throw new MappingException( "No Dialect mapping for JDBC type: " + typeCode );
    }
    return result;
    }
    这就是我得到的:
    defaults = {HashMap@12093}  size = 27
    {Integer@12124} -1 -> "text"
    {Integer@12126} 1 -> "char(1)"
    {Integer@12128} -2 -> "bytea"
    {Integer@12130} 2 -> "numeric($p, $s)"
    {Integer@12132} -3 -> "bytea"
    {Integer@12133} -4 -> "bytea"
    {Integer@12134} 4 -> "int4"
    {Integer@12136} -5 -> "int8"
    {Integer@12138} -6 -> "int2"
    {Integer@12140} 5 -> "int2"
    {Integer@12141} -7 -> "bool"
    {Integer@12143} 6 -> "float4"
    {Integer@12145} 7 -> "real"
    {Integer@12147} 8 -> "float8"
    {Integer@12149} -9 -> "nvarchar($l)"
    {Integer@12151} 12 -> "varchar($l)"
    {Integer@12153} -15 -> "nchar($l)"
    {Integer@12155} -16 -> "nvarchar($l)"
    {Integer@12156} 16 -> "boolean"
    {Integer@12158} 2000 -> "json"
    {Integer@12160} 2004 -> "oid"
    {Integer@12162} 2005 -> "text"
    {Integer@12163} 1111 -> "uuid"
    {Integer@12165} 91 -> "date"
    {Integer@12167} 2011 -> "nclob"
    {Integer@12169} 92 -> "time"
    {Integer@12171} 93 -> "timestamp"
    找不到 jsonb,当我调试自定义方言时,我得到以下信息:
    {Integer@10846} 1111 -> "com.vladmihalcea.hibernate.type.json.JsonStringType"
    key = {Integer@10846} 1111
    value = "com.vladmihalcea.hibernate.type.json.JsonStringType"
    这是为什么?为什么我没有得到 jsonb 类型?

    最佳答案

    我在 pull-request 中提出了我的解决方案

    这个想法是将实体更改为:

    import com.example.demo.pojo.SamplePojo
    import com.vladmihalcea.hibernate.type.json.JsonBinaryType
    import com.vladmihalcea.hibernate.type.json.JsonStringType
    import org.hibernate.annotations.Type
    import org.hibernate.annotations.TypeDef
    import org.hibernate.annotations.TypeDefs
    import javax.persistence.*

    @Entity
    @Table(name = "tests")
    @TypeDefs(
    TypeDef(name = "json", typeClass = JsonStringType::class),
    TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
    )
    data class SampleEntity (
    @Id @GeneratedValue
    val id: Long?,
    val name: String?,

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    var data: Map<String, Any>?
    ) {

    /**
    * Dependently on use-case this can be done differently:
    * https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
    */
    constructor(): this(null, null, null)
    }
  • 每个实体都应该有一个默认构造函数或为其所有参数设置默认值
  • 不是保存 POJO,而是另存为 Map<String, Any>类型

  • 由于我们可以完全控制业务逻辑中 POJO 中的内容,因此唯一缺少的部分是将 POJO 转换为 Map 和 Map 转换为 POJO

    SamplePojo 实现
    data class SamplePojo(
    val payload: String,
    val flag: Boolean
    ) {
    constructor(map: Map<String, Any>) : this(map["payload"] as String, map["flag"] as Boolean)

    fun toMap() : Map<String, Any> {
    return mapOf("payload" to payload, "flag" to flag)
    }
    }

    这是一种解决方法,但它允许我们使用任何深度级别的结构。

    附言我注意到你使用 Serializer并重新定义 equals, toString, hashCode .如果使用 data class ,则不需要这个.

    更新:

    如果您需要比 Map<String, Any> 更灵活的结构,您可以使用 JsonNode . Code example

    实体:
    import com.fasterxml.jackson.databind.JsonNode
    import com.vladmihalcea.hibernate.type.json.JsonBinaryType
    import com.vladmihalcea.hibernate.type.json.JsonStringType
    import org.hibernate.annotations.Type
    import org.hibernate.annotations.TypeDef
    import org.hibernate.annotations.TypeDefs
    import javax.persistence.*

    @Entity
    @Table(name = "tests")
    @TypeDefs(
    TypeDef(name = "json", typeClass = JsonStringType::class),
    TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
    )
    data class SampleJsonNodeEntity (
    @Id @GeneratedValue
    val id: Long?,
    val name: String?,

    @Type(type = "jsonb")
    @Column(columnDefinition = "jsonb")
    var data: JsonNode?
    ) {

    /**
    * Dependently on use-case this can be done differently:
    * https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
    */
    constructor(): this(null, null, null)
    }

    更改存储库中的实体:
    import com.example.demo.entity.SampleJsonNodeEntity
    import org.springframework.data.jpa.repository.JpaRepository

    interface SampleJsonNodeRepository: JpaRepository<SampleJsonNodeEntity, Long> {
    }

    两种方法的测试:
    import com.example.demo.DbTestInitializer
    import com.example.demo.entity.SampleJsonNodeEntity
    import com.example.demo.entity.SampleMapEntity
    import com.example.demo.pojo.SamplePojo
    import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
    import junit.framework.Assert.assertEquals
    import junit.framework.Assert.assertNotNull
    import org.junit.Before
    import org.junit.Test
    import org.junit.runner.RunWith
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
    import org.springframework.boot.test.context.SpringBootTest
    import org.springframework.test.context.ContextConfiguration
    import org.springframework.test.context.junit4.SpringRunner


    @RunWith(SpringRunner::class)
    @SpringBootTest
    @ContextConfiguration(initializers = [DbTestInitializer::class])
    @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
    class SampleRepositoryTest {

    @Autowired
    lateinit var sampleMapRepository: SampleMapRepository

    @Autowired
    lateinit var sampleJsonNodeRepository: SampleJsonNodeRepository

    lateinit var dto: SamplePojo
    lateinit var mapEntity: SampleMapEntity
    lateinit var jsonNodeEntity: SampleJsonNodeEntity

    @Before
    fun setUp() {
    dto = SamplePojo("Test", true)
    mapEntity = SampleMapEntity(null,
    "POJO1",
    dto.toMap()
    )

    jsonNodeEntity = SampleJsonNodeEntity(null,
    "POJO2",
    jacksonObjectMapper().valueToTree(dto)
    )
    }

    @Test
    fun createMapPojo() {
    val id = sampleMapRepository.save(mapEntity).id!!
    assertNotNull(sampleMapRepository.getOne(id))
    assertEquals(sampleMapRepository.getOne(id).data?.let { SamplePojo(it) }, dto)
    }

    @Test
    fun createJsonNodePojo() {
    val id = sampleJsonNodeRepository.save(jsonNodeEntity).id!!
    assertNotNull(sampleJsonNodeRepository.getOne(id))
    assertEquals(jacksonObjectMapper().treeToValue(sampleJsonNodeRepository.getOne(id).data, SamplePojo::class.java), dto)
    }

    }

    关于postgresql - Spring Boot+Kotlin+Postgres 和 JSON : "org.hibernate.MappingException: No Dialect mapping for JDBC type",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61371808/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com