JDBC 类型没有方言映射:1111

No Dialect mapping for JDBC type: 1111

我正在开发 Spring JPA 应用程序,使用 MySQL 作为数据库。我确保加载了所有 spring-jpa 库、hibernate 和 mysql-connector-java。

我是 运行 一个 mysql 5 实例。这是我的 application.properties 文件的摘录:

spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

spring.datasource.url=jdbc:mysql://localhost/mydatabase
spring.datasource.username=myuser
spring.datasource.password=SUPERSECRET
spring.datasource.driverClassName=com.mysql.jdbc.Driver

执行集成测试时,spring 正常启动但无法创建休眠 SessionFactory,例外情况是:

org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111

我认为我的方言应该是 Mysql5Dialect,我也尝试了明确说明 InnoDB 的方言,以及两个不指示版本 5 的方言选项。但我总是得到相同的 'No Dialect mapping for JDBC type: 1111' 消息. 我的 application.properties 文件位于 test/resources 源文件夹中。它被 JUnit 测试运行器识别(我之前因为其中的拼写错误而出现异常)。

是我设置的属性有误吗?我找不到关于这些 属性 名称的一些官方文档,但在这个 Whosebug 答案中找到了提示:

期待您的回答,谢谢!

顺便说一句,该应用程序已经在使用 spring 引导。

这里是基于 SubOptimal 的评论的答案:

