MSSQL 2014 的错误休眠方言

Posted

技术标签:

【中文标题】MSSQL 2014 的错误休眠方言【英文标题】:Wrong hibernate dialect for MSSQL 2014 【发布时间】:2016-02-04 21:44:02 【问题描述】:

我在将使用序列的实体插入 MSSQL 2014 数据库时遇到问题。我使用 Wildfly 10 CR4 附带的休眠(但在 CR1 和 CR2 中我遇到了同样的问题)。

以下是 webapp 运行环境的一般信息:

    野蝇 10 (CR4) Java 8 u 51 Windows 7 专业版 64 位 MSSQL 服务器 2014 MSSQL驱动:sqljdbc42.jar部署在应用服务器上

我的 persistence.xml 文件如下所示:

<persistence-unit name="mb_managed_pu" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>java:/jdbc/datasource</jta-data-source>
    <properties>
        <property name="hibernate.archive.autodetection" value="class, hbm" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.jdbc.batch_size" value="0" />
        <property name="hibernate.default_schema_" value="openmap"/>
        <property name="hibernate.connection.useUnicode" value="yes"/>
        <property name="hibernate.connection.characterEncoding" value="UTF-8"/>
    </properties>
</persistence-unit>

现在这是我遇到错误时会发生的情况。

首先,当 Wildfly 启动时,我可以看到这个警告:

WARN [org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver](ServerService 线程池 -- 68)HHH000385:未知的 Microsoft SQL Server 主要版本 [12] 使用 SQL Server 2000 方言

上网查了一下,发现这个问题从2015年1月就知道了,可惜还是an open issue。

当我尝试持久化具有配置为使用序列的 ID 的新实体时,会引发错误:

@Id
@Column(name = "MAP_BOOKMARK_ID")
@SequenceGenerator(name = "SEQ_MAP_BOOKMARKS", sequenceName = "SEQ_MAP_BOOKMARKS", allocationSize = 1)
@GeneratedValue(generator = "SEQ_MAP_BOOKMARKS", strategy = GenerationType.SEQUENCE)
private long                    id;

引发的异常如下:

com.microsoft.sqlserver.jdbc.SQLServerException:对象名称“SEQ_MAP_BOOKMARKS”无效。

这并不奇怪,因为 hibernate 使用了错误的方言 - 对序列一无所知的方言。

当我修改 persistence.xml 并添加这一行时:

<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect"/>

一切都像魅力一样。

问题在于该应用程序还可以与另一台服务器上的 Oracle 数据库和另一台服务器上的 Postgres 一起使用。我想避免必须准备同一个应用程序的多个版本。

有人知道这个问题的解决方案吗?还是我应该等待另一个 Wildfly 和/或休眠版本出现?

【问题讨论】:

将值 ""org.hibernate.dialect.SQLServer2012Dialect"" 提取到属性文件。将此文件放在tomcat的conf文件夹中。使用弹簧占位符来设置方言。使用此配置,您可以在两个不同的服务器上部署战争,您只需更改 tomcat 中的属性文件。 【参考方案1】:

我认为您的问题可能与这个已知问题HHH-9570 有关。 (该链接实际上包含我对我提出的解决方法的拉取请求)

基本上,就像之前在 SQL Server 2012 中发生的那样,Hibernate 的 StandardDialectResolver 无法识别 SQL Server 2014([Major version 12]),然后返回默认方言 SQLServerDialect,这是 SQL Server 2000 的方言

【讨论】:

【参考方案2】:

同时团队没有解决这个问题,你可以创建一个自定义的方言解析器:

public class ScopeStandardDialectResolver implements DialectResolver 


private static final long serialVersionUID = 1L;

    @Override
    public Dialect resolveDialect(DialectResolutionInfo info) 
        Dialect customDialectResolver = customDialectResolver(info);
        Log.getInstance().logInfo(Thread.currentThread().getStackTrace(), customDialectResolver.getClass().getName());
        return customDialectResolver;
    

    private Dialect customDialectResolver(DialectResolutionInfo info) 
        final String databaseName = info.getDatabaseName();
        final int majorVersion = info.getDatabaseMajorVersion();
        if (isSqlServer2014(databaseName, majorVersion)) 
            return new SQLServer2012Dialect(); 
         else 
            return StandardDialectResolver.INSTANCE.resolveDialect(info);
        
    

    private boolean isSqlServer2014(final String databaseName, final int majorVersion) 
        return databaseName.startsWith("Microsoft SQL Server") && majorVersion == 12;
    


然后你在你的持久化单元中配置:

<property name="hibernate.dialect_resolvers" value="com.oki.scope.hibernate.ScopeStandardDialectResolver" />

基于此示例:http://blog.exxeta.com/2016/03/23/dynamically-resolve-hibernate-database-dialect/

【讨论】:

【参考方案3】:

其实这个问题是由于表的映射不正确造成的。检查表和实体类映射。

【讨论】:

【参考方案4】:

对于 Springboot 1.4.7 及更低版本,请在属性文件中添加以下内容

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

【讨论】:

以上是关于MSSQL 2014 的错误休眠方言的主要内容,如果未能解决你的问题,请参考以下文章

即使驱动程序类名和休眠方言的值错误,Spring Hibernate 集成示例也会执行

MySQL8 的休眠方言

休眠 2 与 MSSQL 用于 ORDER BY

mysql的hsql休眠方言

JBoss EAP 7.2 Oracle 休眠方言

MSSQL over PHP 的连接错误