带有 c3p0 数据库池和故障转移的 Spring Boot JDBCTemplate

Posted

技术标签:

【中文标题】带有 c3p0 数据库池和故障转移的 Spring Boot JDBCTemplate【英文标题】:Spring Boot JDBCTemplate with c3p0 DataBase Pooling and failover 【发布时间】:2018-12-04 00:49:29 【问题描述】:

我需要在 SpringBoot 应用程序(嵌入式 tomcat)中为 ibatis 建立 DB connectionfailover,其中 jdbctemplate 使用 c3p0 进行连接池。下面是我的应用程序的 applicaiton.properties。我有主数据库和辅助数据库。如果主数据库失败,那么辅助应该用于运行时的数据库连接故障转移。请帮助我实现这一点。我尝试在配置中包含多个 DB url,但它不起作用。

c3p0 Java Database Pooling, failover configuration https://docs.genesys.com/Documentation/Composer/8.1.4/Help/ConnectionPooling

application.properties:(错误来了)

#      connection properties for data source
##########################################################################################################
spring.datasource.c3p0.driverClass=oracle.jdbc.driver.OracleDriver
spring.datasource.c3p0.maxConnectionAge=3600
spring.datasource.c3p0.maxIdleTime=600
spring.datasource.c3p0.initialPoolSize=5
spring.datasource.c3p0.maxPoolSize=10
spring.datasource.c3p0.minPoolSize=5
spring.datasource.c3p0.acquireIncrement=1

##########################################################################################################


spring.datasource.url=jdbc:oracle:thin:@primary.com:1521:db1,jdbc:oracle:thin:@secondary.com:1521:db2
spring.datasource.username=user
spring.datasource.password=password

【问题讨论】:

错误是什么?你已经看过***.com/questions/39208028/…和medium.com/@joeclever/… 它说 url 的格式是错误的,因为我使用逗号分割了 url。 您需要定义 2 组键 - 请参阅下面的答案并参考我提供的链接和代码。 【参考方案1】:

据我所知,故障转移配置取决于 JDBC 驱动程序。如果是 Oracle,您可以使用连接描述符对其进行配置。所以在你的情况下,你可以把它放在tnsnames.ora

CONNECTION_WITH_FAILOVER = 
    (DESCRIPTION =
        (ADDRESS_LIST =
            (ADDRESS = (PROTOCOL = TCP)(HOST = primary.com)(PORT = 1521))
            (ADDRESS = (PROTOCOL = TCP)(HOST = secondary.com)(PORT = 1521))
            (LOAD_BALANCE = no)
            (FAILOVER = yes)
        )
        (CONNECT_DATA =
            (SERVER = DEDICATED)
            (SERVICE_NAME = db)
            (FAILOVER_MODE =
                (TYPE = select)
                (METHOD = preconnect)
                (RETRIES = 180)
                (DELAY = 10)
            )
        )
    )

然后在你的配置中:

spring.datasource.url=jdbc:oracle:thin:@CONNECTION_WITH_FAILOVER 

当然,您可能没有或不想使用tnsnames.ora,在这种情况下,您可以使用连接描述符作为 JDBC 连接字符串的一部分:

spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=primary.com)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=secondary.com)(PORT=1521))(LOAD_BALANCE=no)(FAILOVER=yes))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=db)(FAILOVER_MODE=(TYPE=select)(METHOD=preconnect)(RETRIES=180)(DELAY=10))))

有关连接描述符、tnsnames.ora 和为 Oracle DB 配置故障转移的更多详细信息,请参阅这些链接:

Local Naming Parameters Oracle and OCI & JDBC connection strings TNS_ADMIN - 用于配置tnsnames.ora 的位置 Description of failover mode in Oracle DB (pdf) - 包含参数 FAILOVER_MODE 的描述

请注意,所有数据库上的服务名称必须相同,因此我将您配置中的db1db2 替换为db

如果您想拥有不同的服务名称,您必须以编程方式配置单独的数据源(如 Sheetal Mohan Sharma 所述)。

编辑:

您收到的错误表明您正在尝试连接到服务器上不存在的服务名称 - 更多 here

我今天更仔细地重新阅读了文档(特别是我上面链接的 PDF),似乎可以在连接字符串中指定辅助服务名称,因此在您的情况下,tnsnames.ora 中的条目将是:

