diff --git a/ruoyi-visual/ruoyi-seata-server/pom.xml b/ruoyi-visual/ruoyi-seata-server/pom.xml index 2a3e5db0..cff7c244 100644 --- a/ruoyi-visual/ruoyi-seata-server/pom.xml +++ b/ruoyi-visual/ruoyi-seata-server/pom.xml @@ -219,8 +219,9 @@ HikariCP - com.mysql - mysql-connector-j + mysql + mysql-connector-java + 8.0.27 org.postgresql diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java new file mode 100644 index 00000000..4603d2cb --- /dev/null +++ b/ruoyi-visual/ruoyi-seata-server/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.seata.core.store.db; + +import org.apache.seata.common.exception.StoreException; +import org.apache.seata.common.executor.Initialize; +import org.apache.seata.common.util.ConfigTools; +import org.apache.seata.common.util.StringUtils; +import org.apache.seata.config.Configuration; +import org.apache.seata.config.ConfigurationFactory; +import org.apache.seata.core.constants.ConfigurationKeys; +import org.apache.seata.core.constants.DBType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MAX_CONN; +import static org.apache.seata.common.DefaultValues.DEFAULT_DB_MIN_CONN; + +/** + * The abstract datasource provider + * + */ +public abstract class AbstractDataSourceProvider implements DataSourceProvider, Initialize { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDataSourceProvider.class); + + private DataSource dataSource; + + /** + * The constant CONFIG. + */ + protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); + + private final static String MYSQL_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; + + private final static String MYSQL8_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver"; + + private final static String MYSQL_DRIVER_FILE_PREFIX = "mysql-connector-java-"; + + private final static Map MYSQL_DRIVER_LOADERS; + + private static final long DEFAULT_DB_MAX_WAIT = 5000; + + static { + MYSQL_DRIVER_LOADERS = createMysqlDriverClassLoaders(); + } + + @Override + public void init() { + this.dataSource = generate(); + } + + @Override + public DataSource provide() { + return this.dataSource; + } + + public DataSource generate() { + validate(); + return doGenerate(); + } + + public void validate() { + //valid driver class name + String driverClassName = getDriverClassName(); +// ClassLoader loader = getDriverClassLoader(); +// if (null == loader) { +// throw new StoreException("class loader set error, you should not use the Bootstrap classloader"); +// } + try { +// loader.loadClass(driverClassName); + Class.forName(driverClassName); + } catch (ClassNotFoundException exx) { + String driverClassPath = null; + String folderPath = System.getProperty("loader.path"); + if (null != folderPath) { + driverClassPath = folderPath + "/jdbc/"; + } + throw new StoreException(String.format( + "The driver {%s} cannot be found in the path %s. Please ensure that the appropriate database driver dependencies are included in the classpath.", driverClassName, driverClassPath)); + } + + } + /** + * generate the datasource + * @return datasource + */ + public abstract DataSource doGenerate(); + + /** + * Get db type db type. + * + * @return the db type + */ + protected DBType getDBType() { + return DBType.valueof(CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE)); + } + + /** + * get db driver class name + * + * @return the db driver class name + */ + protected String getDriverClassName() { + String driverClassName = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DRIVER_CLASS_NAME); + if (StringUtils.isBlank(driverClassName)) { + throw new StoreException( + String.format("the {%s} can't be empty", ConfigurationKeys.STORE_DB_DRIVER_CLASS_NAME)); + } + return driverClassName; + } + + /** + * get db max wait + * + * @return the db max wait + */ + protected Long getMaxWait() { + Long maxWait = CONFIG.getLong(ConfigurationKeys.STORE_DB_MAX_WAIT, DEFAULT_DB_MAX_WAIT); + return maxWait; + } + + protected ClassLoader getDriverClassLoader() { + return MYSQL_DRIVER_LOADERS.getOrDefault(getDriverClassName(), ClassLoader.getSystemClassLoader()); + } + + private static Map createMysqlDriverClassLoaders() { + Map loaders = new HashMap<>(); + String cp = System.getProperty("java.class.path"); + if (cp == null || cp.isEmpty()) { + return loaders; + } + Stream.of(cp.split(File.pathSeparator)) + .map(File::new) + .filter(File::exists) + .map(file -> file.isFile() ? file.getParentFile() : file) + .filter(Objects::nonNull) + .filter(File::isDirectory) + .map(file -> new File(file, "jdbc")) + .filter(File::exists) + .filter(File::isDirectory) + .distinct() + .flatMap(file -> { + File[] files = file.listFiles((f, name) -> name.startsWith(MYSQL_DRIVER_FILE_PREFIX)); + if (files != null) { + return Stream.of(files); + } else { + return Stream.of(); + } + }) + .forEach(file -> { + if (loaders.containsKey(MYSQL8_DRIVER_CLASS_NAME) && loaders.containsKey(MYSQL_DRIVER_CLASS_NAME)) { + return; + } + try { + URL url = file.toURI().toURL(); + ClassLoader loader = new URLClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader()); + try { + loader.loadClass(MYSQL8_DRIVER_CLASS_NAME); + loaders.putIfAbsent(MYSQL8_DRIVER_CLASS_NAME, loader); + } catch (ClassNotFoundException e) { + loaders.putIfAbsent(MYSQL_DRIVER_CLASS_NAME, loader); + } + } catch (MalformedURLException ignore) { + } + }); + return loaders; + } + + /** + * Get url string. + * + * @return the string + */ + protected String getUrl() { + String url = CONFIG.getConfig(ConfigurationKeys.STORE_DB_URL); + if (StringUtils.isBlank(url)) { + throw new StoreException(String.format("the {%s} can't be empty", ConfigurationKeys.STORE_DB_URL)); + } + return url; + } + + /** + * Get user string. + * + * @return the string + */ + protected String getUser() { + String user = CONFIG.getConfig(ConfigurationKeys.STORE_DB_USER); + if (StringUtils.isBlank(user)) { + throw new StoreException(String.format("the {%s} can't be empty", ConfigurationKeys.STORE_DB_USER)); + } + return user; + } + + /** + * Get password string. + * + * @return the string + */ + protected String getPassword() { + String password = CONFIG.getConfig(ConfigurationKeys.STORE_DB_PASSWORD); + String publicKey = getPublicKey(); + if (StringUtils.isNotBlank(publicKey)) { + try { + password = ConfigTools.publicDecrypt(password, publicKey); + } catch (Exception e) { + LOGGER.error( + "decryption failed,please confirm whether the ciphertext and secret key are correct! error msg: {}", + e.getMessage()); + } + } + return password; + } + + /** + * Get min conn int. + * + * @return the int + */ + protected int getMinConn() { + int minConn = CONFIG.getInt(ConfigurationKeys.STORE_DB_MIN_CONN, DEFAULT_DB_MIN_CONN); + return minConn < 0 ? DEFAULT_DB_MIN_CONN : minConn; + } + + /** + * Get max conn int. + * + * @return the int + */ + protected int getMaxConn() { + int maxConn = CONFIG.getInt(ConfigurationKeys.STORE_DB_MAX_CONN, DEFAULT_DB_MAX_CONN); + return maxConn < 0 ? DEFAULT_DB_MAX_CONN : maxConn; + } + + /** + * Get validation query string. + * + * @param dbType the db type + * @return the string + */ + protected String getValidationQuery(DBType dbType) { + if (DBType.ORACLE.equals(dbType)) { + return "select sysdate from dual"; + } else { + return "select 1"; + } + } + + /** + * Get public key. + * + * @return the string + */ + protected String getPublicKey() { + return CONFIG.getConfig(ConfigurationKeys.STORE_PUBLIC_KEY); + } + +}