Spring Boot多数据源问题

标签: 无 分类: 未分类 创建时间:2020-06-18 01:55:37 更新时间:2024-11-15 10:49:43

1.com.microsoft.sqlserver.jdbc.SQLServerException: 对象名 ‘pg_class’ 无效。

解决方法很奇怪,只要注释掉ddl-auto: update就可以了。

1
2
3
#  jpa:
# hibernate:
# ddl-auto: update

或者改为:

1
2
3
4
5
spring:
jpa:
properties:
hibernate.temp.use_jdbc_metadata_defaults: fase
hibernate.ddl-auto: update
参考文章:
1.spring-boot jpa 配置两个数据源
2.springBoot+Hibernate多数据源配置与使用 (这篇文章也可以借鉴,较新的集成两个数据源的方法)

2.对象名 ‘sec_his’ 无效

(1) 这个sec_his我在代码里没有,但是我有一个类名为SecHis,即实体为SecHis。初步查询资料,以为是返回值的问题,进行了尝试,没有任何的效果。

(2) 命名规则的问题
通过打开hibernate自动生成的sql语句,我发现了在查询表的时候,表名是用下滑线自动生成的,但是我的数据库的表名是secHis,而不是sec_his

经过我新建一个表,然后表名和字段名都统一使用小写,然后进行查询,结果出现的查询是正确的,那么最终确定了原因,就是hibernate的命名策略的问题。

