如何将 Hibernate 从 MySQL 迁移到 SQL Server?

Posted

技术标签:

【中文标题】如何将 Hibernate 从 MySQL 迁移到 SQL Server?【英文标题】:How to migrate Hibernate from MySQL to SQL Server? 【发布时间】:2016-06-09 16:26:33 【问题描述】:

我需要将我的 JPA/Hibernate (5.1) Java EE 应用程序从 mysql 迁移到 SQL Server (2012)。由于 JPA 提供了抽象,我的拙见是认为这要简单明了。

我开始在 Wildfly 10 上加载 SQL Server JDBC 4.2 驱动程序,从 Microsoft 网站下载,并定义新的数据源,从而成功进行连接测试。

然后,我重新发布了我的应用程序,让 Hibernate 重建数据库表,但我被困在这个问题上:

13:27:29,268 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ServerService Thread Pool -- 61) SQL Error: 1038, SQLState: S0004
13:27:29,268 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (ServerService Thread Pool -- 61) An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.
13:27:29,270 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 61) MSC000001: Failed to start service jboss.persistenceunit."best.war#best": org.jboss.msc.service.StartException in service jboss.persistenceunit."best.war#best": javax.persistence.PersistenceException: [PersistenceUnit: best] Unable to build Hibernate SessionFactory
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:172)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:117)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:182)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: best] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:884)
    at org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:154)
    ... 7 more
Caused by: org.hibernate.exception.SQLGrammarException: Error accessing table metadata
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.convertSQLException(InformationExtractorJdbcDatabaseMetaDataImpl.java:99)
    at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.locateTableInNamespace(InformationExtractorJdbcDatabaseMetaDataImpl.java:354)
    at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.getTable(InformationExtractorJdbcDatabaseMetaDataImpl.java:228)
    at org.hibernate.tool.schema.internal.exec.ImprovedDatabaseInformationImpl.getTableInformation(ImprovedDatabaseInformationImpl.java:109)
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.performMigration(SchemaMigratorImpl.java:252)
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigration(SchemaMigratorImpl.java:137)
    at org.hibernate.tool.schema.internal.SchemaMigratorImpl.doMigration(SchemaMigratorImpl.java:110)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:176)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:64)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:458)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:881)
    ... 9 more
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:217)
    at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onEOF(tdsparser.java:251)
    at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:81)
    at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:36)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:1834)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:6276)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1793)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectionCommand(SQLServerConnection.java:1839)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.setCatalog(SQLServerConnection.java:2190)
    at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.switchCatalogs(SQLServerDatabaseMetaData.java:331)
    at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetFromStoredProc(SQLServerDatabaseMetaData.java:282)
    at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetWithProvidedColumnNames(SQLServerDatabaseMetaData.java:309)
    at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getTables(SQLServerDatabaseMetaData.java:496)
    at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.locateTableInNamespace(InformationExtractorJdbcDatabaseMetaDataImpl.java:339)
    ... 19 more

13:27:29,278 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "best.war")]) - failure description: "WFLYCTL0080: Failed services" => "jboss.persistenceunit.\"best.war#best\"" => "org.jboss.msc.service.StartException in service jboss.persistenceunit.\"best.war#best\": javax.persistence.PersistenceException: [PersistenceUnit: best] Unable to build Hibernate SessionFactory
    Caused by: javax.persistence.PersistenceException: [PersistenceUnit: best] Unable to build Hibernate SessionFactory
    Caused by: org.hibernate.exception.SQLGrammarException: Error accessing table metadata
    Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as \"\" or [] are not allowed. Change the alias to a valid name."
13:27:29,300 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 34) WFLYSRV0010: Deployed "best.war" (runtime-name : "best.war")
13:27:29,301 INFO  [org.jboss.as.controller] (Controller Boot Thread) WFLYCTL0183: Service status report
WFLYCTL0186:   Services which failed to start:      service jboss.persistenceunit."best.war#best": org.jboss.msc.service.StartException in service jboss.persistenceunit."best.war#best": javax.persistence.PersistenceException: [PersistenceUnit: best] Unable to build Hibernate SessionFactory

发生了什么事?这是我的persistence.xml

<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="best" transaction-type="JTA">
        <jta-data-source>java:/datasource/mssql/best</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
  </persistence-units>
</persistence>

我也尝试添加这个,因为我使用的是 SQL Server 2012,但没有任何改变:

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

有什么想法或建议吗?

更新

问题似乎只发生在hibernate.hbm2ddl.auto = update 上,因为create 可以工作。但我真的需要update 来像使用 MySQL 一样工作,因为我正在进行大量开发并且我的架构经常更改。

【问题讨论】:

【参考方案1】:

SQL Server 需要明确的 catalogschema 设置。

persistence.xml 中的附加说明:

<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect" />
<property name="hibernate.default_catalog" value="[database name]" />
<property name="hibernate.default_schema" value="dbo" />
<property name="hibernate.id.new_generator_mappings" value="false" />

参考:

java - Problem using Hibernate and SQL Server 2008 - Stack Overflow java - JPA GenerationType.AUTO not considering column with auto increment - Stack Overflow

【讨论】:

