Spring Boot连接SqlServer数据库
1.修改pom.xml,添加sql server支持
1 | <dependency> |
我在windows+JDK8上开发上开发时,使用的是sqljdbc4的依赖,但是我换到Deepin上,使用了免安装版的OpenJDK13,使用idea打开原先的工程,始终解决不了sqljdbc4的依赖
于是换成了mssql-jdb依赖,结果还真是可以了。
2.修改application.yml配置文件
1 | spring: |
也可以在url中指定用户名密码:
1 | jdbc:sqlserver://localhost;user=MyUserName;password=*****; |
3.编写实体类
4.编写接口,继承自JpaRepository
问题
(1) 对象名 ‘sys.sequences’ 无效
解决方法是在application.yml配置文件中配置数据库版本:database-platform: org.hibernate.dialect.SQLServer2008Dialect
1.com.microsoft.sqlserver.jdbc.SQLServerException: 对象名 ‘bbs_category’ 无效
2.JPA在sqlserver2008下缺少sys.sequences的解决办法
(2) 缺少对象或列名,或者对象或列名为空。
对于 SELECT INTO 语句,请确保每列均具有名称。对于其他语句,请查找空的别名。不允许使用定义为 “” 或 [] 的别名。请将别名更改为有效名称。
1.缺少对象或列名,或者对象或列名为空。对于 SELECT INTO 语句,请确保每列均具有名称。对于其他语句,请查找空的别名。不允许使用定义为 “” 或 [] 的别名。请添加名称或单个空格作为别名。 System.Data.SqlClient.SqlException: 缺少对象或列名,或者对象或列名为空。对于 SELECT INTO 语句,请确保每列均具有名称。对于其他语句,请查找空的别名。不允
2.jpa 列名无效
3.Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.SQLGrammarException: Error accessing column metadata
4.Hibernate在控制台打印sql语句以及参数
今天回来再次解决这个问题。这里有一些网站,都是说要指定模式的名字。
1 | <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect" /> |
我尝试着使用jpa.show-sql: true,将打印出的select语句,复制到navicate中,去掉where子句(因为生成的where子句是:where vclient0_.SiteNo=?),是可以执行的。出现了占位符的问题,我查了一下,发现sql server好像不支持占位符。
1.java - 如何将Hibernate从MySQL迁移到SQL Server?
2.How to migrate Hibernate from MySQL to SQL Server?
3.SQL Server中能否使用“?”占位符
jpa中添加了use-new-id-generator-mappings: false也不起作用,将naming:physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl,这样就将生成的name_ki类似列名,就改成了Entity中的字符中的大小写固定下来了。
还是没解决啊。我尝试着在网上搜相关的内容,愣是没有人遇到过,真是的。询问群里的人,也没人愿意搭理我。我花了很长时间在这上面了,确实解决不了。项目又推进的急,真是崩溃啊。虽然可以使用Mybatis代替Hibernate,但是我总是不甘心就这样把这个问题留在这里。
根据参考资料,我再次将ddl-auto: update 改为了ddl-auto: validate,结果出现: wrong column type encountered in column [SiteNo] in table [ztzn.dbo.V_client]; found [smallint (Types#SMALLINT)], but expecting [int (Types#INTEGER)]
数据类型不一致,难道是这个原因吗?我继续探索,将数据类型修改一下。
改成什么呢?改成String不行,int也不行,Integer也不行。
经历了将number对应到BigDecimal;将smalint对应到java的byte;然后将datetime对应java.sql.Timestamp;将char对应于string,并在那一列添加@Column(columnDefinition = “Char(5)”)注解;将tinyint改为byte,等一系列改造。
卧槽,还是报错:缺少对象或列名,或者对象或列名为空。对于 SELECT INTO 语句,请确保每列均具有名称。对于其他语句,请查找空的别名。不允许使用定义为 “” 或 [] 的别名。请将别名更改为有效名称。
最后放弃吧,改成mybatis算了。
惊喜啊,通过同事的帮助,我终于解决了这个问题,问题是出在我的application.yml配置中。
错误的配置:
1 | server: |
正确的配置:
1 | server: |
注意挥掉的内容
还有一个地方就是你要把@Id下面的@GeneratedValue注解去掉,否则会报:对象名 ‘hibernate_sequence’ 无效 的错误。
总结起来,主要就是自己的配置文件搞得事情,那个配置文件:temp.use_jdbc_metadata_defaults 属性是针对于Postgres的,但是不能在SqlServer中,所以不明白每一个文件配置内容,确实还是头疼啊。总之,还是要多多的学习吧,不能瞎几把抄网上的答案。我记得这个属性是PostgresSql数据库必须配置的,否则会出现:java.sql.SQLFeatureNotSupportedException: 这个 org.postgresql.jdbc.PgConnection.createClob() 方法尚未被实作,详情请收看 Spring-Boot连接PostgresSql数据库
1.System property stops taking effect when moved to application.properties
2.Hibernate 进阶
3.hibernate.cfg.xml 常用配置
4.Java数据类型和MySql数据类型对应表
5.SQLServer与Java数据类型对应表
(3) The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: “The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]
【解决方法】
主要是jdk版本和mssql-jdbc版本不匹配,我安装了JDK17,使用的是:8.1.0.jre8-preview
1 | <!--1.8版本--> |
以前遇到了这个问题,我修改了mssql-jdbc的版本,就可以了,但是后来,又出现了这个问题,在docker中运行,死活不行,我尝试了 mssql-jdbc 版本 9.5.0.jre11-preview。 根据尝试,我认为第一个出现这个问题的原因,就是sql server服务器启用了TSL1.0,但是openjdk默认禁用了TLS1.0,所以就会出现,客户端不支持服务器的TLS1.0,JDK作为客户端,SQL Server服务器作为服务端。
1.The server selected protocol version TLS10 is not
2.The server selected protocol version TLS10 is not accepted by client preferences [TLS12] In order to resolve this, your database administrator should enable TLS 1.2 on your database server host. See more information on TLS 1.2 support for SQL Server and MySQL.
3.如何在站点服务器和远程站点系统上启用 TLS 1.2
根据分析,这个问题相应的就有两种方法解决:
- 1.服务器开启TLS 1.2
关于sql server 服务器开启tls1.2,这个我就先不探索了,本着解决问题的思路进行,我因为不能很方便的接触到 sql server 服务器,所以就暂时先不用这个方法解决了。
1.通过将 SQL Server 限制到 TLS 1.2 启用安全连接 这是在sql server 层面的配置
- 2.JDK开启TLS 1.0
我用的是 docker 部署的程序,镜像是 adoptopenjdk/openjdk11-openj9:alpine-slim,1
2
3
4
5
6
7
8
9
10## 进入docker容器
docker exec -it id /bin/sh
## 定位 security 配置文件
/opt/java/openjdk/conf/security/java.security
## 将下面的内容 使用 井号注释掉
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
include jdk.disabled.namedCurves
## 或者删除其中的TLSV1和TLSv1.1
经过测试,确实实现了启动TLS1.0的功能,但是还有一个问题,因为是使用的docker部署,不能每一次都直接进入到docker容器中吧,如何能使用dockerfile进行修改呢?
1.Java 1.8.0 enable TLS1.2 in JDBC connection Starting with JDBC driver version 6.3.2 we can add ;sslProtocol=TLSv1.2 to our connection URLs to specify the TLS version to use.
2.The server selected protocol version TLS10 is not accepted by client preferences TLS12 因为新版的 JDK 不推荐使用旧的 TLSV1.0 的协议,所以默认删除 TLS10 的支持
3.关于OpenJDK禁用TLS 1.0与1.1的分析 这里指出了OpenJDK禁用TLS1.0和1.1的问题,也指出了使用java代码输出支持的TLS版本
4.使用docker注意加驱动程序mssql可能会连接错误,需要到容器中修改java.security屏蔽3DES_EDE_CBC #50 使用docker注意加驱动程序mssql可能会连接错误,需要到容器中修改java.security屏蔽3DES_EDE_CBC
5.重新启用 TLSv1 和 TLSv1.1 1.在 JDK 的安装目录中,导航到文件夹 ./conf/security/;2.打开文件 java.security;3.搜索配置属性 jdk.tls.disabledAlgorithms;4.删除元素 TLSv1 和/或 TLSv1.1;5.重新启动 Java 应用程序;
接着上文继续解决问题,dockerfile文件修改容器中的文件,可以使用copy命令,将宿主机上的文件拷贝到容器上。先将容器中修改后的文件,拷贝到本地来
1 | ## 复制security文件 |
然后编写dockerfile文件,使用copy命令进行覆盖
1 | ## 复制security文件 |
1.关于Docker:在Dockerfile中更改Java” SecureRandom”
2.使用 Dockerfile 更换已有镜像的文件(换包) 1.找到需要修改的镜像 name 和 tag;2.备份原始镜像;3.编写 DockerFile;4.构建新的镜像;5.push 镜像到仓库;6.回退。
3.docker中宿主机与容器(container)互相拷贝传递文件的方法 docker cp mycontainer:/opt/testnew/file.txt /opt/test/;docker cp /opt/test/file.txt mycontainer:/opt/testnew/。 不管容器有没有启动,拷贝命令都会生效。
4.dockerfile动态修改服务配置文件
5.docker修改镜像中的文件 这个就是使用的cp命令覆盖了镜像中的一个文件
(4) Cannot invoke “java.lang.reflect.Method.invoke(Object, Object[])” because “com.sun.xml.bind.v2.runtime.reflect.opt.Injector.defineClass”
这个也是因为代码和java版本不匹配导致的问题,暂时没解决,还是把jdk降到了13,没有用17了。