我在getVendorProperties中,分别使用了下面的属性,但是还是不起作用,比如:physical_naming_strategy,DefaultNamingStrategy等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Map<String, Object> getVendorProperties(DataSource dataSource) {
Map<String,String> properties=jpaProperties.getProperties();
// 去掉postgresql的特性
properties.remove("hibernate.temp.use_jdbc_metadata_defaults");

properties.put("hibernate.naming.physical-strategy","org.hibernate.cfg.DefaultNamingStrategy");
properties.put("hibernate.naming.physical_naming_strategy", DefaultNamingStrategy.class.getName());
properties.put("hibernate.naming.physical_naming_strategy", PhysicalNamingStrategyStandardImpl.class.getName());
properties.put("hibernate.naming.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
properties.put("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");

HibernateSettings hibernateSettings=new HibernateSettings();
return hibernateProperties.determineHibernateProperties(
properties, new HibernateSettings());
}

命名策略主要有:
(1) org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
默认策略的表现为:表名及字段全小写,并以下划线分隔

(2) org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Hibernate 提供的命名策略是以实体名和属性名分别作为表名及字段名,但如果有定义 @Table 和 @Column ,则以该属性值进行映射命名

经过长时间的探索,终于找到了合适的命名策略的配置,implicit-strategy和physical-strategy缺一不可,这样就可以实现上面的第二条命名策略的效果了:以实体名和属性名分别作为表名及字段名,但如果有定义 @Table 和 @Column ,则以该属性值进行映射命名

1
2
3
4
5
6
spring:
jpa:
hibernate:
naming:
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
参考文章:
1.springBoot整合hibernate表名总是小写
2.Spring boot 自定义数据库命名策略 (这篇文章也写了如何自定义命名策略)
3.jpa多数据源时Hibernate配置自动生成表不生效 (这个其实可以看到如何配置hibernate,从源码的角度分析为什么配置不生效,但是说的不够全面,我也没有成功)
4.Spring Boot下使用JPA报错:’hibernate.dialect’ not set的解决办法
5.【hibernate】hibernate不同版本的命名策略
6.Hibernate5中实体映射命名策略
7.Hibernate入门之命名策略(naming strategy)详解 (这里写了四种命名策略,但是好像都说不到点子上,作为源码参考或者是理清命名策略的方法倒是可以参考)
8.Hibernate中实体映射时的命名策略(1)
9.如何自定义 JPA 的数据库命名策略 (这个讲的很清楚,只有两种命名策略,以及如何实现自定义的命名策略)
10.Jpa多数据源,为每个数据源配置单独的命名策略 (这里写了如何为多源数据库分别设置命名策略,但是很遗憾,我的springboot版本2.3.1中没有jpaProperties.getHibernate()方法,参见参考文章11、12、13)
11.12.1.从零开始学springboot-getHibernateProperties报错问题
12.Undefined method error occurs after upgrading from spring boot 2.0.6 to 2.1.0
13.getHibernateProperties cannot resolve,Spring boot 2.1.0+ JPA多数据源配置
14.Hibernate5中实体映射命名策略 (这篇文章,Hibernate5将此视为2阶段过程,最终让我测试成功了,实现了自己的功能)
15.SpringBoot和JPA多数据源整合 (这篇文章对多源数据分别进行不同的hibernate进行配置,提供了思路,比如不同的数据源配置不同的方言dialect)

3.Could not fetch the SequenceInformation from the database

(1) 当我在hibrenate属性中配置ddl-auto:update时,总会弹出这个错误:com.microsoft.sqlserver.jdbc.SQLServerException: 对象名 ‘INFORMATION_SCHEMA.SEQUENCES’ 无效,将属性删掉之后,就好了。

还有就是除了ddl-auto,我看有些文章中还设置了hibernate.hbm2ddl.auto这个属性,我却没有找到两者有什么差距的文章,但是两者使用方式和结果都是一样的。

最后经过周转,发现是因为我在第二个数据源的属性配置中添加了properties.remove(“hibernate.temp.use_jdbc_metadata_defaults”);这句代码,将其删除就不会报错了。

1
2
3
4
5
6
7
8
private Map<String, Object> getVendorProperties(DataSource dataSource) {
Map<String,String> properties=jpaProperties.getProperties();
// 去掉postgresql的特性
// properties.remove("hibernate.temp.use_jdbc_metadata_defaults");
properties.put("hibernate.dialect","org.hibernate.dialect.SQLServer2012Dialect");
return hibernateProperties.determineHibernateProperties(
properties, new HibernateSettings());
}

但是我也不能加上ddl-auto:update,否则也会报同样的错误。
根据进一步的分析无法添加ddl-auto:update,多半是因为没有数据的写权限,因为我连接数据的时候,使用了只读的账号,所以无法自动创建数据表。

(2) 在第二个数据源也就是sqlserver数据源的属性中必须添加如下代码,否则也会出现:对象名 ‘INFORMATION_SCHEMA.SEQUENCES’ 无效

1
2
3
4
5
6
7
private Map<String, Object> getVendorProperties(DataSource dataSource) {
Map<String,String> properties=new HashMap<>();
properties.put("hibernate.temp.use_jdbc_metadata_defaults","false"); // 这句话必须要
return hibernateProperties.determineHibernateProperties(
properties, new HibernateSettings());
}

问题虽然被解决了,但是我还是有一个非常疑惑的问题,就是“createClob() 方法尚未被实作问题”不见了,当我删除掉所有的配置代码,回归到最初的状态,甚至没有添加hibernate.temp.use_jdbc_metadata_defaults属性时,程序竟然没有报错,我也已经无法还原事故现场了,无论怎么改,都还原不到出现“未被实作”的状态了。

终于知道如何才能出现“createClob() 方法尚未被实作问题”问题了
是因为使用的版本问题,使用2.1.8.RELEASE版本就会出现“createClob() 方法尚未被实作问题”,当把版本升级到2.3.1.RELEASE,这个postgresql问题就应没有了。

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

总结

针对多数据源的时候,第一数据源为postgresql,第二个数据源为sql server,则需要有以下几点配置
~~ (1) sql server数据源,必须添加:hibernate.temp.use_jdbc_metadata_defaults=false
(2) sql server数据源连接时如何是只读用户,不能设置:hibernate.hbm2ddl.auto=update
(3) 当第二个数据源sqlserver设置了hibernate.temp.use_jdbc_metadata_defaults=false,即便第一个数据源postgresql数据源不设置:hibernate.temp.use_jdbc_metadata_defaults=false也不会再报错createClob() 方法尚未被实作问题 ~~

(1) 如果sql server数据源配置了:”hibernate.dialect”=”org.hibernate.dialect.SQLServer2012Dialect”,就要相应的配置:”hibernate.temp.use_jdbc_metadata_defaults”=”false”,否则会报对象名 ‘INFORMATION_SCHEMA.SEQUENCES’ 无效
(2) ql server数据源连接时如何是只读用户,不能设置:hibernate.hbm2ddl.auto=update

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。