前言
问题描述
在springboot项目中使用springdata Jpa,并且希望当我的实体类发生了更改,数据库表结构随着实体类的改变而自动做出相应的改变。故在application.properties文件中设置属性spring.jpa.hibernate.ddl-auto=update。然而在启动的时候报错,报错信息如下:
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:259)
at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onEOF(tdsparser.java:256)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:108)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:28)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:2754)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7344)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2713)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectionCommand(SQLServerConnection.java:2759)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.setCatalog(SQLServerConnection.java:3076)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.switchCatalogs(SQLServerDatabaseMetaData.java:345)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetFromStoredProc(SQLServerDatabaseMetaData.java:297)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetWithProvidedColumnNames(SQLServerDatabaseMetaData.java:321)
at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getTables(SQLServerDatabaseMetaData.java:493)
at org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl.locateTableInNamespace(InformationExtractorJdbcDatabaseMetaDataImpl.java:339)
... 31 common frames omitted
技术栈
- springboot 1.5.6
- springdata jpa
- sqlServer2014
UserEntity实体类
@Entity
@Table(name = "user_entity", schema = "yueyue")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer uid;
@Column(name = "username", columnDefinition = "varchar(255)", nullable = false)
private String username;
@Column(name = "password", columnDefinition = "varchar(255)", nullable = false)
private String password;
}
application.yml
spring:
datasource:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://localhost;databaseName=testdb;sendStringParametersAsUnicode=false
username: sa
password: Abcd1234
jpa:
hibernate:
ddl-auto: update
dialect: org.hibernate.dialect.SQLServer2012Dialect
show-sql: true
解决思路
看抛出来的错误信息并不是很明显知道错误在哪,我们还是debug进代码里面看具体做了什么操作,挑一个比较显眼的方法打个断点。这里我选择at com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData.getResultSetFromStoredProc(SQLServerDatabaseMetaData.java:297)
这个方法,这个方法的意思是通过调用存储过程得到结果集,错误信息显示的是在297行,再进入switchCatalogs方法。这段代码的逻辑很清晰,拿到当前数据库的catalog(默认是数据库名),然后和传进来的catalog做对比,如果相同返回null,如果不同就将数据库的catalog设置成传进来的值,最后返回该值。
在switchCatalogs方法中的第一行打上断点,重新debug启动springboot的引导类,进入到断点里面,可以看到相应的变量值,我们传进来的catelog为空字符串,所以执行
connection.setCatalog("")
这句代码,而数据库的catalog是不允许为空的,所以抛出SQLServerException,就看到文章开头的错误信息。
解决方案
当一切逻辑都很清晰时,自然bug改起来也是省时省力。只需要在相应的实体类@Table注解上加上catalog属性就行了,这里我改成数据库名。最后重启app。
修改后的UserEntity
@Entity
@Table(name = "user_entity", schema = "yueyue", catalog = "testdb")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer uid;
@Column(name = "username", columnDefinition = "varchar(255)", nullable = false)
private String username;
@Column(name = "password", columnDefinition = "varchar(255)", nullable = false)
private String password;
}
总结
最后一个小小的总结作为本文的结束,使用springdata jpa时,如果希望实体类发生更改而数据库表做出相应的更改且不破坏数据库现有的数据,要将spring.jpa.hibernate.ddl-auto属性值设置为update,同时需要在实体类上的@Table注解中加上catalog属性,值为数据库名。
这里其实还是有一些小小的不足,就算你设置成update值,它也并不能识别你对数据库表结构的所有更改,它往往只能识别出你增加的字段,比如修改字段名,修改字段类型或者删除一个字段它都是不能够识别的。
总的来说,只是使用这个属性值来对数据库做版本控制是有很大的局限性的。在实际开发中,我们更多会用到flyway这个工具,这里就不再做多阐述。
thanks for reading,see u next time~~~
wangyue