hibernate.default_catalog=[数据库名称] 已修复,谢谢!! 这是我的观点中的一个错误。它在 4.3 中运行良好。现在,如果在 @Table 中仅指定了模式而没有目录,Hibernate 不会向 SQL Server 发出正确的查询!我提出了一个错误hibernate.atlassian.net/browse/HHH-10978 谢谢!对于那些努力设置与 mssql 对话的 Quarkus 应用程序的人:``` quarkus.hibernate-orm.dialect=org.hibernate.dialect.SQLServer2012Dialect quarkus.hibernate-orm.database.default-catalog=DBNAME quarkus.hibernate-orm。 database.default-schema=SCHEMANAME ```【参考方案2】:

当您使用带有架构值但没有目录值且没有在 persistence.xml 中指定 hibernate.default_catalog 的 @Table 时,问题就出现了。

这是我的观点中的一个错误。它在 4.3 中运行良好。现在,如果在 @Table 中仅指定了模式而没有目录,Hibernate 不会向 SQL Server 发出正确的查询!我在这里提出了一个错误:https://hibernate.atlassian.net/browse/HHH-10978

【讨论】:

【参考方案3】:

MySQL 和 SQL Server 都有一些特定的关键字或保留名称。

检查您的实体没有使用任何作为表名或列名。

【讨论】:

他们没有,这都是 JPA 的默认设置。我没有@Tables 也没有@Columns,但我发现问题只出在update DDL,create 有效。 您是否尝试再次切换到更新?您在上面写道,您只是在出现问题后才设置方言,可能是引入了某种不可恢复的模式不匹配。【参考方案4】:

我在 SQL Server 2012 中使用休眠 5.1.0.Final 时遇到了类似的问题。我降级到休眠 4.3.11.Final 并解决了这个问题。 p>

休眠 EntityManager 5.1.0.Final

INFO  Version:37 - HHH000412: Hibernate Core 5.1.0.Final
INFO  Environment:213 - HHH000206: hibernate.properties not found
INFO  Environment:317 - HHH000021: Bytecode provider name : javassist
INFO  Version:66 - HCANN000001: Hibernate Commons Annotations 5.0.1.Final
INFO  Dialect:156 - HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect
INFO  Version:30 - HV000001: Hibernate Validator 5.2.4.Final
WARN  SqlExceptionHelper:129 - SQL Error: 1038, SQLState: S0004
ERROR SqlExceptionHelper:131 - Falta o está vacío un nombre de objeto o columna. Compruebe si todas las columnas de las instrucciones SELECT INTO tienen un nombre. Para otras instrucciones, busque si hay nombres de alias vacíos. No se permiten los alias definidos como "" o []. Cambie el alias por un nombre válido.

休眠 EntityManager 4.3.11.Final

Version:54 - HHH000412: Hibernate Core 4.3.11.Final
Environment:239 - HHH000206: hibernate.properties not found
Environment:346 - HHH000021: Bytecode provider name : javassist
Version:66 - HCANN000001: Hibernate Commons Annotations 4.0.5.Final
Dialect:145 - HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect
ASTQueryTranslatorFactory:47 - HHH000397: Using ASTQueryTranslatorFactory
Version:30 - HV000001: Hibernate Validator 5.2.4.Final
SchemaValidator:157 - HHH000229: Running schema validator
SchemaValidator:165 - HHH000102: Fetching database metadata
TableMetadata:65 - HHH000261: Table found: rino.rino.tipo_ticket

希望这会有所帮助!

【讨论】:

【参考方案5】:

我在这里的这个线程迟到了,但是当我无法让 Spring Boot JPA 与 MS SQL Server 一起使用它与 MySQL 和 Postgres 的工作方式时,我来到了这里。

此线程对使用 Hibernate 5.0.12.Final 的 Spring Boot 1.5.9.RELEASE 非常有帮助。

另请注意,许多教程都显示了 Spring Boot application.propeties 文件,其中包含数据库和休眠的条目,这些条目现在已被 Spring Boot 取代为更新的属性。

因此,如果您将 Spring Boot 与 Microsoft SQL Server 一起使用,请使用以下样式的属性

spring.datasource.url=jdbc:sqlserver://127.0.0.1:1433;jdbc.databaseName=mydb
spring.datasource.username=admin
spring.datasource.password=aadmin
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.database=sql-server
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

在您的实体中,您需要提供以下架构信息:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(schema="dbo", name="MyUser",catalog="mydatabase")
public class MyUser 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private int age;

    public MyUser() 
    

    public MyUser(String name, int age) 
        this.name = name;
        this.age = age;
    

    public Integer getId() 
        return id;
    

    public void setId(Integer id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    

    @Override
    public String toString() 
        return "User" + ", name='" + name + '\'' + ", Age=" + age + '';
    

注意:@Table 注释的catalog 属性应该是您的数据库名称。上面提到的Spring Boot和Hibernate结合使用时,连接和访问Microsoft SQL Server需要它。

【讨论】:

以上是关于如何将 Hibernate 从 MySQL 迁移到 SQL Server?的主要内容,如果未能解决你的问题,请参考以下文章

如何从表字段迁移 Hibernate @Audited 信息?

从 Migrate 迁移到 Spring MVC 4 + Hibernate5

如何使用文件将数据从 mysql 迁移到 clickhouse?

将 Spring 应用程序从 Hibernate 4.3.1.Final 迁移到 5.4.27.Final

如何将数据库从 Filemaker 迁移到 Mysql?

使用 Hibernate 将 Java 应用程序从 DB2 迁移到 BigQuery 时出现错误“找到:int64,预期:整数”