错误信息实际上是说一个列类型不能被hibernate映射到一个数据库类型。 在我的例子中,它是我在我的一些实体中用作主键的 java.util.UUID 类型。只需应用注释 @Type(type="uuid-char")(对于 postgres @Type(type="pg-uuid")

还有另一个常见的用例抛出此异常。调用 returns void 的函数。有关更多信息和解决方案,请转到 here.

有时当您调用 sql procedure/function 时,可能需要 return 一些东西。您可以尝试 returning void: RETURN; 或 string(这个对我有用):RETURN 'OK'

请检查某些列 return 中是否有许多 未知类型 在查询中。

例如:'1' as column_name 可以有未知类型

1因为column_name是整数是正确的一.

这东西对我有用。

对于使用旧休眠 (3.x) 版本遇到此错误的任何人:

不要用大写字母写return类型。 hibernate 类型实现映射使用小写 return 类型并且不转换它们:

CREATE OR REPLACE FUNCTION do_something(param varchar)
    RETURNS integer AS
$BODY$
...

在我的例子中,问题是我在我的用户 class 中设置存储过程时忘记添加 resultClasses 属性。

@NamedStoredProcedureQuery(name = "find_email",
                procedureName = "find_email", resultClasses = User.class, //<--I forgot that. 
                parameters = {
                    @StoredProcedureParameter(mode = ParameterMode.IN, name = "param_email", type = String.class)
                }),

我遇到了同样的错误,因为我的查询返回了一个 UUID 列。为了解决这个问题,我通过 "cast(columnName as varchar)" 之类的查询将 UUID 列作为 varchar 类型返回,然后它起作用了。

示例:

public interface StudRepository extends JpaRepository<Mark, UUID> {

    @Modifying
    @Query(value = "SELECT Cast(stuid as varchar) id, SUM(marks) as marks FROM studs where group by stuid", nativeQuery = true)
    List<Student> findMarkGroupByStuid();

    public static interface Student(){
        private String getId();
        private String getMarks();
    }
}

当您使用 Hibernate 和 returning void 函数时也会发生这种情况。至少有 postgres。它不知道如何处理 void。我最终不得不将 void 更改为 return int.

如果您使用的是 Postgres,请检查您是否没有 Abstime 类型的列。 Abstime 是 JPA 无法识别的内部 Postgres 数据类型。在这种情况下,如果您的业务要求允许,使用 TO_CHAR 转换为文本可能 有所帮助。

如果您有原生 SQL 查询,则通过向查询添加转换来修复它。

例子:

CAST('yourString' AS varchar(50)) as anyColumnName

就我而言,它对我有用。

这是 Hibernate (5.x) 版本

正在调用数据库函数 return JSON string/object

为此使用 unwrap(org.hibernate.query.NativeQuery.class).addScalar() 相同的方法。

示例如下(Spring & 休眠):

@PersistenceContext

EntityManager em;

@Override

    public String getJson(String strLayerName) {

        String *nativeQuery* = "select fn_layer_attributes(:layername)";

        return em.createNativeQuery(*nativeQuery*).setParameter("layername", strLayerName).**unwrap(org.hibernate.query.NativeQuery.class).addScalar**("fn_layer_attributes", **new JsonNodeBinaryType()**) .getSingleResult().toString();

    }

查找触发问题的列

首先,您没有提供实体映射,因此我们无法判断是哪个列产生了这个问题。例如,它可以是 UUIDJSON 列。

现在,您使用的是非常古老的 Hibernate 方言。 MySQL5Dialect 适用于 MySQL 5。很可能您使用的是较新的 MySQL 版本。

因此,尝试使用 MySQL8Dialect 代替:

spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

添加非标准类型

如果您因为使用 JSON 列类型而遇到问题,请尝试提供支持非标准类型的自定义 Hibernate 方言:

public class MySQL8JsonDialect
        extends MySQL8Dialect{
 
    public MySQL8JsonDialect() {
        super();
        this.registerHibernateType(
            Types.OTHER, JsonStringType.class.getName()
        );
    }
}

答案使用自定义 Hibernate 方言:

<property
    name="hibernate.dialect"
    value="com.vladmihalcea.book.hpjp.hibernate.type.json.MySQL8JsonDialect"
/>

如果在执行 SQL 本地查询时出现此异常,则需要通过 addScalar:

传递类型
JsonNode properties = (JsonNode) entityManager
.createNativeQuery(
    "SELECT properties " +
    "FROM book " +
    "WHERE isbn = :isbn")
.setParameter("isbn", "978-9730228236")
.unwrap(org.hibernate.query.NativeQuery.class)
.addScalar("properties", JsonStringType.INSTANCE)
.getSingleResult();
 
assertEquals(
    "High-Performance Java Persistence",
    properties.get("title").asText()
);

我得到了同样的错误,这里的问题是存储在数据库中的 UUID 没有转换为对象。

我尝试应用这些注释@Type(type="uuid-char")(对于 postgres @Type(type="pg-uuid")但它对我不起作用。

这对我有用。假设您想要来自 table 的 id 和 name 以及 JPA 中的本机查询。使用字段 id 和 name 创建一个实体 class,例如 'User',然后尝试将 object[] 转换为我们想要的实体。这里匹配的数据是我们从查询中获得的对象数组列表。

@Query( value = "SELECT CAST(id as varchar) id, name from users ", nativeQuery = true)

public List<Object[]> search();

public class User{
   private UUID id;
   private String name;
}


List<User> userList=new ArrayList<>();

for(Object[] data:matchedData){
        userList.add(new User(UUID.fromString(String.valueOf(data[0])),
                String.valueOf(data[1])));

    }

假设这是我们拥有的实体

函数或过程 returning void 导致 JPA/Hibernate 出现问题,因此将其更改为 return integer 并在过程结束时调用 return 1 可能会解决问题。

SQL类型1111表示String。

另一个简单的解释可能是您正在获取复杂类型 (Entity/POJO) 但未指定要映射到的实体:

String sql = "select yourentity.* from {h-schema}Yourentity yourentity";
return entityManager.createNativeQuery(sql).getResultList();

只需在 createNativeQuery 方法中添加 class 映射到:

return entityManager.createNativeQuery(sql, Yourentity.class).getResultList();

在我的例子中,问题是 Hibernate 不知道如何处理 UUID 列。如果您使用的是 Postgres,请尝试将此添加到您的 resources/application.properties:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect

如果使用 Postgres

public class CustomPostgreSqlDialect extends PostgreSQL94Dialect{

    @Override
    public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor)
    {
        switch (sqlTypeDescriptor.getSqlType())
        {
        case Types.CLOB:
            return VarcharTypeDescriptor.INSTANCE;
        case Types.BLOB:
            return VarcharTypeDescriptor.INSTANCE;
        case 1111://1111 should be json of pgsql
            return VarcharTypeDescriptor.INSTANCE;
        }
        return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
    }
    public CustomPostgreSqlDialect() {
        super();
        registerHibernateType(1111, "string");
    }}

并使用

<prop key="hibernate.dialect">com.abc.CustomPostgreSqlDialect</prop>

如果您正在调用 EntityManager.createNativeQuery(),请务必在第二个参数中包含结果 java class:

return em.createNativeQuery(sql, MyRecord.class).getResultList()

在尝试了许多建议的解决方案之后,包括:

终于是这个用最少的更改修复了所有问题:

https://gist.github.com/agrawald/adad25d28bf6c56a7e4618fe95ee5a39

诀窍是不要在 class 上有 @TypeDef,而是在 2 个不同的 package-info.java 文件中有 2 个不同的 @TypeDef。一个在生产代码包中用于生产数据库,一个在测试包中用于测试 H2 数据库。