在运行时获取数据库主机名
Getting the database host name at runtime
有一个连接到 Oracle 数据的 Springboot 应用程序。数据库的 URL 配置为
spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=\
(LOAD_BALANCE=OFF)(FAILOVER=ON)\
(ADDRESS=(PROTOCOL=TCP)(HOST=domainName1.com) (PORT=1521))\
(ADDRESS=(PROTOCOL=TCP)(HOST=domainName2.com)(PORT=1521))\
(CONNECT_DATA=(SERVICE_NAME=xyz)))
此 URL 配置为当一台主机关闭时应用程序连接到第二个数据库。
到数据库的URL在应用程序健康检查中打印如下所示
Hello
version : 4.0.0
build : 2022-03-3
datasource : oracle.jdbc.OracleDriver
db url : jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=OFF)(FAILOVER=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=domainName1.com) (PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=domainName2.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xyz)))
db status : ok
我的问题是如何只获取正在使用的数据库的主机名,这意味着我如何获取应用程序当前正在使用的主机(domainName1 或 domainName2)并将其显示在健康检查中?例如下图。
Hello
version : 4.0.0
build : 2022-03-3
datasource : oracle.jdbc.OracleDriver
db url : jdbc:oracle:thin:@domainName1.com: 1521/coldv1
db status : ok (LVZ count = 379)
我用于此健康检查的 java 代码如下所示。
@GetMapping(path = "/healthcheck",
produces = MediaType.APPLICATION_JSON_VALUE
)
public String getServiceStatus(){
String[] activeProfiles = environment.getActiveProfiles();
final BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(dataSource);
final String driverClassName = String.valueOf(accessor.getPropertyValue("driverClassName"));
String url = null;
if(activeProfiles[1].equals("external_tomcat")) {
url = String.valueOf(accessor.getPropertyValue("url"));
}else{
try {
String[] dataSourceProperties = nameService.getDataSource();
url = dataSourceProperties[0];
} catch (SQLException ex) {
// throwables.printStackTrace();
log.error(ex.getMessage(), ex);
}
}
String version = buildProperties.getVersion();
String buildTimestamp = String.valueOf(buildProperties.getTime());
BigDecimal count = nameService.getCount("Table_name_of_database");
StringBuilder result = new StringBuilder("Hello")
.append("\nversion :\t")
.append(version)
.append("\nbuild :\t")
.append(buildTimestamp)
.append("\ndatasource :\t")
.append(driverClassName)
.append("\ndb url :\t")
.append(url)
.append("\ndb status :\tok ")
.append(count.intValue())
.append(")");
return result.toString();
}
NameService.java
@Override
public String[] getDataSource() throws SQLException {
return getDataSourceProperties();
}
public String[] getDataSourceProperties() {
String[] dataSourceProperties = new String[2];
HikariDataSource dataSource = getDataSourceFromHibernateEntityManager();
if(dataSource.getJdbcUrl() != null){
dataSourceProperties[0] = dataSource.getJdbcUrl();
dataSourceProperties[1] = dataSource.getDataSourceClassName();
}
return dataSourceProperties;
}
一种解决方案是执行 SQL 查询以检索服务器主机名,例如:
SELECT host_name FROM v$instance
有关详细信息,请参阅 this question。
数据库实例有此数据可用,因此您应该询问数据库实例。
使用 v$instance 很诱人,但这需要额外的 select 权限。
SELECT sys_context('USERENV','SERVER_HOST') server_host
FROM dual;
不需要额外权限。
如果您无法像其他 2 个答案那样从数据库中获取它,则使用 @Value:
将 spring 属性 注入到组件中
@Value("spring.datasource.url")
String datasource;
然后从字符串中解析出值。
您是否考虑过更原生的方法?
我的意思是你为什么不装饰数据源实现。
您可以使用 org.springframework.beans.factory.config.BeanPostProcessor
及其变体来实现此目的,并使用一个对象来包装您的数据源和 decorates/override Datasource#getConnection
以通知或保存值或 属性 你想要某个地方。
使用
dataSource.getConnection().getMetaData().getURL();
@Olivier 和@ik_zelf 两个答案都适合我。
我在 spring 引导应用程序中实现的方式是使用以下代码片段。
public String getHostNameFromUrl() {
String sql = "SELECT host_name FROM v$instance";
// String sql = "SELECT sys_context('USERENV','SERVER_HOST') server_host FROM dual"; this also works
Query query = entityManager.createNativeQuery(sql);
return query.getSingleResult().toString();
}
稍后在控制器中我调用此方法显示在健康检查中。
有一个连接到 Oracle 数据的 Springboot 应用程序。数据库的 URL 配置为
spring.datasource.url=jdbc:oracle:thin:@(DESCRIPTION=\
(LOAD_BALANCE=OFF)(FAILOVER=ON)\
(ADDRESS=(PROTOCOL=TCP)(HOST=domainName1.com) (PORT=1521))\
(ADDRESS=(PROTOCOL=TCP)(HOST=domainName2.com)(PORT=1521))\
(CONNECT_DATA=(SERVICE_NAME=xyz)))
此 URL 配置为当一台主机关闭时应用程序连接到第二个数据库。 到数据库的URL在应用程序健康检查中打印如下所示
Hello
version : 4.0.0
build : 2022-03-3
datasource : oracle.jdbc.OracleDriver
db url : jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=OFF)(FAILOVER=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=domainName1.com) (PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=domainName2.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=xyz)))
db status : ok
我的问题是如何只获取正在使用的数据库的主机名,这意味着我如何获取应用程序当前正在使用的主机(domainName1 或 domainName2)并将其显示在健康检查中?例如下图。
Hello
version : 4.0.0
build : 2022-03-3
datasource : oracle.jdbc.OracleDriver
db url : jdbc:oracle:thin:@domainName1.com: 1521/coldv1
db status : ok (LVZ count = 379)
我用于此健康检查的 java 代码如下所示。
@GetMapping(path = "/healthcheck",
produces = MediaType.APPLICATION_JSON_VALUE
)
public String getServiceStatus(){
String[] activeProfiles = environment.getActiveProfiles();
final BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(dataSource);
final String driverClassName = String.valueOf(accessor.getPropertyValue("driverClassName"));
String url = null;
if(activeProfiles[1].equals("external_tomcat")) {
url = String.valueOf(accessor.getPropertyValue("url"));
}else{
try {
String[] dataSourceProperties = nameService.getDataSource();
url = dataSourceProperties[0];
} catch (SQLException ex) {
// throwables.printStackTrace();
log.error(ex.getMessage(), ex);
}
}
String version = buildProperties.getVersion();
String buildTimestamp = String.valueOf(buildProperties.getTime());
BigDecimal count = nameService.getCount("Table_name_of_database");
StringBuilder result = new StringBuilder("Hello")
.append("\nversion :\t")
.append(version)
.append("\nbuild :\t")
.append(buildTimestamp)
.append("\ndatasource :\t")
.append(driverClassName)
.append("\ndb url :\t")
.append(url)
.append("\ndb status :\tok ")
.append(count.intValue())
.append(")");
return result.toString();
}
NameService.java
@Override
public String[] getDataSource() throws SQLException {
return getDataSourceProperties();
}
public String[] getDataSourceProperties() {
String[] dataSourceProperties = new String[2];
HikariDataSource dataSource = getDataSourceFromHibernateEntityManager();
if(dataSource.getJdbcUrl() != null){
dataSourceProperties[0] = dataSource.getJdbcUrl();
dataSourceProperties[1] = dataSource.getDataSourceClassName();
}
return dataSourceProperties;
}
一种解决方案是执行 SQL 查询以检索服务器主机名,例如:
SELECT host_name FROM v$instance
有关详细信息,请参阅 this question。
数据库实例有此数据可用,因此您应该询问数据库实例。
使用 v$instance 很诱人,但这需要额外的 select 权限。
SELECT sys_context('USERENV','SERVER_HOST') server_host
FROM dual;
不需要额外权限。
如果您无法像其他 2 个答案那样从数据库中获取它,则使用 @Value:
将 spring 属性 注入到组件中@Value("spring.datasource.url")
String datasource;
然后从字符串中解析出值。
您是否考虑过更原生的方法? 我的意思是你为什么不装饰数据源实现。
您可以使用 org.springframework.beans.factory.config.BeanPostProcessor
及其变体来实现此目的,并使用一个对象来包装您的数据源和 decorates/override Datasource#getConnection
以通知或保存值或 属性 你想要某个地方。
使用
dataSource.getConnection().getMetaData().getURL();
@Olivier 和@ik_zelf 两个答案都适合我。 我在 spring 引导应用程序中实现的方式是使用以下代码片段。
public String getHostNameFromUrl() {
String sql = "SELECT host_name FROM v$instance";
// String sql = "SELECT sys_context('USERENV','SERVER_HOST') server_host FROM dual"; this also works
Query query = entityManager.createNativeQuery(sql);
return query.getSingleResult().toString();
}
稍后在控制器中我调用此方法显示在健康检查中。