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

时间:2016-02-26 12:39:45

标签: java sql-server hibernate jpa wildfly

我需要将我的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一样工作,因为我正在进行大量开发,而且我的架构经常变化。

5 个答案:

答案 0 :(得分:6)

SQL Server需要明确的目录架构设置。

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" />

参考文献:

答案 1 :(得分:1)

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

这是我的pov中的一个错误。它在4.3中工作得非常好。现在,如果在@Table中只指定了架构且没有目录,Hibernate不会向SQL Server发出正确的查询!我在这里提出了一个错误:https://hibernate.atlassian.net/browse/HHH-10978

答案 2 :(得分:0)

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

检查您的实体是否使用any作为表名或列名。

答案 3 :(得分:0)

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

Hibernate 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.

Hibernate 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

希望这有帮助!

答案 4 :(得分:0)

我迟到了这个帖子,但是当我无法让Spring Boot JPA与MS SQL Server一起工作时,它与MySQL和Postgres一起工作。

这个帖子对Spring Boot 1.5.9.RELEASE 非常有用,后者使用Hibernate 5.0.12.Final

另请注意,许多教程都显示了Spring Boot application.propeties文件,其中包含数据库和hibernate的条目,这些条目现在已被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 + '}';
    }
}

注意:catalog注释的@Table属性应该是您的数据库名称。当使用如上所述的Spring Boot和Hibernate的组合时,它是连接和访问Microsoft SQL Server所必需的。