----初始化项目
This commit is contained in:
74
persistence/pom.xml
Normal file
74
persistence/pom.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-all</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>nacos-persistence</artifactId>
|
||||
<name>nacos-persistence ${project.version}</name>
|
||||
<url>https://nacos.io</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-datasource-plugin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-sys</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-consistency</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>kingbase</groupId>
|
||||
<artifactId>kingbase</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration;
|
||||
|
||||
import com.alibaba.nacos.persistence.constants.PersistenceConstant;
|
||||
import com.alibaba.nacos.persistence.utils.DatasourcePlatformUtil;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* Configuration about datasource.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DatasourceConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
/**
|
||||
* Standalone mode uses DB.
|
||||
*/
|
||||
public static boolean useExternalDB = false;
|
||||
|
||||
/**
|
||||
* Inline storage value = ${nacos.standalone}.
|
||||
*/
|
||||
public static boolean embeddedStorage = EnvUtil.getStandaloneMode();
|
||||
|
||||
public static boolean isUseExternalDB() {
|
||||
return useExternalDB;
|
||||
}
|
||||
|
||||
public static void setUseExternalDB(boolean useExternalDB) {
|
||||
DatasourceConfiguration.useExternalDB = useExternalDB;
|
||||
}
|
||||
|
||||
public static boolean isEmbeddedStorage() {
|
||||
return embeddedStorage;
|
||||
}
|
||||
|
||||
public static void setEmbeddedStorage(boolean embeddedStorage) {
|
||||
DatasourceConfiguration.embeddedStorage = embeddedStorage;
|
||||
}
|
||||
|
||||
private void loadDatasourceConfiguration() {
|
||||
// External data sources are used by default in cluster mode
|
||||
String platform = DatasourcePlatformUtil.getDatasourcePlatform("");
|
||||
boolean useExternalStorage =
|
||||
!PersistenceConstant.EMPTY_DATASOURCE_PLATFORM.equalsIgnoreCase(platform) && !PersistenceConstant.DERBY
|
||||
.equalsIgnoreCase(platform);
|
||||
setUseExternalDB(useExternalStorage);
|
||||
|
||||
// must initialize after setUseExternalDB
|
||||
// This value is true in stand-alone mode and false in cluster mode
|
||||
// If this value is set to true in cluster mode, nacos's distributed storage engine is turned on
|
||||
// default value is depend on ${nacos.standalone}
|
||||
|
||||
if (isUseExternalDB()) {
|
||||
setEmbeddedStorage(false);
|
||||
} else {
|
||||
boolean embeddedStorage = isEmbeddedStorage() || Boolean.getBoolean(PersistenceConstant.EMBEDDED_STORAGE);
|
||||
setEmbeddedStorage(embeddedStorage);
|
||||
|
||||
// If the embedded data source storage is not turned on, it is automatically
|
||||
// upgraded to the external data source storage, as before
|
||||
if (!embeddedStorage) {
|
||||
setUseExternalDB(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(final ConfigurableApplicationContext applicationContext) {
|
||||
loadDatasourceConfiguration();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* when embeddedStorage==true and nacos.standalone=false
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class ConditionDistributedEmbedStorage implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return DatasourceConfiguration.isEmbeddedStorage() && !EnvUtil.getStandaloneMode();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* Judge whether to user EmbeddedStorage by condition.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class ConditionOnEmbeddedStorage implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return DatasourceConfiguration.isEmbeddedStorage();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* Judge whether to user ExternalStorage by condition.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class ConditionOnExternalStorage implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return !DatasourceConfiguration.isEmbeddedStorage();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* Judge whether to user StandaloneEmbedStorage by condition.
|
||||
* When embeddedStorage==false.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class ConditionStandaloneEmbedStorage implements Condition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return DatasourceConfiguration.isEmbeddedStorage() && EnvUtil.getStandaloneMode();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.constants;
|
||||
|
||||
/**
|
||||
* Persistence constant.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class PersistenceConstant {
|
||||
|
||||
public static final String DEFAULT_ENCODE = "UTF-8";
|
||||
|
||||
/**
|
||||
* May be removed with the upgrade of springboot version.
|
||||
*/
|
||||
public static final String DATASOURCE_PLATFORM_PROPERTY_OLD = "spring.datasource.platform";
|
||||
|
||||
public static final String DATASOURCE_PLATFORM_PROPERTY = "spring.sql.init.platform";
|
||||
|
||||
public static final String MYSQL = "mysql";
|
||||
|
||||
public static final String DERBY = "derby";
|
||||
|
||||
public static final String EMPTY_DATASOURCE_PLATFORM = "";
|
||||
|
||||
public static final String EMBEDDED_STORAGE = "embeddedStorage";
|
||||
|
||||
/**
|
||||
* The derby base dir.
|
||||
*/
|
||||
public static final String DERBY_BASE_DIR = "derby-data";
|
||||
|
||||
/**
|
||||
* Specifies that reads wait without timeout.
|
||||
*/
|
||||
public static final String EXTEND_NEED_READ_UNTIL_HAVE_DATA = "00--0-read-join-0--00";
|
||||
|
||||
public static final String CONFIG_MODEL_RAFT_GROUP = "nacos_config";
|
||||
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* DataSource pool properties.
|
||||
*
|
||||
* <p>Nacos server use HikariCP as the datasource pool. So the basic pool properties will based on {@link
|
||||
* com.zaxxer.hikari.HikariDataSource}.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DataSourcePoolProperties {
|
||||
|
||||
public static final long DEFAULT_CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(3L);
|
||||
|
||||
public static final long DEFAULT_VALIDATION_TIMEOUT = TimeUnit.SECONDS.toMillis(10L);
|
||||
|
||||
public static final long DEFAULT_IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10L);
|
||||
|
||||
public static final int DEFAULT_MAX_POOL_SIZE = 20;
|
||||
|
||||
public static final int DEFAULT_MINIMUM_IDLE = 2;
|
||||
|
||||
private final HikariDataSource dataSource;
|
||||
|
||||
private DataSourcePoolProperties() {
|
||||
dataSource = new HikariDataSource();
|
||||
dataSource.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
|
||||
dataSource.setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
|
||||
dataSource.setValidationTimeout(DEFAULT_VALIDATION_TIMEOUT);
|
||||
dataSource.setMaximumPoolSize(DEFAULT_MAX_POOL_SIZE);
|
||||
dataSource.setMinimumIdle(DEFAULT_MINIMUM_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build new Hikari config.
|
||||
*
|
||||
* @return new hikari config
|
||||
*/
|
||||
public static DataSourcePoolProperties build(Environment environment) {
|
||||
DataSourcePoolProperties result = new DataSourcePoolProperties();
|
||||
Binder.get(environment).bind("db.pool.config", Bindable.ofInstance(result.getDataSource()));
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDriverClassName(final String driverClassName) {
|
||||
dataSource.setDriverClassName(driverClassName);
|
||||
}
|
||||
|
||||
public void setJdbcUrl(final String jdbcUrl) {
|
||||
dataSource.setJdbcUrl(jdbcUrl);
|
||||
}
|
||||
|
||||
public void setUsername(final String username) {
|
||||
dataSource.setUsername(username);
|
||||
}
|
||||
|
||||
public void setPassword(final String password) {
|
||||
dataSource.setPassword(password);
|
||||
}
|
||||
|
||||
public HikariDataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
/**
|
||||
* Datasource interface.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public interface DataSourceService {
|
||||
|
||||
/**
|
||||
* Initialize the relevant resource information.
|
||||
*
|
||||
* @throws Exception exception.
|
||||
*/
|
||||
void init() throws Exception;
|
||||
|
||||
/**
|
||||
* Reload.
|
||||
*
|
||||
* @throws IOException exception.
|
||||
*/
|
||||
void reload() throws IOException;
|
||||
|
||||
/**
|
||||
* Check master db.
|
||||
*
|
||||
* @return is master.
|
||||
*/
|
||||
boolean checkMasterWritable();
|
||||
|
||||
/**
|
||||
* Get jdbc template.
|
||||
*
|
||||
* @return JdbcTemplate.
|
||||
*/
|
||||
JdbcTemplate getJdbcTemplate();
|
||||
|
||||
/**
|
||||
* Get transaction template.
|
||||
*
|
||||
* @return TransactionTemplate.
|
||||
*/
|
||||
TransactionTemplate getTransactionTemplate();
|
||||
|
||||
/**
|
||||
* Get current db url.
|
||||
*
|
||||
* @return database url
|
||||
*/
|
||||
String getCurrentDbUrl();
|
||||
|
||||
/**
|
||||
* Get heath information.
|
||||
*
|
||||
* @return heath info.
|
||||
*/
|
||||
String getHealth();
|
||||
|
||||
/**
|
||||
* Get current db type.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getDataSourceType();
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
|
||||
/**
|
||||
* Datasource adapter.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class DynamicDataSource {
|
||||
|
||||
private DataSourceService localDataSourceService = null;
|
||||
|
||||
private DataSourceService basicDataSourceService = null;
|
||||
|
||||
private static final DynamicDataSource INSTANCE = new DynamicDataSource();
|
||||
|
||||
private DynamicDataSource() {}
|
||||
|
||||
public static DynamicDataSource getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public synchronized DataSourceService getDataSource() {
|
||||
try {
|
||||
|
||||
// Embedded storage is used by default in stand-alone mode
|
||||
// In cluster mode, external databases are used by default
|
||||
|
||||
if (DatasourceConfiguration.isEmbeddedStorage()) {
|
||||
if (localDataSourceService == null) {
|
||||
localDataSourceService = new LocalDataSourceServiceImpl();
|
||||
localDataSourceService.init();
|
||||
}
|
||||
return localDataSourceService;
|
||||
} else {
|
||||
if (basicDataSourceService == null) {
|
||||
basicDataSourceService = new ExternalDataSourceServiceImpl();
|
||||
basicDataSourceService.init();
|
||||
}
|
||||
return basicDataSourceService;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.common.utils.Preconditions;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.core.env.Environment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.alibaba.nacos.common.utils.CollectionUtils.getOrDefault;
|
||||
|
||||
/**
|
||||
* Properties of external DataSource.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class ExternalDataSourceProperties {
|
||||
|
||||
private static final String JDBC_DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
|
||||
|
||||
private static final String TEST_QUERY = "SELECT 1";
|
||||
|
||||
private Integer num;
|
||||
|
||||
private List<String> url = new ArrayList<>();
|
||||
|
||||
private List<String> user = new ArrayList<>();
|
||||
|
||||
private List<String> password = new ArrayList<>();
|
||||
|
||||
private List<String> driverClassName = new ArrayList<>();
|
||||
|
||||
private List<String> testQuery = new ArrayList<>();
|
||||
|
||||
public void setNum(Integer num) {
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
public void setUrl(List<String> url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setUser(List<String> user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void setPassword(List<String> password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public List<String> getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public void setDriverClassName(List<String> driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
public void setTestQuery(List<String> testQuery) {
|
||||
this.testQuery = testQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build serveral HikariDataSource.
|
||||
*
|
||||
* @param environment {@link Environment}
|
||||
* @param callback Callback function when constructing data source
|
||||
* @return List of {@link HikariDataSource}
|
||||
*/
|
||||
List<HikariDataSource> build(Environment environment, Callback<HikariDataSource> callback) {
|
||||
List<HikariDataSource> dataSources = new ArrayList<>();
|
||||
Binder.get(environment).bind("db", Bindable.ofInstance(this));
|
||||
Preconditions.checkArgument(Objects.nonNull(num), "db.num is null");
|
||||
Preconditions.checkArgument(isNotEmpty(user), "db.user or db.user.[index] is null");
|
||||
Preconditions.checkArgument(isNotEmpty(password), "db.password or db.password.[index] is null");
|
||||
Preconditions.checkArgument(isNotEmpty(driverClassName), "db.driverClassName or db.driverClassName.[index] is null");
|
||||
for (int index = 0; index < num; index++) {
|
||||
int currentSize = index + 1;
|
||||
Preconditions.checkArgument(url.size() >= currentSize, "db.url.%s is null", index);
|
||||
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(environment);
|
||||
poolProperties.setDriverClassName(getOrDefault(driverClassName, index, JDBC_DRIVER_NAME).trim());
|
||||
poolProperties.setJdbcUrl(url.get(index).trim());
|
||||
poolProperties.setUsername(getOrDefault(user, index, user.get(0)).trim());
|
||||
poolProperties.setPassword(getOrDefault(password, index, password.get(0)).trim());
|
||||
HikariDataSource ds = poolProperties.getDataSource();
|
||||
if (StringUtils.isEmpty(ds.getConnectionTestQuery())) {
|
||||
ds.setConnectionTestQuery(getOrDefault(testQuery, index, TEST_QUERY).trim());
|
||||
}
|
||||
dataSources.add(ds);
|
||||
callback.accept(ds);
|
||||
}
|
||||
Preconditions.checkArgument(isNotEmpty(dataSources), "no datasource available");
|
||||
return dataSources;
|
||||
}
|
||||
|
||||
|
||||
public <E>boolean isNotEmpty(Collection<E> col) {
|
||||
return col!=null && !col.isEmpty();
|
||||
}
|
||||
|
||||
interface Callback<D> {
|
||||
|
||||
/**
|
||||
* Perform custom logic.
|
||||
*
|
||||
* @param datasource dataSource.
|
||||
*/
|
||||
void accept(D datasource);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ConvertUtils;
|
||||
import com.alibaba.nacos.common.utils.InternetAddressUtil;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.persistence.monitor.DatasourceMetrics;
|
||||
import com.alibaba.nacos.persistence.utils.ConnectionCheckUtil;
|
||||
import com.alibaba.nacos.persistence.utils.DatasourcePlatformUtil;
|
||||
import com.alibaba.nacos.persistence.utils.PersistenceExecutor;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Base data source.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class ExternalDataSourceServiceImpl implements DataSourceService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ExternalDataSourceServiceImpl.class);
|
||||
|
||||
/**
|
||||
* JDBC execute timeout value, unit:second.
|
||||
*/
|
||||
private int queryTimeout = 3;
|
||||
|
||||
private static final int TRANSACTION_QUERY_TIMEOUT = 5;
|
||||
|
||||
private static final int DB_MASTER_SELECT_THRESHOLD = 1;
|
||||
|
||||
private static final String DB_LOAD_ERROR_MSG = "[db-load-error]load jdbc.properties error";
|
||||
|
||||
private List<HikariDataSource> dataSourceList = new ArrayList<>();
|
||||
|
||||
private JdbcTemplate jt;
|
||||
|
||||
private DataSourceTransactionManager tm;
|
||||
|
||||
private TransactionTemplate tjt;
|
||||
|
||||
private JdbcTemplate testMasterJT;
|
||||
|
||||
private JdbcTemplate testMasterWritableJT;
|
||||
|
||||
private volatile List<JdbcTemplate> testJtList;
|
||||
|
||||
private volatile List<Boolean> isHealthList;
|
||||
|
||||
private volatile int masterIndex;
|
||||
|
||||
private String dataSourceType = "";
|
||||
|
||||
private final String defaultDataSourceType = "";
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
queryTimeout = ConvertUtils.toInt(System.getProperty("QUERYTIMEOUT"), 3);
|
||||
jt = new JdbcTemplate();
|
||||
// Set the maximum number of records to prevent memory expansion
|
||||
jt.setMaxRows(50000);
|
||||
jt.setQueryTimeout(queryTimeout);
|
||||
|
||||
testMasterJT = new JdbcTemplate();
|
||||
testMasterJT.setQueryTimeout(queryTimeout);
|
||||
|
||||
testMasterWritableJT = new JdbcTemplate();
|
||||
// Prevent the login interface from being too long because the main library is not available
|
||||
testMasterWritableJT.setQueryTimeout(1);
|
||||
|
||||
// Database health check
|
||||
|
||||
testJtList = new ArrayList<>();
|
||||
isHealthList = new ArrayList<>();
|
||||
|
||||
tm = new DataSourceTransactionManager();
|
||||
tjt = new TransactionTemplate(tm);
|
||||
|
||||
// Transaction timeout needs to be distinguished from ordinary operations.
|
||||
tjt.setTimeout(120);
|
||||
|
||||
dataSourceType = DatasourcePlatformUtil.getDatasourcePlatform(defaultDataSourceType);
|
||||
|
||||
if (DatasourceConfiguration.isUseExternalDB()) {
|
||||
try {
|
||||
reload();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("[ExternalDataSourceService] datasource reload error", e);
|
||||
throw new RuntimeException(DB_LOAD_ERROR_MSG, e);
|
||||
}
|
||||
|
||||
if (this.dataSourceList.size() > DB_MASTER_SELECT_THRESHOLD) {
|
||||
PersistenceExecutor.scheduleTask(new SelectMasterTask(), 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
PersistenceExecutor.scheduleTask(new CheckDbHealthTask(), 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reload() throws IOException {
|
||||
try {
|
||||
final List<JdbcTemplate> testJtListNew = new ArrayList<JdbcTemplate>();
|
||||
final List<Boolean> isHealthListNew = new ArrayList<Boolean>();
|
||||
|
||||
List<HikariDataSource> dataSourceListNew = new ExternalDataSourceProperties()
|
||||
.build(EnvUtil.getEnvironment(), (dataSource) -> {
|
||||
//check datasource connection
|
||||
ConnectionCheckUtil.checkDataSourceConnection(dataSource);
|
||||
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
jdbcTemplate.setQueryTimeout(queryTimeout);
|
||||
jdbcTemplate.setDataSource(dataSource);
|
||||
testJtListNew.add(jdbcTemplate);
|
||||
isHealthListNew.add(Boolean.TRUE);
|
||||
});
|
||||
|
||||
final List<HikariDataSource> dataSourceListOld = dataSourceList;
|
||||
final List<JdbcTemplate> testJtListOld = testJtList;
|
||||
dataSourceList = dataSourceListNew;
|
||||
testJtList = testJtListNew;
|
||||
isHealthList = isHealthListNew;
|
||||
new SelectMasterTask().run();
|
||||
new CheckDbHealthTask().run();
|
||||
|
||||
//close old datasource.
|
||||
if (dataSourceListOld != null && !dataSourceListOld.isEmpty()) {
|
||||
for (HikariDataSource dataSource : dataSourceListOld) {
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
if (testJtListOld != null && !testJtListOld.isEmpty()) {
|
||||
for (JdbcTemplate oldJdbc : testJtListOld) {
|
||||
oldJdbc.setDataSource(null);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOGGER.error(DB_LOAD_ERROR_MSG, e);
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMasterWritable() {
|
||||
|
||||
testMasterWritableJT.setDataSource(jt.getDataSource());
|
||||
// Prevent the login interface from being too long because the main library is not available
|
||||
testMasterWritableJT.setQueryTimeout(1);
|
||||
String sql = " SELECT @@read_only ";
|
||||
|
||||
try {
|
||||
Integer result = testMasterWritableJT.queryForObject(sql, Integer.class);
|
||||
if (result == null) {
|
||||
return false;
|
||||
} else {
|
||||
return result == 0;
|
||||
}
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] " + e.toString(), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcTemplate getJdbcTemplate() {
|
||||
return this.jt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionTemplate getTransactionTemplate() {
|
||||
return this.tjt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentDbUrl() {
|
||||
DataSource ds = this.jt.getDataSource();
|
||||
if (ds == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
HikariDataSource bds = (HikariDataSource) ds;
|
||||
return bds.getJdbcUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHealth() {
|
||||
for (int i = 0; i < isHealthList.size(); i++) {
|
||||
if (!isHealthList.get(i)) {
|
||||
if (i == masterIndex) {
|
||||
// The master is unhealthy.
|
||||
return "DOWN:" + InternetAddressUtil.getIPFromString(dataSourceList.get(i).getJdbcUrl());
|
||||
} else {
|
||||
// The slave is unhealthy.
|
||||
return "WARN:" + InternetAddressUtil.getIPFromString(dataSourceList.get(i).getJdbcUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "UP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSourceType() {
|
||||
return dataSourceType;
|
||||
}
|
||||
|
||||
class SelectMasterTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("check master db.");
|
||||
}
|
||||
boolean isFound = false;
|
||||
|
||||
int index = -1;
|
||||
for (HikariDataSource ds : dataSourceList) {
|
||||
index++;
|
||||
testMasterJT.setDataSource(ds);
|
||||
testMasterJT.setQueryTimeout(queryTimeout);
|
||||
try {
|
||||
testMasterJT.update("DELETE FROM config_info WHERE data_id='com.alibaba.nacos.testMasterDB'");
|
||||
if (jt.getDataSource() != ds) {
|
||||
LOGGER.warn("[master-db] {}", ds.getJdbcUrl());
|
||||
}
|
||||
jt.setDataSource(ds);
|
||||
tm.setDataSource(ds);
|
||||
isFound = true;
|
||||
masterIndex = index;
|
||||
break;
|
||||
} catch (DataAccessException e) { // read only
|
||||
LOGGER.warn("[master-db] master db access error", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFound) {
|
||||
LOGGER.error("[master-db] master db not found.");
|
||||
DatasourceMetrics.getDbException().increment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
class CheckDbHealthTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("check db health.");
|
||||
}
|
||||
String sql = "SELECT * FROM config_info_beta WHERE id = 1";
|
||||
|
||||
for (int i = 0; i < testJtList.size(); i++) {
|
||||
JdbcTemplate jdbcTemplate = testJtList.get(i);
|
||||
try {
|
||||
try {
|
||||
jdbcTemplate.queryForMap(sql);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
// do nothing.
|
||||
}
|
||||
isHealthList.set(i, Boolean.TRUE);
|
||||
} catch (DataAccessException e) {
|
||||
if (i == masterIndex) {
|
||||
LOGGER.error("[db-error] master db {} down.",
|
||||
InternetAddressUtil.getIPFromString(dataSourceList.get(i).getJdbcUrl()));
|
||||
} else {
|
||||
LOGGER.error("[db-error] slave db {} down.",
|
||||
InternetAddressUtil.getIPFromString(dataSourceList.get(i).getJdbcUrl()));
|
||||
}
|
||||
isHealthList.set(i, Boolean.FALSE);
|
||||
|
||||
DatasourceMetrics.getDbException().increment();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
|
||||
import com.alibaba.nacos.common.utils.IoUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.persistence.constants.PersistenceConstant;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* local data source.
|
||||
*
|
||||
* @author Nacos
|
||||
*/
|
||||
public class LocalDataSourceServiceImpl implements DataSourceService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LocalDataSourceServiceImpl.class);
|
||||
|
||||
private final String jdbcDriverName = "org.apache.derby.jdbc.EmbeddedDriver";
|
||||
|
||||
private final String userName = "nacos";
|
||||
|
||||
private final String password = "nacos";
|
||||
|
||||
private final String derbyBaseDir = "data" + File.separator + PersistenceConstant.DERBY_BASE_DIR;
|
||||
|
||||
private final String derbyShutdownErrMsg = "Derby system shutdown.";
|
||||
|
||||
private volatile JdbcTemplate jt;
|
||||
|
||||
private volatile TransactionTemplate tjt;
|
||||
|
||||
private boolean initialize = false;
|
||||
|
||||
private boolean jdbcTemplateInit = false;
|
||||
|
||||
private String healthStatus = "UP";
|
||||
|
||||
private String dataSourceType = "derby";
|
||||
|
||||
@Override
|
||||
public synchronized void init() throws Exception {
|
||||
if (DatasourceConfiguration.isUseExternalDB()) {
|
||||
return;
|
||||
}
|
||||
if (!initialize) {
|
||||
LOGGER.info("use local db service for init");
|
||||
final String jdbcUrl = "jdbc:derby:" + Paths.get(EnvUtil.getNacosHome(), derbyBaseDir) + ";create=true";
|
||||
initialize(jdbcUrl);
|
||||
initialize = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reload() {
|
||||
DataSource ds = jt.getDataSource();
|
||||
if (ds == null) {
|
||||
throw new RuntimeException("datasource is null");
|
||||
}
|
||||
try {
|
||||
execute(ds.getConnection(), "META-INF/derby-schema.sql");
|
||||
} catch (Exception e) {
|
||||
if (LOGGER.isErrorEnabled()) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
throw new NacosRuntimeException(NacosException.SERVER_ERROR, "load derby-schema.sql error.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public DataSource getDatasource() {
|
||||
return jt.getDataSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean and reopen Derby.
|
||||
*
|
||||
* @throws Exception exception.
|
||||
*/
|
||||
public void cleanAndReopenDerby() throws Exception {
|
||||
doDerbyClean();
|
||||
final String jdbcUrl =
|
||||
"jdbc:derby:" + Paths.get(EnvUtil.getNacosHome(), derbyBaseDir).toString() + ";create=true";
|
||||
initialize(jdbcUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore derby.
|
||||
*
|
||||
* @param jdbcUrl jdbcUrl string value.
|
||||
* @param callable callable.
|
||||
* @throws Exception exception.
|
||||
*/
|
||||
public void restoreDerby(String jdbcUrl, Callable<Void> callable) throws Exception {
|
||||
doDerbyClean();
|
||||
callable.call();
|
||||
initialize(jdbcUrl);
|
||||
}
|
||||
|
||||
private void doDerbyClean() throws Exception {
|
||||
LOGGER.warn("use local db service for reopenDerby");
|
||||
try {
|
||||
DriverManager.getConnection("jdbc:derby:;shutdown=true");
|
||||
} catch (Exception e) {
|
||||
// An error is thrown when the Derby shutdown is executed, which should be ignored
|
||||
if (!StringUtils.containsIgnoreCase(e.getMessage(), derbyShutdownErrMsg)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
DiskUtils.deleteDirectory(Paths.get(EnvUtil.getNacosHome(), derbyBaseDir).toString());
|
||||
}
|
||||
|
||||
private synchronized void initialize(String jdbcUrl) {
|
||||
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(EnvUtil.getEnvironment());
|
||||
poolProperties.setDriverClassName(jdbcDriverName);
|
||||
poolProperties.setJdbcUrl(jdbcUrl);
|
||||
poolProperties.setUsername(userName);
|
||||
poolProperties.setPassword(password);
|
||||
HikariDataSource ds = poolProperties.getDataSource();
|
||||
DataSourceTransactionManager tm = new DataSourceTransactionManager();
|
||||
tm.setDataSource(ds);
|
||||
if (jdbcTemplateInit) {
|
||||
jt.setDataSource(ds);
|
||||
tjt.setTransactionManager(tm);
|
||||
} else {
|
||||
jt = new JdbcTemplate();
|
||||
jt.setMaxRows(50000);
|
||||
jt.setQueryTimeout(5000);
|
||||
jt.setDataSource(ds);
|
||||
tjt = new TransactionTemplate(tm);
|
||||
tjt.setTimeout(5000);
|
||||
jdbcTemplateInit = true;
|
||||
}
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMasterWritable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcTemplate getJdbcTemplate() {
|
||||
return jt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionTemplate getTransactionTemplate() {
|
||||
return tjt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentDbUrl() {
|
||||
return "jdbc:derby:" + EnvUtil.getNacosHome() + File.separator + derbyBaseDir + ";create=true";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHealth() {
|
||||
return healthStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSourceType() {
|
||||
return dataSourceType;
|
||||
}
|
||||
|
||||
public void setHealthStatus(String healthStatus) {
|
||||
this.healthStatus = healthStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load sql.
|
||||
*
|
||||
* @param sqlFile sql.
|
||||
* @return sqls.
|
||||
* @throws Exception Exception.
|
||||
*/
|
||||
private List<String> loadSql(String sqlFile) throws Exception {
|
||||
List<String> sqlList = new ArrayList<>();
|
||||
InputStream sqlFileIn = null;
|
||||
try {
|
||||
File file = new File(
|
||||
EnvUtil.getNacosHome() + File.separator + "conf" + File.separator + "derby-schema.sql");
|
||||
if (StringUtils.isBlank(EnvUtil.getNacosHome()) || !file.exists()) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
URL url = classLoader.getResource(sqlFile);
|
||||
sqlFileIn = url.openStream();
|
||||
} else {
|
||||
sqlFileIn = new FileInputStream(file);
|
||||
}
|
||||
|
||||
StringBuilder sqlSb = new StringBuilder();
|
||||
byte[] buff = new byte[1024];
|
||||
int byteRead = 0;
|
||||
while ((byteRead = sqlFileIn.read(buff)) != -1) {
|
||||
sqlSb.append(new String(buff, 0, byteRead, PersistenceConstant.DEFAULT_ENCODE));
|
||||
}
|
||||
|
||||
String[] sqlArr = sqlSb.toString().split(";");
|
||||
for (int i = 0; i < sqlArr.length; i++) {
|
||||
String sql = sqlArr[i].replaceAll("--.*", "").trim();
|
||||
if (StringUtils.isNotEmpty(sql)) {
|
||||
sqlList.add(sql);
|
||||
}
|
||||
}
|
||||
return sqlList;
|
||||
} catch (Exception ex) {
|
||||
throw new Exception(ex.getMessage());
|
||||
} finally {
|
||||
IoUtils.closeQuietly(sqlFileIn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute sql.
|
||||
*
|
||||
* @param conn connect.
|
||||
* @param sqlFile sql.
|
||||
* @throws Exception Exception.
|
||||
*/
|
||||
private void execute(Connection conn, String sqlFile) throws Exception {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
List<String> sqlList = loadSql(sqlFile);
|
||||
for (String sql : sqlList) {
|
||||
try {
|
||||
stmt.execute(sql);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.exception;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* NJdbcException.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class NJdbcException extends DataAccessException {
|
||||
|
||||
private String originExceptionName;
|
||||
|
||||
public NJdbcException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public NJdbcException(String msg, String originExceptionName) {
|
||||
super(msg);
|
||||
this.originExceptionName = originExceptionName;
|
||||
}
|
||||
|
||||
public NJdbcException(String msg, Throwable cause, String originExceptionName) {
|
||||
super(msg, cause);
|
||||
this.originExceptionName = originExceptionName;
|
||||
}
|
||||
|
||||
public NJdbcException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public NJdbcException(Throwable cause) {
|
||||
super("", cause);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Page.
|
||||
*
|
||||
* @author boyan
|
||||
* @date 2010-5-6
|
||||
*/
|
||||
public class Page<E> implements Serializable {
|
||||
|
||||
static final long serialVersionUID = 1234544030560484292L;
|
||||
|
||||
/**
|
||||
* totalCount.
|
||||
*/
|
||||
private int totalCount;
|
||||
|
||||
/**
|
||||
* pageNumber.
|
||||
*/
|
||||
private int pageNumber;
|
||||
|
||||
/**
|
||||
* pagesAvailable.
|
||||
*/
|
||||
private int pagesAvailable;
|
||||
|
||||
/**
|
||||
* pageItems.
|
||||
*/
|
||||
private List<E> pageItems = new ArrayList<>();
|
||||
|
||||
public void setPageNumber(int pageNumber) {
|
||||
this.pageNumber = pageNumber;
|
||||
}
|
||||
|
||||
public void setPagesAvailable(int pagesAvailable) {
|
||||
this.pagesAvailable = pagesAvailable;
|
||||
}
|
||||
|
||||
public void setPageItems(List<E> pageItems) {
|
||||
this.pageItems = pageItems;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(int totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public int getPageNumber() {
|
||||
return pageNumber;
|
||||
}
|
||||
|
||||
public int getPagesAvailable() {
|
||||
return pagesAvailable;
|
||||
}
|
||||
|
||||
public List<E> getPageItems() {
|
||||
return pageItems;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.model.event;
|
||||
|
||||
import com.alibaba.nacos.common.notify.SlowEvent;
|
||||
|
||||
/**
|
||||
* Data import event.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class DerbyImportEvent extends SlowEvent {
|
||||
|
||||
private static final long serialVersionUID = 3299565864352399053L;
|
||||
|
||||
private final boolean finished;
|
||||
|
||||
public DerbyImportEvent(boolean finished) {
|
||||
this.finished = finished;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.model.event;
|
||||
|
||||
import com.alibaba.nacos.common.notify.SlowEvent;
|
||||
|
||||
/**
|
||||
* DerbyLoadEvent.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class DerbyLoadEvent extends SlowEvent {
|
||||
|
||||
public static final DerbyLoadEvent INSTANCE = new DerbyLoadEvent();
|
||||
|
||||
private static final long serialVersionUID = 875401667921565121L;
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.model.event;
|
||||
|
||||
import com.alibaba.nacos.common.notify.SlowEvent;
|
||||
|
||||
/**
|
||||
* RaftDBErrorEvent.
|
||||
*
|
||||
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class RaftDbErrorEvent extends SlowEvent {
|
||||
|
||||
private static final long serialVersionUID = 101591819161802336L;
|
||||
|
||||
private Throwable ex;
|
||||
|
||||
public RaftDbErrorEvent() {
|
||||
}
|
||||
|
||||
public RaftDbErrorEvent(Throwable ex) {
|
||||
this.ex = ex;
|
||||
}
|
||||
|
||||
public Throwable getEx() {
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.monitor;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
|
||||
/**
|
||||
* Metrics for datasource.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class DatasourceMetrics {
|
||||
|
||||
public static Counter getDbException() {
|
||||
// TODO: After {@code NacosMeterRegistryCenter} move to more basic module, the usage can be changed.
|
||||
// TODO: Current {@code NacosMeterRegistryCenter} is in core module, but core module maybe depend persistence to save namespace.
|
||||
return Metrics.counter("nacos_exception", "module", "config", "name", "db");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository;
|
||||
|
||||
import com.alibaba.nacos.persistence.model.Page;
|
||||
import com.alibaba.nacos.plugin.datasource.model.MapperResult;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Pagination Utils interface.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractMethodOrInterfaceMethodMustUseJavadocRule")
|
||||
public interface PaginationHelper<E> {
|
||||
|
||||
Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, final Object[] args, final int pageNo,
|
||||
final int pageSize, final RowMapper<E> rowMapper);
|
||||
|
||||
Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, final Object[] args, final int pageNo,
|
||||
final int pageSize, final Long lastMaxId, final RowMapper<E> rowMapper);
|
||||
|
||||
Page<E> fetchPageLimit(final String sqlCountRows, final String sqlFetchRows, final Object[] args, final int pageNo,
|
||||
final int pageSize, final RowMapper<E> rowMapper);
|
||||
|
||||
Page<E> fetchPageLimit(final String sqlCountRows, final Object[] args1, final String sqlFetchRows,
|
||||
final Object[] args2, final int pageNo, final int pageSize, final RowMapper<E> rowMapper);
|
||||
|
||||
Page<E> fetchPageLimit(final String sqlFetchRows, final Object[] args, final int pageNo, final int pageSize,
|
||||
final RowMapper<E> rowMapper);
|
||||
|
||||
Page<E> fetchPageLimit(final MapperResult countMapperResult, final MapperResult mapperResult, final int pageNo,
|
||||
final int pageSize, final RowMapper<E> rowMapper);
|
||||
|
||||
void updateLimit(final String sql, final Object[] args);
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manager RowMapper {@link RowMapper} for database object mapping.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public final class RowMapperManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RowMapperManager.class);
|
||||
|
||||
public static final MapRowMapper MAP_ROW_MAPPER = new MapRowMapper();
|
||||
|
||||
public static Map<String, RowMapper> mapperMap = new HashMap<>(16);
|
||||
|
||||
static {
|
||||
// MAP_ROW_MAPPER
|
||||
mapperMap.put(MAP_ROW_MAPPER.getClass().getCanonicalName(), MAP_ROW_MAPPER);
|
||||
}
|
||||
|
||||
public static <D> RowMapper<D> getRowMapper(String classFullName) {
|
||||
return (RowMapper<D>) mapperMap.get(classFullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register custom row mapper to manager.
|
||||
*
|
||||
* @param classFullName full class name of row mapper handled.
|
||||
* @param rowMapper row mapper
|
||||
* @param <D> class of row mapper handled
|
||||
*/
|
||||
public static synchronized <D> void registerRowMapper(String classFullName, RowMapper<D> rowMapper) {
|
||||
if (mapperMap.containsKey(classFullName)) {
|
||||
LOGGER.warn("row mapper {} conflicts, {} will be replaced by {}", classFullName,
|
||||
mapperMap.get(classFullName).getClass().getCanonicalName(),
|
||||
rowMapper.getClass().getCanonicalName());
|
||||
}
|
||||
mapperMap.put(classFullName, rowMapper);
|
||||
}
|
||||
|
||||
public static final class MapRowMapper implements RowMapper<Map<String, Object>> {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> mapRow(ResultSet resultSet, int rowNum) throws SQLException {
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
Map<String, Object> map = new LinkedHashMap<>(columnCount);
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded;
|
||||
|
||||
import com.alibaba.nacos.persistence.model.Page;
|
||||
import com.alibaba.nacos.persistence.repository.PaginationHelper;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.operate.DatabaseOperate;
|
||||
import com.alibaba.nacos.plugin.datasource.model.MapperResult;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Pagination Utils For Apache Derby.
|
||||
*
|
||||
* @param <E> Generic class
|
||||
* @author boyan
|
||||
* @date 2010-5-6
|
||||
*/
|
||||
public class EmbeddedPaginationHelperImpl<E> implements PaginationHelper {
|
||||
|
||||
private final DatabaseOperate databaseOperate;
|
||||
|
||||
public EmbeddedPaginationHelperImpl(DatabaseOperate databaseOperate) {
|
||||
this.databaseOperate = databaseOperate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take paging.
|
||||
*
|
||||
* @param sqlCountRows Query total SQL
|
||||
* @param sqlFetchRows Query data sql
|
||||
* @param args query args
|
||||
* @param pageNo page number
|
||||
* @param pageSize page size
|
||||
* @param rowMapper Entity mapping
|
||||
* @return Paging data
|
||||
*/
|
||||
@Override
|
||||
public Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, final Object[] args,
|
||||
final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
return fetchPage(sqlCountRows, sqlFetchRows, args, pageNo, pageSize, null, rowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, Object[] args, final int pageNo,
|
||||
final int pageSize, final Long lastMaxId, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
// Query the total number of current records
|
||||
Integer rowCountInt = databaseOperate.queryOne(sqlCountRows, args, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Count pages
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
|
||||
List<E> result = databaseOperate.queryMany(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlCountRows, final String sqlFetchRows, final Object[] args,
|
||||
final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Query the total number of current records
|
||||
Integer rowCountInt = databaseOperate.queryOne(sqlCountRows, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Count pages
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
|
||||
List<E> result = databaseOperate.queryMany(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlCountRows, final Object[] args1, final String sqlFetchRows,
|
||||
final Object[] args2, final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Query the total number of current records
|
||||
Integer rowCountInt = databaseOperate.queryOne(sqlCountRows, args1, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Count pages
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
|
||||
List<E> result = databaseOperate.queryMany(sqlFetchRows, args2, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlFetchRows, final Object[] args, final int pageNo, final int pageSize,
|
||||
final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
|
||||
List<E> result = databaseOperate.queryMany(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page fetchPageLimit(MapperResult countMapperResult, MapperResult mapperResult, int pageNo, int pageSize,
|
||||
RowMapper rowMapper) {
|
||||
return fetchPageLimit(countMapperResult.getSql(), countMapperResult.getParamList().toArray(),
|
||||
mapperResult.getSql(), mapperResult.getParamList().toArray(), pageNo, pageSize, rowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLimit(final String sql, final Object[] args) {
|
||||
EmbeddedStorageContextHolder.addSqlContext(sql, args);
|
||||
try {
|
||||
databaseOperate.update(EmbeddedStorageContextHolder.getCurrentSqlContext());
|
||||
} finally {
|
||||
EmbeddedStorageContextHolder.cleanAllContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded;
|
||||
|
||||
import com.alibaba.nacos.persistence.repository.embedded.sql.ModifyRequest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Embedded storae context holder.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class EmbeddedStorageContextHolder {
|
||||
|
||||
private static final ThreadLocal<ArrayList<ModifyRequest>> SQL_CONTEXT = ThreadLocal.withInitial(ArrayList::new);
|
||||
|
||||
private static final ThreadLocal<Map<String, String>> EXTEND_INFO_CONTEXT = ThreadLocal.withInitial(HashMap::new);
|
||||
|
||||
/**
|
||||
* Add sql context.
|
||||
*
|
||||
* @param sql sql
|
||||
* @param args argument list
|
||||
*/
|
||||
public static void addSqlContext(String sql, Object... args) {
|
||||
ArrayList<ModifyRequest> requests = SQL_CONTEXT.get();
|
||||
ModifyRequest context = new ModifyRequest();
|
||||
context.setExecuteNo(requests.size());
|
||||
context.setSql(sql);
|
||||
context.setArgs(args);
|
||||
requests.add(context);
|
||||
SQL_CONTEXT.set(requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sql context.
|
||||
*
|
||||
* @param rollbackOnUpdateFail roll back when update fail
|
||||
* @param sql sql
|
||||
* @param args argument list
|
||||
*/
|
||||
public static void addSqlContext(boolean rollbackOnUpdateFail, String sql, Object... args) {
|
||||
ArrayList<ModifyRequest> requests = SQL_CONTEXT.get();
|
||||
ModifyRequest context = new ModifyRequest();
|
||||
context.setExecuteNo(requests.size());
|
||||
context.setSql(sql);
|
||||
context.setArgs(args);
|
||||
context.setRollBackOnUpdateFail(rollbackOnUpdateFail);
|
||||
requests.add(context);
|
||||
SQL_CONTEXT.set(requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put extend info.
|
||||
*
|
||||
* @param key key
|
||||
* @param value value
|
||||
*/
|
||||
public static void putExtendInfo(String key, String value) {
|
||||
Map<String, String> old = EXTEND_INFO_CONTEXT.get();
|
||||
old.put(key, value);
|
||||
EXTEND_INFO_CONTEXT.set(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all extend info.
|
||||
*
|
||||
* @param map all extend info
|
||||
*/
|
||||
public static void putAllExtendInfo(Map<String, String> map) {
|
||||
Map<String, String> old = EXTEND_INFO_CONTEXT.get();
|
||||
old.putAll(map);
|
||||
EXTEND_INFO_CONTEXT.set(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if key is included.
|
||||
*
|
||||
* @param key key
|
||||
* @return {@code true} if contains key
|
||||
*/
|
||||
public static boolean containsExtendInfo(String key) {
|
||||
Map<String, String> extendInfo = EXTEND_INFO_CONTEXT.get();
|
||||
boolean exist = extendInfo.containsKey(key);
|
||||
EXTEND_INFO_CONTEXT.set(extendInfo);
|
||||
return exist;
|
||||
}
|
||||
|
||||
public static List<ModifyRequest> getCurrentSqlContext() {
|
||||
return SQL_CONTEXT.get();
|
||||
}
|
||||
|
||||
public static Map<String, String> getCurrentExtendInfo() {
|
||||
return EXTEND_INFO_CONTEXT.get();
|
||||
}
|
||||
|
||||
public static void cleanAllContext() {
|
||||
SQL_CONTEXT.remove();
|
||||
EXTEND_INFO_CONTEXT.remove();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.hook;
|
||||
|
||||
import com.alibaba.nacos.consistency.entity.WriteRequest;
|
||||
|
||||
/**
|
||||
* Embedded storage apply hook.
|
||||
*
|
||||
* <p>Async Hook after embedded storage apply raft log.</p>
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
|
||||
public abstract class EmbeddedApplyHook {
|
||||
|
||||
protected EmbeddedApplyHook() {
|
||||
EmbeddedApplyHookHolder.getInstance().register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after apply finished.
|
||||
*
|
||||
* @param log raft log
|
||||
*/
|
||||
public abstract void afterApply(WriteRequest log);
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.hook;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holder for Embedded apply hook.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class EmbeddedApplyHookHolder {
|
||||
|
||||
private static final EmbeddedApplyHookHolder INSTANCE = new EmbeddedApplyHookHolder();
|
||||
|
||||
private final Set<EmbeddedApplyHook> hooks;
|
||||
|
||||
private EmbeddedApplyHookHolder() {
|
||||
hooks = new HashSet<>();
|
||||
}
|
||||
|
||||
public static EmbeddedApplyHookHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void register(EmbeddedApplyHook hook) {
|
||||
this.hooks.add(hook);
|
||||
}
|
||||
|
||||
public Set<EmbeddedApplyHook> getAllHooks() {
|
||||
return this.hooks;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.operate;
|
||||
|
||||
import com.alibaba.nacos.common.utils.ExceptionUtil;
|
||||
import com.alibaba.nacos.common.utils.LoggerUtils;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.sql.ModifyRequest;
|
||||
import com.alibaba.nacos.persistence.utils.DerbyUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.transaction.IllegalTransactionStateException;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* The Derby database basic operation.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractMethodOrInterfaceMethodMustUseJavadocRule")
|
||||
public interface BaseDatabaseOperate extends DatabaseOperate {
|
||||
|
||||
Logger LOGGER = LoggerFactory.getLogger(BaseDatabaseOperate.class);
|
||||
|
||||
/**
|
||||
* query one result by sql then convert result to target type.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param cls target type
|
||||
* @param <R> target type
|
||||
* @return R
|
||||
*/
|
||||
default <R> R queryOne(JdbcTemplate jdbcTemplate, String sql, Class<R> cls) {
|
||||
try {
|
||||
return jdbcTemplate.queryForObject(sql, cls);
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] can't get connection : {}", ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException : {}", ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query one result by sql and args then convert result to target type.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @param cls target type
|
||||
* @param <R> target type
|
||||
* @return R
|
||||
*/
|
||||
default <R> R queryOne(JdbcTemplate jdbcTemplate, String sql, Object[] args, Class<R> cls) {
|
||||
try {
|
||||
return jdbcTemplate.queryForObject(sql, args, cls);
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] {}", e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", sql, args,
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query one result by sql and args then convert result to target type through {@link RowMapper}.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @param mapper {@link RowMapper}
|
||||
* @param <R> target type
|
||||
* @return R
|
||||
*/
|
||||
default <R> R queryOne(JdbcTemplate jdbcTemplate, String sql, Object[] args, RowMapper<R> mapper) {
|
||||
try {
|
||||
return jdbcTemplate.queryForObject(sql, args, mapper);
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] {}", e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", sql, args,
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query many result by sql and args then convert result to target type through {@link RowMapper}.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @param mapper {@link RowMapper}
|
||||
* @param <R> target type
|
||||
* @return result list
|
||||
*/
|
||||
default <R> List<R> queryMany(JdbcTemplate jdbcTemplate, String sql, Object[] args, RowMapper<R> mapper) {
|
||||
try {
|
||||
return jdbcTemplate.query(sql, args, mapper);
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] {}", e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", sql, args,
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query many result by sql and args then convert result to target type.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @param rClass target type class
|
||||
* @param <R> target type
|
||||
* @return result list
|
||||
*/
|
||||
default <R> List<R> queryMany(JdbcTemplate jdbcTemplate, String sql, Object[] args, Class<R> rClass) {
|
||||
try {
|
||||
return jdbcTemplate.queryForList(sql, args, rClass);
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] {}", e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", sql, args,
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query many result by sql and args then convert result to List<Map<String, Object>>.
|
||||
*
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @return List<Map<String, Object>>
|
||||
*/
|
||||
default List<Map<String, Object>> queryMany(JdbcTemplate jdbcTemplate, String sql, Object[] args) {
|
||||
try {
|
||||
return jdbcTemplate.queryForList(sql, args);
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] {}", e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", sql, args,
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* execute update operation.
|
||||
*
|
||||
* @param transactionTemplate {@link TransactionTemplate}
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param contexts {@link List} ModifyRequest list
|
||||
* @return {@link Boolean}
|
||||
*/
|
||||
default Boolean update(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate,
|
||||
List<ModifyRequest> contexts) {
|
||||
return update(transactionTemplate, jdbcTemplate, contexts, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* execute update operation, to fix #3617.
|
||||
*
|
||||
* @param transactionTemplate {@link TransactionTemplate}
|
||||
* @param jdbcTemplate {@link JdbcTemplate}
|
||||
* @param contexts {@link List} ModifyRequest list
|
||||
* @return {@link Boolean}
|
||||
*/
|
||||
default Boolean update(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate,
|
||||
List<ModifyRequest> contexts, BiConsumer<Boolean, Throwable> consumer) {
|
||||
boolean updateResult = Boolean.FALSE;
|
||||
try {
|
||||
updateResult = transactionTemplate.execute(status -> {
|
||||
String[] errSql = new String[] {null};
|
||||
Object[][] args = new Object[][] {null};
|
||||
try {
|
||||
contexts.forEach(pair -> {
|
||||
errSql[0] = pair.getSql();
|
||||
args[0] = pair.getArgs();
|
||||
boolean rollBackOnUpdateFail = pair.isRollBackOnUpdateFail();
|
||||
LoggerUtils.printIfDebugEnabled(LOGGER, "current sql : {}", errSql[0]);
|
||||
LoggerUtils.printIfDebugEnabled(LOGGER, "current args : {}", args[0]);
|
||||
int row = jdbcTemplate.update(pair.getSql(), pair.getArgs());
|
||||
if (rollBackOnUpdateFail && row < 1) {
|
||||
LoggerUtils.printIfDebugEnabled(LOGGER, "SQL update affected {} rows ", row);
|
||||
throw new IllegalTransactionStateException("Illegal transaction");
|
||||
}
|
||||
});
|
||||
if (consumer != null) {
|
||||
consumer.accept(Boolean.TRUE, null);
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
} catch (BadSqlGrammarException | DataIntegrityViolationException e) {
|
||||
LOGGER.error("[db-error] sql : {}, args : {}, error : {}", errSql[0], args[0], e.toString());
|
||||
if (consumer != null) {
|
||||
consumer.accept(Boolean.FALSE, e);
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
LOGGER.error("[db-error] sql : {}, args : {}, error : {}", errSql[0], args[0], e.toString());
|
||||
throw e;
|
||||
} catch (DataAccessException e) {
|
||||
LOGGER.error("[db-error] DataAccessException sql : {}, args : {}, error : {}", errSql[0], args[0],
|
||||
ExceptionUtil.getAllExceptionMsg(e));
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
} catch (IllegalTransactionStateException e) {
|
||||
LoggerUtils.printIfDebugEnabled(LOGGER, "Roll back transaction for {} ", e.getMessage());
|
||||
if (consumer != null) {
|
||||
consumer.accept(Boolean.FALSE, e);
|
||||
}
|
||||
}
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform data import.
|
||||
*
|
||||
* @param template {@link JdbcTemplate}
|
||||
* @param requests {@link List} ModifyRequest list
|
||||
* @return {@link Boolean}
|
||||
*/
|
||||
default Boolean doDataImport(JdbcTemplate template, List<ModifyRequest> requests) {
|
||||
final String[] sql = requests.stream().map(ModifyRequest::getSql).map(DerbyUtils::insertStatementCorrection)
|
||||
.toArray(String[]::new);
|
||||
int[] affect = template.batchUpdate(sql);
|
||||
return IntStream.of(affect).count() == requests.size();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.operate;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.EmbeddedStorageContextHolder;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.sql.ModifyRequest;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Derby database operation.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public interface DatabaseOperate {
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param cls target type
|
||||
* @param <R> return type
|
||||
* @return query result
|
||||
*/
|
||||
<R> R queryOne(String sql, Class<R> cls);
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param args sql parameters
|
||||
* @param cls target type
|
||||
* @param <R> return type
|
||||
* @return query result
|
||||
*/
|
||||
<R> R queryOne(String sql, Object[] args, Class<R> cls);
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param args sql parameters
|
||||
* @param mapper Database query result converter
|
||||
* @param <R> return type
|
||||
* @return query result
|
||||
*/
|
||||
<R> R queryOne(String sql, Object[] args, RowMapper<R> mapper);
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param args sql parameters
|
||||
* @param mapper Database query result converter
|
||||
* @param <R> return type
|
||||
* @return query result
|
||||
*/
|
||||
<R> List<R> queryMany(String sql, Object[] args, RowMapper<R> mapper);
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param args sql parameters
|
||||
* @param rClass target type
|
||||
* @param <R> return type
|
||||
* @return query result
|
||||
*/
|
||||
<R> List<R> queryMany(String sql, Object[] args, Class<R> rClass);
|
||||
|
||||
/**
|
||||
* Data query transaction.
|
||||
*
|
||||
* @param sql sqk text
|
||||
* @param args sql parameters
|
||||
* @return query result
|
||||
*/
|
||||
List<Map<String, Object>> queryMany(String sql, Object[] args);
|
||||
|
||||
/**
|
||||
* data modify transaction.
|
||||
*
|
||||
* @param modifyRequests {@link List}
|
||||
* @param consumer {@link BiConsumer}
|
||||
* @return is success
|
||||
*/
|
||||
Boolean update(List<ModifyRequest> modifyRequests, BiConsumer<Boolean, Throwable> consumer);
|
||||
|
||||
/**
|
||||
* data modify transaction.
|
||||
*
|
||||
* @param modifyRequests {@link List}
|
||||
* @return is success
|
||||
*/
|
||||
default Boolean update(List<ModifyRequest> modifyRequests) {
|
||||
return update(modifyRequests, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* data importing, This method is suitable for importing data from external data sources into embedded data
|
||||
* sources.
|
||||
*
|
||||
* @param file {@link File}
|
||||
* @return {@link CompletableFuture}
|
||||
*/
|
||||
CompletableFuture<RestResult<String>> dataImport(File file);
|
||||
|
||||
/**
|
||||
* data modify transaction The SqlContext to be executed in the current thread will be executed and automatically
|
||||
* cleared.
|
||||
*
|
||||
* @return is success
|
||||
*/
|
||||
default Boolean blockUpdate() {
|
||||
return blockUpdate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* data modify transaction The SqlContext to be executed in the current thread will be executed and automatically
|
||||
* cleared.
|
||||
* @author klw(213539@qq.com)
|
||||
* 2020/8/24 18:16
|
||||
* @param consumer the consumer
|
||||
* @return java.lang.Boolean
|
||||
*/
|
||||
default Boolean blockUpdate(BiConsumer<Boolean, Throwable> consumer) {
|
||||
try {
|
||||
return update(EmbeddedStorageContextHolder.getCurrentSqlContext(), consumer);
|
||||
} finally {
|
||||
EmbeddedStorageContextHolder.cleanAllContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* data modify transaction The SqlContext to be executed in the current thread will be executed and automatically
|
||||
* cleared.
|
||||
*
|
||||
* @return is success
|
||||
*/
|
||||
default CompletableFuture<Boolean> futureUpdate() {
|
||||
try {
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
update(EmbeddedStorageContextHolder.getCurrentSqlContext(), (o, throwable) -> {
|
||||
if (Objects.nonNull(throwable)) {
|
||||
future.completeExceptionally(throwable);
|
||||
return;
|
||||
}
|
||||
future.complete(o);
|
||||
});
|
||||
return future;
|
||||
} finally {
|
||||
EmbeddedStorageContextHolder.cleanAllContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.operate;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.common.model.RestResultUtils;
|
||||
import com.alibaba.nacos.common.utils.CollectionUtils;
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.persistence.configuration.condition.ConditionStandaloneEmbedStorage;
|
||||
import com.alibaba.nacos.persistence.datasource.DataSourceService;
|
||||
import com.alibaba.nacos.persistence.datasource.DynamicDataSource;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.sql.ModifyRequest;
|
||||
import com.alibaba.nacos.sys.utils.DiskUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Derby operation in stand-alone mode.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@Conditional(ConditionStandaloneEmbedStorage.class)
|
||||
@Component
|
||||
public class StandaloneDatabaseOperateImpl implements BaseDatabaseOperate {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StandaloneDatabaseOperateImpl.class);
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@PostConstruct
|
||||
protected void init() {
|
||||
DataSourceService dataSourceService = DynamicDataSource.getInstance().getDataSource();
|
||||
jdbcTemplate = dataSourceService.getJdbcTemplate();
|
||||
transactionTemplate = dataSourceService.getTransactionTemplate();
|
||||
LOGGER.info("use StandaloneDatabaseOperateImpl");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R queryOne(String sql, Class<R> cls) {
|
||||
return queryOne(jdbcTemplate, sql, cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R queryOne(String sql, Object[] args, Class<R> cls) {
|
||||
return queryOne(jdbcTemplate, sql, args, cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R queryOne(String sql, Object[] args, RowMapper<R> mapper) {
|
||||
return queryOne(jdbcTemplate, sql, args, mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> List<R> queryMany(String sql, Object[] args, RowMapper<R> mapper) {
|
||||
return queryMany(jdbcTemplate, sql, args, mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> List<R> queryMany(String sql, Object[] args, Class<R> rClass) {
|
||||
return queryMany(jdbcTemplate, sql, args, rClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> queryMany(String sql, Object[] args) {
|
||||
return queryMany(jdbcTemplate, sql, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RestResult<String>> dataImport(File file) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try (DiskUtils.LineIterator iterator = DiskUtils.lineIterator(file)) {
|
||||
int batchSize = 1000;
|
||||
List<String> batchUpdate = new ArrayList<>(batchSize);
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
List<Boolean> results = new CopyOnWriteArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
String sql = iterator.next();
|
||||
if (StringUtils.isNotBlank(sql)) {
|
||||
batchUpdate.add(sql);
|
||||
}
|
||||
if (batchUpdate.size() == batchSize || !iterator.hasNext()) {
|
||||
List<ModifyRequest> sqls = batchUpdate.stream().map(s -> {
|
||||
ModifyRequest request = new ModifyRequest();
|
||||
request.setSql(s);
|
||||
return request;
|
||||
}).collect(Collectors.toList());
|
||||
futures.add(CompletableFuture.runAsync(() -> results.add(doDataImport(jdbcTemplate, sqls))));
|
||||
batchUpdate.clear();
|
||||
}
|
||||
}
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
||||
int code = 500;
|
||||
if (!CollectionUtils.isEmpty(results)) {
|
||||
code = (!results.stream().anyMatch(Boolean.FALSE::equals)) ? 200 : 500;
|
||||
}
|
||||
return RestResult.<String>builder().withCode(code).withData("").build();
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.error("An exception occurred when external data was imported into Derby : ", ex);
|
||||
return RestResultUtils.failed(ex.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean update(List<ModifyRequest> modifyRequests, BiConsumer<Boolean, Throwable> consumer) {
|
||||
return update(transactionTemplate, jdbcTemplate, modifyRequests, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean update(List<ModifyRequest> requestList) {
|
||||
return update(transactionTemplate, jdbcTemplate, requestList);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.sql;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents a database UPDATE or INSERT or DELETE statement.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
|
||||
public class ModifyRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4548851816596520564L;
|
||||
|
||||
private int executeNo;
|
||||
|
||||
private String sql;
|
||||
|
||||
private boolean rollBackOnUpdateFail = Boolean.FALSE;
|
||||
|
||||
private Object[] args;
|
||||
|
||||
public ModifyRequest() {
|
||||
}
|
||||
|
||||
public ModifyRequest(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public int getExecuteNo() {
|
||||
return executeNo;
|
||||
}
|
||||
|
||||
public void setExecuteNo(int executeNo) {
|
||||
this.executeNo = executeNo;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(Object[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public boolean isRollBackOnUpdateFail() {
|
||||
return rollBackOnUpdateFail;
|
||||
}
|
||||
|
||||
public void setRollBackOnUpdateFail(boolean rollBackOnUpdateFail) {
|
||||
this.rollBackOnUpdateFail = rollBackOnUpdateFail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SQL{" + "executeNo=" + executeNo + ", sql='" + sql + '\'' + ", args=" + Arrays.toString(args) + '}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.sql;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Associated with the method correspondence of the {@link org.springframework.jdbc.core.JdbcTemplate}.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class QueryType {
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#queryForObject(String, RowMapper)}.
|
||||
*/
|
||||
public static final byte QUERY_ONE_WITH_MAPPER_WITH_ARGS = 0;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#queryForObject(String, Class)}.
|
||||
*/
|
||||
public static final byte QUERY_ONE_NO_MAPPER_NO_ARGS = 1;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#queryForObject(String, Object[], Class)}.
|
||||
*/
|
||||
public static final byte QUERY_ONE_NO_MAPPER_WITH_ARGS = 2;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#query(String, Object[], RowMapper)}.
|
||||
*/
|
||||
public static final byte QUERY_MANY_WITH_MAPPER_WITH_ARGS = 3;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#queryForList(String, Object...)}.
|
||||
*/
|
||||
public static final byte QUERY_MANY_WITH_LIST_WITH_ARGS = 4;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate#queryForList(String, Object[], Class)}.
|
||||
*/
|
||||
public static final byte QUERY_MANY_NO_MAPPER_WITH_ARGS = 5;
|
||||
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.sql;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents a database SELECT statement.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class SelectRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2212052574976898602L;
|
||||
|
||||
private byte queryType;
|
||||
|
||||
private String sql;
|
||||
|
||||
private Object[] args;
|
||||
|
||||
private String className;
|
||||
|
||||
public byte getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
public void setQueryType(byte queryType) {
|
||||
this.queryType = queryType;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public void setSql(String sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(Object[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SelectRequest{" + "queryType=" + queryType + ", sql='" + sql + '\'' + ", args=" + Arrays.toString(args)
|
||||
+ ", className='" + className + '\'' + '}';
|
||||
}
|
||||
|
||||
public static SelectRequestBuilder builder() {
|
||||
return new SelectRequestBuilder();
|
||||
}
|
||||
|
||||
public static final class SelectRequestBuilder {
|
||||
|
||||
private byte queryType;
|
||||
|
||||
private String sql;
|
||||
|
||||
private Object[] args;
|
||||
|
||||
private String className = null;
|
||||
|
||||
private SelectRequestBuilder() {
|
||||
}
|
||||
|
||||
public SelectRequestBuilder queryType(byte queryType) {
|
||||
this.queryType = queryType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectRequestBuilder sql(String sql) {
|
||||
this.sql = sql;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectRequestBuilder args(Object[] args) {
|
||||
this.args = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectRequestBuilder className(String className) {
|
||||
this.className = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* build select request.
|
||||
*
|
||||
* @return {@link SelectRequest}
|
||||
*/
|
||||
public SelectRequest build() {
|
||||
SelectRequest request = new SelectRequest();
|
||||
request.setQueryType(queryType);
|
||||
request.setSql(sql);
|
||||
request.setArgs(args);
|
||||
request.setClassName(className);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.extrnal;
|
||||
|
||||
import com.alibaba.nacos.persistence.model.Page;
|
||||
import com.alibaba.nacos.persistence.repository.PaginationHelper;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.EmbeddedStorageContextHolder;
|
||||
import com.alibaba.nacos.plugin.datasource.model.MapperResult;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* External Storage Pagination utils.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
|
||||
public class ExternalStoragePaginationHelperImpl<E> implements PaginationHelper {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public ExternalStoragePaginationHelperImpl(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take paging.
|
||||
*
|
||||
* @param sqlCountRows query total SQL
|
||||
* @param sqlFetchRows query data sql
|
||||
* @param args query parameters
|
||||
* @param pageNo page number
|
||||
* @param pageSize page size
|
||||
* @param rowMapper {@link RowMapper}
|
||||
* @return Paginated data {@code <E>}
|
||||
*/
|
||||
@Override
|
||||
public Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, final Object[] args,
|
||||
final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
return fetchPage(sqlCountRows, sqlFetchRows, args, pageNo, pageSize, null, rowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPage(final String sqlCountRows, final String sqlFetchRows, Object[] args, final int pageNo,
|
||||
final int pageSize, final Long lastMaxId, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
|
||||
// Query the total number of current records.
|
||||
Integer rowCountInt = jdbcTemplate.queryForObject(sqlCountRows, args, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Compute pages count
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
|
||||
List<E> result = jdbcTemplate.query(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlCountRows, final String sqlFetchRows, final Object[] args,
|
||||
final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Query the total number of current records
|
||||
Integer rowCountInt = jdbcTemplate.queryForObject(sqlCountRows, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Compute pages count
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
|
||||
List<E> result = jdbcTemplate.query(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page fetchPageLimit(MapperResult countMapperResult, MapperResult mapperResult, int pageNo, int pageSize,
|
||||
RowMapper rowMapper) {
|
||||
return fetchPageLimit(countMapperResult.getSql(), countMapperResult.getParamList().toArray(),
|
||||
mapperResult.getSql(), mapperResult.getParamList().toArray(), pageNo, pageSize, rowMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlCountRows, final Object[] args1, final String sqlFetchRows,
|
||||
final Object[] args2, final int pageNo, final int pageSize, final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Query the total number of current records
|
||||
Integer rowCountInt = jdbcTemplate.queryForObject(sqlCountRows, args1, Integer.class);
|
||||
if (rowCountInt == null) {
|
||||
throw new IllegalArgumentException("fetchPageLimit error");
|
||||
}
|
||||
|
||||
// Compute pages count
|
||||
int pageCount = rowCountInt / pageSize;
|
||||
if (rowCountInt > pageSize * pageCount) {
|
||||
pageCount++;
|
||||
}
|
||||
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
page.setPageNumber(pageNo);
|
||||
page.setPagesAvailable(pageCount);
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return page;
|
||||
}
|
||||
List<E> result = jdbcTemplate.query(sqlFetchRows, args2, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<E> fetchPageLimit(final String sqlFetchRows, final Object[] args, final int pageNo, final int pageSize,
|
||||
final RowMapper rowMapper) {
|
||||
if (pageNo <= 0 || pageSize <= 0) {
|
||||
throw new IllegalArgumentException("pageNo and pageSize must be greater than zero");
|
||||
}
|
||||
// Create Page object
|
||||
final Page<E> page = new Page<>();
|
||||
List<E> result = jdbcTemplate.query(sqlFetchRows, args, rowMapper);
|
||||
for (E item : result) {
|
||||
page.getPageItems().add(item);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLimit(final String sql, final Object[] args) {
|
||||
try {
|
||||
jdbcTemplate.update(sql, args);
|
||||
} finally {
|
||||
EmbeddedStorageContextHolder.cleanAllContext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update limit with response.
|
||||
*
|
||||
* @param sql sql
|
||||
* @param args args
|
||||
* @return update row count
|
||||
*/
|
||||
public int updateLimitWithResponse(final String sql, final Object[] args) {
|
||||
String sqlUpdate = sql;
|
||||
|
||||
try {
|
||||
return jdbcTemplate.update(sqlUpdate, args);
|
||||
} finally {
|
||||
EmbeddedStorageContextHolder.cleanAllContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* DataSource Connection CheckUtil.
|
||||
*
|
||||
* @author Long Yu
|
||||
*/
|
||||
public class ConnectionCheckUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionCheckUtil.class);
|
||||
|
||||
/**
|
||||
* check HikariDataSource connection ,avoid [no datasource set] text.
|
||||
*
|
||||
* @param ds HikariDataSource object
|
||||
*/
|
||||
public static void checkDataSourceConnection(HikariDataSource ds) {
|
||||
java.sql.Connection connection = null;
|
||||
try {
|
||||
connection = ds.getConnection();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.alibaba.nacos.persistence.constants.PersistenceConstant;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
|
||||
/**
|
||||
* get datasource platform util.
|
||||
*
|
||||
* @author lixiaoshuang
|
||||
*/
|
||||
public class DatasourcePlatformUtil {
|
||||
|
||||
/**
|
||||
* get datasource platform.
|
||||
*
|
||||
* @param defaultPlatform default platform.
|
||||
* @return
|
||||
*/
|
||||
public static String getDatasourcePlatform(String defaultPlatform) {
|
||||
String platform = EnvUtil.getProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY, defaultPlatform);
|
||||
if (StringUtils.isBlank(platform)) {
|
||||
platform = EnvUtil.getProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, defaultPlatform);
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Derby util.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public final class DerbyUtils {
|
||||
|
||||
private static final String INSERT_INTO_VALUES = "(INSERT INTO .+? VALUES)";
|
||||
|
||||
private static final Pattern INSERT_INTO_PATTERN = Pattern.compile(INSERT_INTO_VALUES);
|
||||
|
||||
/**
|
||||
* Because Derby's database table name is uppercase, you need to do a conversion to the insert statement that was
|
||||
* inserted.
|
||||
*
|
||||
* @param sql external database insert sql
|
||||
* @return derby insert sql
|
||||
*/
|
||||
public static String insertStatementCorrection(String sql) {
|
||||
Matcher matcher = INSERT_INTO_PATTERN.matcher(sql);
|
||||
if (!matcher.find()) {
|
||||
return sql;
|
||||
}
|
||||
final String target = matcher.group(0);
|
||||
final String upperCase = target.toUpperCase().replace("`", "");
|
||||
return sql.replaceFirst(INSERT_INTO_VALUES, upperCase).replace(";", "");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import com.alibaba.nacos.common.executor.ExecutorFactory;
|
||||
import com.alibaba.nacos.common.executor.NameThreadFactory;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Persistence async task executors.
|
||||
*
|
||||
* @author xiweng.yy
|
||||
*/
|
||||
public class PersistenceExecutor {
|
||||
|
||||
private static final ScheduledExecutorService TIMER_EXECUTOR = ExecutorFactory.Managed
|
||||
.newScheduledExecutorService(PersistenceExecutor.class.getCanonicalName(), 2,
|
||||
new NameThreadFactory("com.alibaba.nacos.persistence.timer"));
|
||||
|
||||
private static final Executor DUMP_EXECUTOR = ExecutorFactory.Managed
|
||||
.newSingleExecutorService(PersistenceExecutor.class.getCanonicalName(),
|
||||
new NameThreadFactory("com.alibaba.nacos.persistence.embedded.dump"));
|
||||
|
||||
private static final ExecutorService EMBEDDED_SNAPSHOT_EXECUTOR = ExecutorFactory.Managed
|
||||
.newSingleExecutorService(PersistenceExecutor.class.getCanonicalName(),
|
||||
new NameThreadFactory("com.alibaba.nacos.persistence.embedded.snapshot"));
|
||||
|
||||
public static void scheduleTask(Runnable command, long initialDelay, long delay, TimeUnit unit) {
|
||||
TIMER_EXECUTOR.scheduleWithFixedDelay(command, initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
public static void executeEmbeddedDump(Runnable runnable) {
|
||||
DUMP_EXECUTOR.execute(runnable);
|
||||
}
|
||||
|
||||
public static void executeSnapshot(Runnable runnable) {
|
||||
EMBEDDED_SNAPSHOT_EXECUTOR.execute(runnable);
|
||||
}
|
||||
}
|
||||
2
persistence/src/main/resources/META-INF/spring.factories
Normal file
2
persistence/src/main/resources/META-INF/spring.factories
Normal file
@ -0,0 +1,2 @@
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
com.alibaba.nacos.persistence.configuration.DatasourceConfiguration
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class ConditionDistributedEmbedStorageTest {
|
||||
|
||||
private ConditionDistributedEmbedStorage conditionDistributedEmbedStorage;
|
||||
|
||||
@Mock
|
||||
ConditionContext context;
|
||||
|
||||
@Mock
|
||||
AnnotatedTypeMetadata metadata;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
conditionDistributedEmbedStorage = new ConditionDistributedEmbedStorage();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() {
|
||||
MockedStatic<DatasourceConfiguration> propertyUtilMockedStatic = Mockito
|
||||
.mockStatic(DatasourceConfiguration.class);
|
||||
MockedStatic<EnvUtil> envUtilMockedStatic = Mockito.mockStatic(EnvUtil.class);
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(true);
|
||||
Assert.assertFalse(conditionDistributedEmbedStorage.matches(context, metadata));
|
||||
|
||||
Mockito.when(DatasourceConfiguration.isEmbeddedStorage()).thenReturn(true);
|
||||
Mockito.when(EnvUtil.getStandaloneMode()).thenReturn(false);
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(false);
|
||||
Assert.assertTrue(conditionDistributedEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(true);
|
||||
Assert.assertFalse(conditionDistributedEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(false);
|
||||
Assert.assertFalse(conditionDistributedEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.close();
|
||||
envUtilMockedStatic.close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class ConditionOnEmbeddedStorageTest {
|
||||
|
||||
private ConditionOnEmbeddedStorage conditionOnEmbeddedStorage;
|
||||
|
||||
@Mock
|
||||
ConditionContext context;
|
||||
|
||||
@Mock
|
||||
AnnotatedTypeMetadata metadata;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
conditionOnEmbeddedStorage = new ConditionOnEmbeddedStorage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() {
|
||||
MockedStatic<DatasourceConfiguration> mockedStatic = Mockito.mockStatic(DatasourceConfiguration.class);
|
||||
mockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
Assert.assertTrue(conditionOnEmbeddedStorage.matches(context, metadata));
|
||||
|
||||
mockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
Assert.assertFalse(conditionOnEmbeddedStorage.matches(context, metadata));
|
||||
|
||||
mockedStatic.close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class ConditionOnExternalStorageTest {
|
||||
|
||||
private ConditionOnExternalStorage conditionOnExternalStorage;
|
||||
|
||||
@Mock
|
||||
ConditionContext context;
|
||||
|
||||
@Mock
|
||||
AnnotatedTypeMetadata metadata;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
conditionOnExternalStorage = new ConditionOnExternalStorage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() {
|
||||
MockedStatic<DatasourceConfiguration> mockedStatic = Mockito.mockStatic(DatasourceConfiguration.class);
|
||||
|
||||
mockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
Assert.assertFalse(conditionOnExternalStorage.matches(context, metadata));
|
||||
|
||||
mockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
Assert.assertTrue(conditionOnExternalStorage.matches(context, metadata));
|
||||
|
||||
mockedStatic.close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.configuration.condition;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class ConditionStandaloneEmbedStorageTest {
|
||||
|
||||
private ConditionStandaloneEmbedStorage conditionStandaloneEmbedStorage;
|
||||
|
||||
@Mock
|
||||
ConditionContext context;
|
||||
|
||||
@Mock
|
||||
AnnotatedTypeMetadata metadata;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
conditionStandaloneEmbedStorage = new ConditionStandaloneEmbedStorage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() {
|
||||
MockedStatic<DatasourceConfiguration> propertyUtilMockedStatic = Mockito
|
||||
.mockStatic(DatasourceConfiguration.class);
|
||||
MockedStatic<EnvUtil> envUtilMockedStatic = Mockito.mockStatic(EnvUtil.class);
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(true);
|
||||
Assert.assertTrue(conditionStandaloneEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(true);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(false);
|
||||
Assert.assertFalse(conditionStandaloneEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(true);
|
||||
Assert.assertFalse(conditionStandaloneEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.when(DatasourceConfiguration::isEmbeddedStorage).thenReturn(false);
|
||||
envUtilMockedStatic.when(EnvUtil::getStandaloneMode).thenReturn(false);
|
||||
Assert.assertFalse(conditionStandaloneEmbedStorage.matches(context, metadata));
|
||||
|
||||
propertyUtilMockedStatic.close();
|
||||
envUtilMockedStatic.close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.persistence.constants.PersistenceConstant;
|
||||
import com.alibaba.nacos.sys.env.Constants;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* ClusterExternalStorage unit test.
|
||||
*
|
||||
* @author Long Yu
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class ClusterExternalStorageTest {
|
||||
|
||||
@InjectMocks
|
||||
private DynamicDataSource dataSource;
|
||||
|
||||
private MockEnvironment environment;
|
||||
|
||||
@Mock
|
||||
private LocalDataSourceServiceImpl localDataSourceService;
|
||||
|
||||
@Mock
|
||||
private ExternalDataSourceServiceImpl basicDataSourceService;
|
||||
|
||||
DatasourceConfiguration datasourceConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
environment = new MockEnvironment();
|
||||
EnvUtil.setEnvironment(environment);
|
||||
datasourceConfig = new DatasourceConfiguration();
|
||||
dataSource = DynamicDataSource.getInstance();
|
||||
ReflectionTestUtils.setField(dataSource, "localDataSourceService", localDataSourceService);
|
||||
ReflectionTestUtils.setField(dataSource, "basicDataSourceService", basicDataSourceService);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test005WithClusterAndNullDatabase() {
|
||||
// 模拟设置环境05:指定集群,未指定数据库,UseExternalDB是true,数据库类型是""
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "false");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
|
||||
// 模拟初始化
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertFalse(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(DatasourceConfiguration.isUseExternalDB());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test006WithClusterAndMysqlDatabase() {
|
||||
// 模拟设置环境06:指定集群,指定数据库mysql,UseExternalDB是true,数据库类型是mysql
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "false");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "mysql");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
|
||||
// 模拟初始化
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertFalse(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(DatasourceConfiguration.isUseExternalDB());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test007WithClusterAndDerbyDatabase() {
|
||||
// 模拟设置环境07:指定集群,指定数据库derby,UseExternalDB是false,数据库类型是derby
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "false");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "derby");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(true);
|
||||
|
||||
// 模拟初始化
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertFalse(EnvUtil.getStandaloneMode());
|
||||
Assert.assertFalse(DatasourceConfiguration.isUseExternalDB());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof LocalDataSourceServiceImpl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test008WithClusterAndOtherDatabase() {
|
||||
// 模拟设置环境08: 指定集群,指定数据库其他,UseExternalDB是true,数据库类型是其他
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "false");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "postgresql");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
|
||||
// 模拟初始化
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertFalse(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(DatasourceConfiguration.isUseExternalDB());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class DataSourcePoolPropertiesTest {
|
||||
|
||||
private static final String JDBC_URL = "jdbc:derby://127.0.0.1:3306/nacos_devtest?characterEncoding=utf8&serverTimezone=UTC";
|
||||
|
||||
private static final String JDBC_DRIVER_CLASS_NAME = "org.apache.derby.jdbc.EmbeddedDriver";
|
||||
|
||||
private static final String PASSWORD = "nacos";
|
||||
|
||||
private static final String USERNAME = "nacos_devtest";
|
||||
|
||||
private static final Long CONNECTION_TIMEOUT = 10000L;
|
||||
|
||||
private static final Integer MAX_POOL_SIZE = 50;
|
||||
|
||||
private MockEnvironment environment;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
environment = new MockEnvironment();
|
||||
environment.setProperty("db.user", USERNAME);
|
||||
environment.setProperty("db.password", PASSWORD);
|
||||
environment.setProperty("db.pool.config.connectionTimeout", CONNECTION_TIMEOUT.toString());
|
||||
environment.setProperty("db.pool.config.maximumPoolSize", MAX_POOL_SIZE.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuild() {
|
||||
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(environment);
|
||||
poolProperties.setJdbcUrl(JDBC_URL);
|
||||
poolProperties.setDriverClassName(JDBC_DRIVER_CLASS_NAME);
|
||||
poolProperties.setUsername(USERNAME);
|
||||
poolProperties.setPassword(PASSWORD);
|
||||
HikariDataSource actual = poolProperties.getDataSource();
|
||||
assertEquals(JDBC_URL, actual.getJdbcUrl());
|
||||
assertEquals(JDBC_DRIVER_CLASS_NAME, actual.getDriverClassName());
|
||||
assertEquals(USERNAME, actual.getUsername());
|
||||
assertEquals(PASSWORD, actual.getPassword());
|
||||
assertEquals(CONNECTION_TIMEOUT.longValue(), actual.getConnectionTimeout());
|
||||
assertEquals(DataSourcePoolProperties.DEFAULT_VALIDATION_TIMEOUT, actual.getValidationTimeout());
|
||||
assertEquals(DataSourcePoolProperties.DEFAULT_IDLE_TIMEOUT, actual.getIdleTimeout());
|
||||
assertEquals(MAX_POOL_SIZE.intValue(), actual.getMaximumPoolSize());
|
||||
assertEquals(DataSourcePoolProperties.DEFAULT_MINIMUM_IDLE, actual.getMinimumIdle());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DynamicDataSourceTest {
|
||||
|
||||
@InjectMocks
|
||||
private DynamicDataSource dataSource;
|
||||
|
||||
@Mock
|
||||
private LocalDataSourceServiceImpl localDataSourceService;
|
||||
|
||||
@Mock
|
||||
private ExternalDataSourceServiceImpl basicDataSourceService;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
dataSource = DynamicDataSource.getInstance();
|
||||
ReflectionTestUtils.setField(dataSource, "localDataSourceService", localDataSourceService);
|
||||
ReflectionTestUtils.setField(dataSource, "basicDataSourceService", basicDataSourceService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDataSource() {
|
||||
DatasourceConfiguration.setEmbeddedStorage(true);
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof LocalDataSourceServiceImpl);
|
||||
|
||||
DatasourceConfiguration.setEmbeddedStorage(false);
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExternalDataSourcePropertiesTest {
|
||||
|
||||
@SuppressWarnings("checkstyle:linelength")
|
||||
public static final String JDBC_URL = "jdbc:mysql://127.0.0.1:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC";
|
||||
|
||||
public static final String PASSWORD = "nacos";
|
||||
|
||||
public static final String USERNAME = "nacos_devtest";
|
||||
|
||||
@Test
|
||||
public void externalDatasourceNormally() {
|
||||
HikariDataSource expectedDataSource = new HikariDataSource();
|
||||
expectedDataSource.setJdbcUrl(JDBC_URL);
|
||||
expectedDataSource.setUsername(USERNAME);
|
||||
expectedDataSource.setPassword(PASSWORD);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("db.num", "1");
|
||||
environment.setProperty("db.user", USERNAME);
|
||||
environment.setProperty("db.password", PASSWORD);
|
||||
environment.setProperty("db.url.0", JDBC_URL);
|
||||
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
|
||||
Assert.assertEquals(dataSource.getJdbcUrl(), expectedDataSource.getJdbcUrl());
|
||||
Assert.assertEquals(dataSource.getUsername(), expectedDataSource.getUsername());
|
||||
Assert.assertEquals(dataSource.getPassword(), expectedDataSource.getPassword());
|
||||
|
||||
}));
|
||||
Assert.assertEquals(dataSources.size(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalDatasourceToAssertMultiJdbcUrl() {
|
||||
|
||||
HikariDataSource expectedDataSource = new HikariDataSource();
|
||||
expectedDataSource.setJdbcUrl(JDBC_URL);
|
||||
expectedDataSource.setUsername(USERNAME);
|
||||
expectedDataSource.setPassword(PASSWORD);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("db.num", "2");
|
||||
environment.setProperty("db.user", USERNAME);
|
||||
environment.setProperty("db.password", PASSWORD);
|
||||
environment.setProperty("db.url.0", JDBC_URL);
|
||||
environment.setProperty("db.url.1", JDBC_URL);
|
||||
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
|
||||
Assert.assertEquals(dataSource.getJdbcUrl(), expectedDataSource.getJdbcUrl());
|
||||
Assert.assertEquals(dataSource.getUsername(), expectedDataSource.getUsername());
|
||||
Assert.assertEquals(dataSource.getPassword(), expectedDataSource.getPassword());
|
||||
|
||||
}));
|
||||
Assert.assertEquals(dataSources.size(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalDatasourceToAssertMultiPasswordAndUsername() {
|
||||
|
||||
HikariDataSource expectedDataSource = new HikariDataSource();
|
||||
expectedDataSource.setJdbcUrl(JDBC_URL);
|
||||
expectedDataSource.setUsername(USERNAME);
|
||||
expectedDataSource.setPassword(PASSWORD);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("db.num", "2");
|
||||
environment.setProperty("db.user.0", USERNAME);
|
||||
environment.setProperty("db.user.1", USERNAME);
|
||||
environment.setProperty("db.password.0", PASSWORD);
|
||||
environment.setProperty("db.password.1", PASSWORD);
|
||||
environment.setProperty("db.url.0", JDBC_URL);
|
||||
environment.setProperty("db.url.1", JDBC_URL);
|
||||
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
|
||||
Assert.assertEquals(dataSource.getJdbcUrl(), expectedDataSource.getJdbcUrl());
|
||||
Assert.assertEquals(dataSource.getUsername(), expectedDataSource.getUsername());
|
||||
Assert.assertEquals(dataSource.getPassword(), expectedDataSource.getPassword());
|
||||
|
||||
}));
|
||||
Assert.assertEquals(dataSources.size(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalDatasourceToAssertMinIdle() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("db.num", "1");
|
||||
environment.setProperty("db.user", USERNAME);
|
||||
environment.setProperty("db.password", PASSWORD);
|
||||
environment.setProperty("db.url.0", JDBC_URL);
|
||||
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
|
||||
dataSource.validate();
|
||||
Assert.assertEquals(dataSource.getMinimumIdle(), DataSourcePoolProperties.DEFAULT_MINIMUM_IDLE);
|
||||
}));
|
||||
Assert.assertEquals(dataSources.size(), 1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void externalDatasourceFailureWithLarkInfo() {
|
||||
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
new ExternalDataSourceProperties().build(environment, null);
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void externalDatasourceFailureWithErrorInfo() {
|
||||
|
||||
HikariDataSource expectedDataSource = new HikariDataSource();
|
||||
expectedDataSource.setJdbcUrl(JDBC_URL);
|
||||
expectedDataSource.setUsername(USERNAME);
|
||||
expectedDataSource.setPassword(PASSWORD);
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
// error num of db
|
||||
environment.setProperty("db.num", "2");
|
||||
environment.setProperty("db.user", USERNAME);
|
||||
environment.setProperty("db.password", PASSWORD);
|
||||
environment.setProperty("db.url.0", JDBC_URL);
|
||||
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
|
||||
Assert.assertEquals(dataSource.getJdbcUrl(), expectedDataSource.getJdbcUrl());
|
||||
Assert.assertEquals(dataSource.getUsername(), expectedDataSource.getUsername());
|
||||
Assert.assertEquals(dataSource.getPassword(), expectedDataSource.getPassword());
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.UncategorizedSQLException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ExternalDataSourceServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private ExternalDataSourceServiceImpl service;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate jt;
|
||||
|
||||
@Mock
|
||||
private DataSourceTransactionManager tm;
|
||||
|
||||
@Mock
|
||||
private TransactionTemplate tjt;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate testMasterJT;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate testMasterWritableJT;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
service = new ExternalDataSourceServiceImpl();
|
||||
ReflectionTestUtils.setField(service, "jt", jt);
|
||||
ReflectionTestUtils.setField(service, "tm", tm);
|
||||
ReflectionTestUtils.setField(service, "tjt", tjt);
|
||||
ReflectionTestUtils.setField(service, "testMasterJT", testMasterJT);
|
||||
ReflectionTestUtils.setField(service, "testMasterWritableJT", testMasterWritableJT);
|
||||
List<HikariDataSource> dataSourceList = new ArrayList<>();
|
||||
dataSourceList.add(new HikariDataSource());
|
||||
ReflectionTestUtils.setField(service, "dataSourceList", dataSourceList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckMasterWritable() {
|
||||
|
||||
when(testMasterWritableJT.queryForObject(eq(" SELECT @@read_only "), eq(Integer.class))).thenReturn(0);
|
||||
Assert.assertTrue(service.checkMasterWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCurrentDbUrl() {
|
||||
|
||||
HikariDataSource bds = new HikariDataSource();
|
||||
bds.setJdbcUrl("test.jdbc.url");
|
||||
when(jt.getDataSource()).thenReturn(bds);
|
||||
|
||||
Assert.assertEquals("test.jdbc.url", service.getCurrentDbUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHealth() {
|
||||
|
||||
List<Boolean> isHealthList = new ArrayList<>();
|
||||
ReflectionTestUtils.setField(service, "isHealthList", isHealthList);
|
||||
Assert.assertEquals("UP", service.getHealth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDbHealthTaskRun() {
|
||||
|
||||
List<JdbcTemplate> testJtList = new ArrayList<>();
|
||||
testJtList.add(jt);
|
||||
ReflectionTestUtils.setField(service, "testJtList", testJtList);
|
||||
|
||||
List<Boolean> isHealthList = new ArrayList<>();
|
||||
isHealthList.add(Boolean.FALSE);
|
||||
ReflectionTestUtils.setField(service, "isHealthList", isHealthList);
|
||||
|
||||
service.new CheckDbHealthTask().run();
|
||||
Assert.assertEquals(1, isHealthList.size());
|
||||
Assert.assertTrue(isHealthList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDbHealthTaskRunWhenEmptyResult() {
|
||||
List<JdbcTemplate> testJtList = new ArrayList<>();
|
||||
testJtList.add(jt);
|
||||
ReflectionTestUtils.setField(service, "testJtList", testJtList);
|
||||
|
||||
List<Boolean> isHealthList = new ArrayList<>();
|
||||
isHealthList.add(Boolean.FALSE);
|
||||
ReflectionTestUtils.setField(service, "isHealthList", isHealthList);
|
||||
|
||||
when(jt.queryForMap(anyString())).thenThrow(new EmptyResultDataAccessException("Expected exception", 1));
|
||||
service.new CheckDbHealthTask().run();
|
||||
Assert.assertEquals(1, isHealthList.size());
|
||||
Assert.assertTrue(isHealthList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDbHealthTaskRunWhenSqlException() {
|
||||
List<JdbcTemplate> testJtList = new ArrayList<>();
|
||||
testJtList.add(jt);
|
||||
ReflectionTestUtils.setField(service, "testJtList", testJtList);
|
||||
|
||||
List<Boolean> isHealthList = new ArrayList<>();
|
||||
isHealthList.add(Boolean.FALSE);
|
||||
ReflectionTestUtils.setField(service, "isHealthList", isHealthList);
|
||||
|
||||
when(jt.queryForMap(anyString())).thenThrow(
|
||||
new UncategorizedSQLException("Expected exception", "", new SQLException()));
|
||||
service.new CheckDbHealthTask().run();
|
||||
Assert.assertEquals(1, isHealthList.size());
|
||||
Assert.assertFalse(isHealthList.get(0));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LocalDataSourceServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private LocalDataSourceServiceImpl service;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate jt;
|
||||
|
||||
@Mock
|
||||
private TransactionTemplate tjt;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
service = new LocalDataSourceServiceImpl();
|
||||
ReflectionTestUtils.setField(service, "jt", jt);
|
||||
ReflectionTestUtils.setField(service, "tjt", tjt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDataSource() {
|
||||
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl("test.jdbc.url");
|
||||
when(jt.getDataSource()).thenReturn(dataSource);
|
||||
Assert.assertEquals(dataSource.getJdbcUrl(), ((HikariDataSource) service.getDatasource()).getJdbcUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckMasterWritable() {
|
||||
|
||||
Assert.assertTrue(service.checkMasterWritable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAndGetHealth() {
|
||||
|
||||
service.setHealthStatus("DOWN");
|
||||
Assert.assertEquals("DOWN", service.getHealth());
|
||||
|
||||
service.setHealthStatus("UP");
|
||||
Assert.assertEquals("UP", service.getHealth());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.datasource;
|
||||
|
||||
import com.alibaba.nacos.persistence.configuration.DatasourceConfiguration;
|
||||
import com.alibaba.nacos.persistence.constants.PersistenceConstant;
|
||||
import com.alibaba.nacos.sys.env.Constants;
|
||||
import com.alibaba.nacos.sys.env.EnvUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* StandaloneExternalStorage unit test.
|
||||
*
|
||||
* @author Long Yu
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class StandaloneExternalStorageTest {
|
||||
|
||||
@InjectMocks
|
||||
private DynamicDataSource dataSource;
|
||||
|
||||
private MockEnvironment environment;
|
||||
|
||||
@Mock
|
||||
private LocalDataSourceServiceImpl localDataSourceService;
|
||||
|
||||
@Mock
|
||||
private ExternalDataSourceServiceImpl basicDataSourceService;
|
||||
|
||||
DatasourceConfiguration datasourceConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
environment = new MockEnvironment();
|
||||
EnvUtil.setEnvironment(environment);
|
||||
datasourceConfig = new DatasourceConfiguration();
|
||||
dataSource = DynamicDataSource.getInstance();
|
||||
ReflectionTestUtils.setField(dataSource, "localDataSourceService", localDataSourceService);
|
||||
ReflectionTestUtils.setField(dataSource, "basicDataSourceService", basicDataSourceService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test001WithStandaloneAndNullDatabase() {
|
||||
// 模拟设置环境01:指定单例,未指定数据库,UseExternalDB是false
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "true");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
|
||||
// 模拟初始化
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertTrue(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof LocalDataSourceServiceImpl);
|
||||
Assert.assertFalse(DatasourceConfiguration.isUseExternalDB());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test002WithStandaloneAndDerbyDatabase() {
|
||||
// 模拟设置环境02:指定单例,指定数据库derby,UseExternalDB是false
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "true");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "derby");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
// 模拟初始化
|
||||
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertTrue(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof LocalDataSourceServiceImpl);
|
||||
Assert.assertFalse(DatasourceConfiguration.isUseExternalDB());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test003WithStandaloneAndMysqlDatabase() {
|
||||
// 模拟设置环境03:指定单例,指定数据库为mysql, UseExternalDB是true
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "true");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "mysql");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
// 模拟初始化
|
||||
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertTrue(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
Assert.assertTrue(DatasourceConfiguration.isUseExternalDB());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test004WithStandaloneAndOtherDatabase() {
|
||||
// 模拟设置环境04:指定单例,指定数据库为其他, UseExternalDB是true
|
||||
System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "true");
|
||||
environment.setProperty(PersistenceConstant.DATASOURCE_PLATFORM_PROPERTY_OLD, "postgresql");
|
||||
EnvUtil.setIsStandalone(Boolean.getBoolean(Constants.STANDALONE_MODE_PROPERTY_NAME));
|
||||
DatasourceConfiguration.setEmbeddedStorage(EnvUtil.getStandaloneMode());
|
||||
// 模拟初始化
|
||||
|
||||
datasourceConfig.initialize(null);
|
||||
|
||||
Assert.assertTrue(EnvUtil.getStandaloneMode());
|
||||
Assert.assertTrue(dataSource.getDataSource() instanceof ExternalDataSourceServiceImpl);
|
||||
Assert.assertTrue(DatasourceConfiguration.isUseExternalDB());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.operate;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MockConfigInfo {
|
||||
|
||||
private long id;
|
||||
|
||||
private String dataId;
|
||||
|
||||
private String group;
|
||||
|
||||
private String content;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDataId() {
|
||||
return dataId;
|
||||
}
|
||||
|
||||
public void setDataId(String dataId) {
|
||||
this.dataId = dataId;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof MockConfigInfo)) {
|
||||
return false;
|
||||
}
|
||||
MockConfigInfo that = (MockConfigInfo) o;
|
||||
return id == that.id && Objects.equals(dataId, that.dataId) && Objects.equals(group, that.group) && Objects
|
||||
.equals(content, that.content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, dataId, group, content);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.repository.embedded.operate;
|
||||
|
||||
import com.alibaba.nacos.common.model.RestResult;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.EmbeddedStorageContextHolder;
|
||||
import com.alibaba.nacos.persistence.repository.embedded.sql.ModifyRequest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class StandaloneDatabaseOperateImplTest {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private StandaloneDatabaseOperateImpl operate;
|
||||
|
||||
@Mock
|
||||
private RowMapper<MockConfigInfo> rowMapper;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Mock
|
||||
private JdbcTemplate tempJdbcTemplate;
|
||||
|
||||
@Mock
|
||||
private BiConsumer<Boolean, Throwable> biConsumer;
|
||||
|
||||
/* @Mock
|
||||
private File file;
|
||||
*/
|
||||
@Mock
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
ReflectionTestUtils.setField(operate, "jdbcTemplate", jdbcTemplate);
|
||||
ReflectionTestUtils.setField(operate, "transactionTemplate", transactionTemplate);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne1() {
|
||||
String sql = "SELECT 1";
|
||||
Class<Long> clazz = Long.class;
|
||||
Long num = 1L;
|
||||
when(jdbcTemplate.queryForObject(sql, clazz)).thenReturn(num);
|
||||
Assert.assertEquals(operate.queryOne(sql, clazz), (Long) 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne2() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id = ? AND data_id = ? AND group_id = ?";
|
||||
MockConfigInfo configInfo = new MockConfigInfo();
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(jdbcTemplate.queryForObject(sql, args, MockConfigInfo.class)).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(sql, args, MockConfigInfo.class), configInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne3() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id = ? AND data_id = ? AND group_id = ?";
|
||||
MockConfigInfo configInfo = new MockConfigInfo();
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(jdbcTemplate.queryForObject(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(sql, args, rowMapper), configInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne4() {
|
||||
String sql = "SELECT 1";
|
||||
Class<Long> clazz = Long.class;
|
||||
Long result = 1L;
|
||||
when(tempJdbcTemplate.queryForObject(sql, clazz)).thenReturn(result);
|
||||
Assert.assertEquals(operate.queryOne(tempJdbcTemplate, sql, clazz), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne5() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id = ? AND data_id = ? AND group_id = ?";
|
||||
MockConfigInfo configInfo = new MockConfigInfo();
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(tempJdbcTemplate.queryForObject(sql, args, MockConfigInfo.class)).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(tempJdbcTemplate, sql, args, MockConfigInfo.class), configInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOne6() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id = ? AND data_id = ? AND group_id = ?";
|
||||
MockConfigInfo configInfo = new MockConfigInfo();
|
||||
configInfo.setId(1L);
|
||||
configInfo.setDataId("test");
|
||||
configInfo.setGroup("test");
|
||||
Object[] args = new Object[] {configInfo.getId(), configInfo.getDataId(), configInfo.getGroup()};
|
||||
when(tempJdbcTemplate.queryForObject(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfo);
|
||||
Assert.assertEquals(operate.queryOne(tempJdbcTemplate, sql, args, rowMapper), configInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany1() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
MockConfigInfo configInfo1 = new MockConfigInfo();
|
||||
configInfo1.setId(1);
|
||||
MockConfigInfo configInfo2 = new MockConfigInfo();
|
||||
configInfo2.setId(2);
|
||||
List<MockConfigInfo> configInfos = new ArrayList<>();
|
||||
configInfos.add(configInfo1);
|
||||
configInfos.add(configInfo2);
|
||||
when(jdbcTemplate.query(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfos);
|
||||
Assert.assertEquals(configInfos, operate.queryMany(sql, args, rowMapper));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany2() {
|
||||
final String sql = "SELECT id, data_id, group_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
|
||||
final List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
Map<String, Object> map1 = new HashMap<>();
|
||||
map1.put("id", 1);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
final Map<String, Object> map2 = new HashMap<>();
|
||||
map1.put("id", 2);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
resultList.add(map1);
|
||||
resultList.add(map2);
|
||||
|
||||
when(jdbcTemplate.queryForList(sql, args)).thenReturn(resultList);
|
||||
Assert.assertEquals(operate.queryMany(sql, args), resultList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany3() {
|
||||
String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
Object[] args = new Object[] {1, 2};
|
||||
String dataId1 = "test1";
|
||||
String dataId2 = "test2";
|
||||
List<String> resultList = new ArrayList<>();
|
||||
resultList.add(dataId1);
|
||||
resultList.add(dataId2);
|
||||
Class clazz = dataId1.getClass();
|
||||
when(jdbcTemplate.queryForList(sql, args, clazz)).thenReturn(resultList);
|
||||
Assert.assertEquals(operate.queryMany(sql, args, clazz), resultList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany4() {
|
||||
final String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
final List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
Map<String, Object> map1 = new HashMap<>();
|
||||
map1.put("id", 1);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
final Map<String, Object> map2 = new HashMap<>();
|
||||
map1.put("id", 2);
|
||||
map1.put("data_id", "test");
|
||||
map1.put("group_id", "test");
|
||||
|
||||
resultList.add(map1);
|
||||
resultList.add(map2);
|
||||
|
||||
when(tempJdbcTemplate.queryForList(sql, args)).thenReturn(resultList);
|
||||
Assert.assertEquals(operate.queryMany(tempJdbcTemplate, sql, args), resultList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany5() {
|
||||
String sql = "SELECT data_id FROM config_info WHERE id >= ? AND id <= ?";
|
||||
Object[] args = new Object[] {1, 2};
|
||||
String dataId1 = "test1";
|
||||
String dataId2 = "test2";
|
||||
List<String> resultList = new ArrayList<>();
|
||||
resultList.add(dataId1);
|
||||
resultList.add(dataId2);
|
||||
Class clazz = dataId1.getClass();
|
||||
when(operate.queryMany(jdbcTemplate, sql, args, clazz)).thenReturn(resultList);
|
||||
Assert.assertEquals(operate.queryMany(jdbcTemplate, sql, args, clazz), resultList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMany6() {
|
||||
final String sql = "SELECT * FROM config_info WHERE id >= ? AND id <= ?";
|
||||
final Object[] args = new Object[] {1, 2};
|
||||
MockConfigInfo configInfo1 = new MockConfigInfo();
|
||||
configInfo1.setId(1);
|
||||
MockConfigInfo configInfo2 = new MockConfigInfo();
|
||||
configInfo2.setId(2);
|
||||
List<MockConfigInfo> configInfos = new ArrayList<>();
|
||||
configInfos.add(configInfo1);
|
||||
configInfos.add(configInfo2);
|
||||
when(tempJdbcTemplate.query(eq(sql), eq(args), any(RowMapper.class))).thenReturn(configInfos);
|
||||
Assert.assertEquals(operate.queryMany(tempJdbcTemplate, sql, args, rowMapper), configInfos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataImport() throws ExecutionException, InterruptedException {
|
||||
RestResult<String> errorResult = RestResult.<String>builder().withCode(500).withMsg("null").withData(null)
|
||||
.build();
|
||||
CompletableFuture<RestResult<String>> errorFuture = new CompletableFuture<>();
|
||||
errorFuture.complete(errorResult);
|
||||
doReturn(errorFuture).when(operate).dataImport(null);
|
||||
Assert.assertEquals(operate.dataImport(null).get(), errorResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate1() {
|
||||
List<ModifyRequest> modifyRequests = new ArrayList<>();
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.update(modifyRequests));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate2() {
|
||||
List<ModifyRequest> modifyRequests = new ArrayList<>();
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.update(modifyRequests, biConsumer));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate3() {
|
||||
List<ModifyRequest> modifyRequests = new ArrayList<>();
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.update(transactionTemplate, jdbcTemplate, modifyRequests));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate4() {
|
||||
List<ModifyRequest> modifyRequests = new ArrayList<>();
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.update(transactionTemplate, jdbcTemplate, modifyRequests, biConsumer));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockUpdate1() {
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = 1;";
|
||||
EmbeddedStorageContextHolder.addSqlContext(sql);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.blockUpdate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockUpdate2() {
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = 1;";
|
||||
EmbeddedStorageContextHolder.addSqlContext(sql);
|
||||
when(transactionTemplate.execute(any(TransactionCallback.class))).thenReturn(true);
|
||||
Assert.assertTrue(operate.blockUpdate(biConsumer));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoDataImport() {
|
||||
List<ModifyRequest> modifyRequests = new ArrayList<>();
|
||||
ModifyRequest modifyRequest1 = new ModifyRequest();
|
||||
String sql = "UPDATE config_info SET data_id = 'test' WHERE id = ?;";
|
||||
modifyRequest1.setSql(sql);
|
||||
Object[] args = new Object[] {1};
|
||||
modifyRequest1.setArgs(args);
|
||||
modifyRequests.add(modifyRequest1);
|
||||
when(tempJdbcTemplate.batchUpdate(sql)).thenReturn(new int[] {1});
|
||||
Assert.assertTrue(operate.doDataImport(tempJdbcTemplate, modifyRequests));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFutureUpdate() throws ExecutionException, InterruptedException {
|
||||
String sql = "SELECT 1";
|
||||
EmbeddedStorageContextHolder.addSqlContext(sql);
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
future.complete(true);
|
||||
doAnswer((invocationOnMock) -> null).when(operate).futureUpdate();
|
||||
when(operate.futureUpdate()).thenReturn(future);
|
||||
Assert.assertTrue(operate.futureUpdate().get());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* DataSource Connection CheckUtil Unit Test.
|
||||
*
|
||||
* @author Long Yu
|
||||
*/
|
||||
public class ConnectionCheckUtilTest {
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testCheckConnectionThrowException() throws SQLException {
|
||||
HikariDataSource ds = mock(HikariDataSource.class);
|
||||
when(ds.getConnection()).thenThrow(new RuntimeException());
|
||||
ConnectionCheckUtil.checkDataSourceConnection(ds);
|
||||
verify(ds).getConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckConnectionNormal() throws SQLException {
|
||||
HikariDataSource ds = mock(HikariDataSource.class);
|
||||
Connection connection = mock(Connection.class);
|
||||
when(ds.getConnection()).thenReturn(connection);
|
||||
ConnectionCheckUtil.checkDataSourceConnection(ds);
|
||||
verify(ds).getConnection();
|
||||
verify(connection).close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@SuppressWarnings("checkstyle:linelength")
|
||||
public class DerbyUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testDerbySqlCorrect() {
|
||||
final String testSql = "INSERT INTO `config_info` (`id`, `data_id`, `group_id`, `content`, `md5`, `gmt_create`, `gmt_modified`, `src_user`, `src_ip`, `app_name`, `tenant_id`, `c_desc`, `c_use`, `effect`, `type`, `c_schema`) VALUES (1,'boot-test','ALIBABA','dept:123123123\\ngroup:123123123','2ca50d002a7dabf81497f666a7967e15','2020-04-13 13:44:43','2020-04-30 10:45:21',NULL,'127.0.0.1','','',NULL,NULL,NULL,NULL,NULL);";
|
||||
final String result = DerbyUtils.insertStatementCorrection(testSql);
|
||||
|
||||
final String expect = "INSERT INTO CONFIG_INFO (ID, DATA_ID, GROUP_ID, CONTENT, MD5, GMT_CREATE, GMT_MODIFIED, SRC_USER, SRC_IP, APP_NAME, TENANT_ID, C_DESC, C_USE, EFFECT, TYPE, C_SCHEMA) VALUES (1,'boot-test','ALIBABA','dept:123123123\\ngroup:123123123','2ca50d002a7dabf81497f666a7967e15','2020-04-13 13:44:43','2020-04-30 10:45:21',NULL,'127.0.0.1','','',NULL,NULL,NULL,NULL,NULL)";
|
||||
Assert.assertEquals(expect, result);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.persistence.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PersistenceExecutorTest {
|
||||
|
||||
@Test
|
||||
public void testExecuteEmbeddedDump() throws InterruptedException {
|
||||
|
||||
AtomicInteger atomicInteger = new AtomicInteger();
|
||||
|
||||
Runnable runnable = atomicInteger::incrementAndGet;
|
||||
|
||||
PersistenceExecutor.executeEmbeddedDump(runnable);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(20);
|
||||
|
||||
Assert.assertEquals(1, atomicInteger.get());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
15
persistence/src/test/resources/application.properties
Normal file
15
persistence/src/test/resources/application.properties
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright 1999-2023 Alibaba Group Holding Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
Reference in New Issue
Block a user