CONNECTION_WITH_FAILOVER = (描述= (地址列表 = (地址 =(协议 = TCP)(主机 = primary.com)(端口 = 1521)) (地址 =(协议 = TCP)(主机 = secondary.com)(端口 = 1521)) (负载平衡 = 否) (故障转移 = 是) ) (连接数据 = (服务器 = 专用) (SERVICE_NAME = db1) (FAILOVER_MODE = (类型 = 选择) (方法 = 预连接) (重试 = 180) (延迟 = 10) (备份 = db2) ) ) )

并作为 application.properties 中的 JDBC URL:

spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=primary.com)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=secondary.com)(PORT=1521))(LOAD_BALANCE=no)(FAILOVER=yes))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=db1)(FAILOVER_MODE=(TYPE=select)(METHOD=preconnect)(RETRIES=180)(DELAY=10)(BACKUP = db2))))

我目前没有配置这样的设置,所以我把它放在我的 tnsnames.ora 中:

CONNECTION_WITH_FAILOVER = (描述= (地址列表 = (地址 =(协议 = TCP)(主机 = google.com)(端口 = 1521)) (地址 =(协议 = TCP)(主机 = 我的实际数据库)(端口 = 我的数据库端口)) (负载平衡 = 否) (故障转移 = 是) ) (连接数据 = (服务器 = 专用) (SERVICE_NAME = 我的服务名称) (FAILOVER_MODE = (类型 = 选择) (方法 = 预连接) (重试 = 1) (延迟 = 1) ) ) )

模拟主连接失败(因为显然 google.com 上没有运行 Oracle DB)并设法使用 DataGrip 使用连接 URL 连接到我的数据库:jdbc:oracle:thin:@CONNECTION_WITH_FAILOVER

我也直接在 JDBC URL 中使用连接描述符进行了尝试:

jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=google.com)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=my-actual-database)(PORT=my-db-port))(LOAD_BALANCE=no)(FAILOVER=yes))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=my-service-name)(FAILOVER_MODE=(TYPE=select)(METHOD=preconnect)(RETRIES=1)(DELAY=5))))

而且效果也很好,尽管两次建立连接都需要相当长的时间(但这可能与我的网络配置或驱动程序的连接超时值有关)

确保配置 FAILOVER_MODE 参数以满足您的需求 - 特别考虑 RETIRES 和 DELAY 值 - 在我提供的示例中,我使用了 180 次重试和 10 秒重试之间的延迟,再加上每次重试时的连接超时和驱动程序实际切换到故障转移连接可能需要很长时间。

【讨论】:

你能给我一个工作的例子吗?我尝试使用以下单行更改与主要和次要的相同主机 spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=primary.com)(PORT =1521))(ADDRESS=(PROTOCOL=TCP)(HOST=primary.com)(PORT=1521))(LOAD_BALANCE=no)(FAILOVER=yes))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=db)( FAILOVER_MODE=(TYPE=select)(METHOD=preconnect)(RETRIES=180)(DELAY=10)))) 但 ORA-12514 出现异常,TNS:listener 目前不知道连接描述符中请求的服务 谢谢,这很有帮助。【参考方案2】:

您需要定义 2 组属性并分别引用它们 - 注意 url 键的区别

#set1
app.datasource.url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.pool-size=30

#set2
app.datasource.jdbc-url=jdbc:mysql://localhost/test
app.datasource.username=dbuser
app.datasource.password=dbpass
app.datasource.maximum-pool-size=30

但是,如果您使用 JDBC 或 JPA 的默认自动配置,则可以将其中一个标记为 @Primary(然后任何@Autowired 注入都会选择该配置)。

参考-Spring docs

@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() 
    return DataSourceBuilder.create().build();


@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() 
    return DataSourceBuilder.create().build();

您也可以参考分步指南here。

【讨论】:

但是如何在 entitymanager 中包含多个数据源? 根据分步指南,它是针对多个表而不是用于故障转移

以上是关于带有 c3p0 数据库池和故障转移的 Spring Boot JDBCTemplate的主要内容,如果未能解决你的问题,请参考以下文章

spring配置连接池和dao使用jdbcTemplate

C3P0连接池的使用

c3p0数据库连接池的使用详解

带有 sql 连接字符串的 perl 脚本看似故障转移点(。)

案例分享:数据库镜像故障转移失败

Spring Batch 连接池和多线程