使用c3p0数据库连接池和故障转移的Spring Boot JDBCTemplate

8

我需要在使用c3p0连接池的SpringBoot应用程序(内嵌Tomcat)中,为使用JdbcTemplate的ibatis建立数据库连接故障转移。以下是我的应用程序的application.properties。我有主数据库和辅助数据库。如果主数据库出现故障,则应在运行时使用副本进行数据库连接故障转移。请帮助我实现此目标。我尝试将多个数据库URL包含在配置中,但未生效。(错误正在出现)

c3p0 Java数据库连接池,故障转移配置 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

什么是错误?您已经查看了https://stackoverflow.com/questions/39208028/spring-multiple-data-source-configuration-auto-fail-over-mechanism/39208259#39208259和https://medium.com/@joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7。 - Sheetal Mohan Sharma
URL的格式不正确,因为我使用逗号分割了URL。 - sunleo
你需要定义2组密钥-请参考我下面的回答并查看我提供的链接和代码。 - Sheetal Mohan Sharma
2个回答

8
据我所知,故障转移配置取决于JDBC驱动程序。在Oracle的情况下,您可以使用连接描述符进行配置。因此,在您的情况下,您需要将以下内容放入tnsnames.ora文件中: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配置故障转移,请参见以下链接:

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

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

编辑:

  • 你收到的错误表明你尝试连接到服务器上不存在的服务名称 - 更多信息在这里
  • 我今天重新仔细阅读了文档(特别是我上面链接的PDF),似乎在连接字符串中指定辅助服务名称是可能的,因此在您的情况下,在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 = db1) (FAILOVER_MODE = (TYPE = select) (METHOD = preconnect) (RETRIES = 180) (DELAY = 10) (BACKUP = 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 = (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 = 1) ) ) )

为了模拟主连接失败(因为显然google.com上没有Oracle数据库),我使用连接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 does not currently know of service requested in connect descriptor。 - sunleo
谢谢,这很有帮助。 - sunleo

1

你需要定义两组属性并分别引用它们 - 注意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文档

@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();
}

您还可以参考逐步指南此处


但是在这里,你将如何包含多个数据源到实体管理器中? - sunleo
根据逐步指南,它是针对多个表而不是故障转移的。 - sunleo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接