1. 程式人生 > >Spring-基於Spring的多資料來源切換

Spring-基於Spring的多資料來源切換

實現思路

重寫Spring的AbstractRoutingDataSource抽象類的determineCurrentLookupKey方法。

我們來看下Spring-AbstractRoutingDataSource的原始碼

這裡寫圖片描述

AbstractRoutingDataSource獲取資料來源之前會先呼叫determineCurrentLookupKey方法查詢當前的lookupKey。

Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get
(lookupKey); ....... return dataSource;

lookupKey為資料來源標識,因此通過重寫這個查詢資料來源標識的方法就可以讓spring切換到指定的資料來源.

從變數定義中可以知道resolvedDataSources為Map型別的物件。

private Map<Object, DataSource> resolvedDataSources; 

例項

這裡寫圖片描述

步驟一 新建Maven工程

pom.xml

<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">
<modelVersion>4.0.0</modelVersion> <groupId>com.ztesoft</groupId> <artifactId>backupOracle</artifactId> <version>
0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>backupOracle</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <file.encoding>UTF-8</file.encoding> <spring.version>4.3.9.RELEASE</spring.version> <servlet.version>3.1.0</servlet.version> <aspectj.version>1.8.1</aspectj.version> <commons-dbcp.version>1.4</commons-dbcp.version> <jetty.version>8.1.8.v20121106</jetty.version> <log4j.version>1.2.17</log4j.version> <log4j2.version>2.8.2</log4j2.version> <testng.version>6.8.7</testng.version> <oracle.version>11.2.0.4.0</oracle.version> <jstl.version>1.2</jstl.version> </properties> <dependencies> <!-- spring 依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>${commons-dbcp.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- oracle jdbc driver --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>${oracle.version}</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j2.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j2.version}</version> </dependency> </dependencies> <build> <!-- 使用JDK1.7編譯 --> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>

步驟二 繼承AbstractRoutingDataSource並重寫determineCurrentLookupKey方法獲取特定資料來源

package com.ztesoft.backupOracle.dynamicDB;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 
 * 
 * @ClassName: DynamicDataSource
 * 
 * @Description: 
 *               AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是實現資料來源的route的核心
 *               .需要重寫該方法
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月24日 下午8:28:46
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSource();
    }
}

步驟三 建立DynamicDataSourceHolder用於持有當前執行緒中使用的資料來源標識

package com.ztesoft.backupOracle.dynamicDB;

/**
 * 
 * 
 * @ClassName: DynamicDataSourceHolder
 * 
 * @Description:建立DynamicDataSourceHolder用於持有當前執行緒中使用的資料來源標識
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月24日 下午8:23:50
 */
public class DynamicDataSourceHolder {

    /**
     * 資料來源標識儲存線上程變數中,避免多執行緒操作資料來源時互相干擾
     */
    private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<String>();

    /**
     * 
     * 
     * @Title: setDataSource
     * 
     * @Description: 設定資料來源
     * 
     * @param dataSource
     * 
     * @return: void
     */
    public static void setDataSource(String dataSource) {
        dataSourceHolder.set(dataSource);
    }

    /**
     * 
     * 
     * @Title: getDataSource
     * 
     * @Description: 獲取資料來源
     * 
     * @return
     * 
     * @return: String
     */
    public static String getDataSource() {
        return dataSourceHolder.get();
    }

    /**
     * 
     * 
     * @Title: clearDataSource
     * 
     * @Description: 清除資料來源
     * 
     * 
     * @return: void
     */
    public static void clearDataSource() {
        dataSourceHolder.remove();
    }
}

步驟四 配置多個數據源和DynamicDataSource的bean

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 基類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入 -->
    <context:component-scan base-package="com.ztesoft.backupOracle"/>

    <!-- 使用context名稱空間,在xml檔案中配置資料庫的properties檔案  -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置資料來源-->  

    <!-- 主站點的資料來源 -->
    <bean id="dataSourcePR" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassNamePR}"
        p:url="${jdbc.urlPR}"
        p:username="${jdbc.usernamePR}"
        p:password="${jdbc.passwordPR}" />

    <!-- 備用站點的資料來源 -->
    <bean id="dataSourceDR" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassNameDR}"
        p:url="${jdbc.urlDR}"
        p:username="${jdbc.usernameDR}"
        p:password="${jdbc.passwordDR}" /> 

    <!-- 主站點cc例項資料來源 -->
    <bean id="dataSourceCC" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassNameCC}"
        p:url="${jdbc.urlCC}"
        p:username="${jdbc.usernameCC}"
        p:password="${jdbc.passwordCC}" />


    <bean id="dynamicDataSource" class="com.ztesoft.backupOracle.dynamicDB.DynamicDataSource">
        <property name="targetDataSources" ref="dynamicDatasourceMap" />
        <!-- 預設資料來源 -->
        <property name="defaultTargetDataSource" ref="dataSourcePR" />
    </bean>

    <!-- 指定lookupKey和與之對應的資料來源 -->
    <util:map id="dynamicDatasourceMap" key-type="java.lang.String">
        <entry key="dataSourcePR" value-ref="dataSourcePR" />
        <entry key="dataSourceDR" value-ref="dataSourceDR" />
        <entry key="dataSourceCC" value-ref="dataSourceCC" />
    </util:map>


    <!-- 配置Jdbc模板  JdbcTemplate使用動態資料來源的配置  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dynamicDataSource" />

    <!-- 配置資料來源註解的攔截規則,比如攔截service層或者dao層的所有方法,這裡攔截了com.ztesoft.backupOracle下的全部方法 -->   
     <bean id="dataSourceAspect" class="com.ztesoft.backupOracle.dynamicDB.DataSourceAspect" />
     <aop:config>
         <aop:aspect ref="dataSourceAspect">
             <!-- 攔截所有XXX方法 -->
             <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ztesoft.backupOracle..*(..))"/>
             <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
         </aop:aspect>
     </aop:config>

    <!-- 配置事務管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dynamicDataSource" />

    <!-- 通過AOP配置提供事務增強,讓com.ztesoft.backupOracle包下所有Bean的所有方法擁有事務 -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="serviceMethod"
            expression="(execution(* com.ztesoft.backupOracle..*(..))) and (@annotation(org.springframework.transaction.annotation.Transactional))" />
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
</beans>

配置到這裡,我們就可以使用多個數據源了,只需要在操作資料庫之前只要DynamicDataSourceHolder.setDataSource(“dataSourcePR”)即可切換到資料來源dataSourcePR並對資料庫dataSourcePR進行操作了。

問題:每次使用都需要呼叫DynamicDataSourceHolder#setDataSource,十分繁瑣,並且難以維護。

我們可以通過Spring的AOP和註解, 直接通過註解的方式指定需要訪問的資料來源。

步驟五 定義名為@DataSource的註解

package com.ztesoft.backupOracle.dynamicDB;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 * 
 * @ClassName: DataSource 
 * 
 * 
 * @Description: 註解@DataSource既可以加在方法上,也可以加在介面或者介面的實現類上,優先級別:方法>實現類>介面。
 *               如果介面、介面實現類以及方法上分別加了@DataSource註解來指定資料來源,則優先以方法上指定的為準。
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月24日 下午9:59:29
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    // 和配置檔案中 dynamicDatasourceMap中的key保持一致
    public static String PR_RB = "dataSourcePR";

    public static String DR_RB = "dataSourceDR";

    public static String PR_CC = "dataSourceCC";

    /**
     * 
     * 
     * @Title: name
     * 
     * @Description: 如果僅標註@DataSource 預設為PR_RB資料庫例項
     * 
     * @return
     * 
     * @return: String
     */
    String name() default DataSource.PR_RB;

}

步驟六 定義AOP切面以便攔截所有帶有註解@DataSource的方法,取出註解的值作為資料來源標識放到DynamicDataSourceHolder的執行緒變數中

package com.ztesoft.backupOracle.dynamicDB;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * 
 * 
 * @ClassName: DataSourceAspect
 * 
 * @Description: 
 *               定義AOP切面以便攔截所有帶有註解@DataSource的方法,取出註解的值作為資料來源標識放到DBContextHolder的執行緒變數中
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月25日 上午10:51:41
 */
public class DataSourceAspect {

    /**
     * 
     * 
     * @Title: intercept
     * 
     * @Description: 攔截目標方法,獲取由@DataSource指定的資料來源標識,設定到執行緒儲存中以便切換資料來源
     * 
     * @param point
     * @throws Exception
     * 
     * @return: void
     */
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 預設使用目標型別的註解,如果沒有則使用其實現介面的註解
        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }

    /**
     * 
     * 
     * @Title: resolveDataSource
     * 
     * @Description: 提取目標物件方法註解和型別註解中的資料來源標識
     * 
     * @param clazz
     * @param method
     * 
     * @return: void
     */
    private void resolveDataSource(Class<?> clazz, Method method) {
        try {
            Class<?>[] types = method.getParameterTypes();
            // 預設使用型別註解
            if (clazz.isAnnotationPresent(DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.name());
            }
            // 方法註解可以覆蓋型別註解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.name());
            }
        } catch (Exception e) {
            System.out.println(clazz + ":" + e.getMessage());
        }
    }
}

步驟七 在spring配置檔案中配置攔截規則

    <!-- 配置資料來源註解的攔截規則,比如攔截service層或者dao層的所有方法,這裡攔截了com.ztesoft.backupOracle下的全部方法 -->   
     <bean id="dataSourceAspect" class="com.ztesoft.backupOracle.dynamicDB.DataSourceAspect" />
     <aop:config>
         <aop:aspect ref="dataSourceAspect">
             <!-- 攔截所有XXX方法 -->
             <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ztesoft.backupOracle..*(..))"/>
             <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
         </aop:aspect>
     </aop:config>

使用註解切換多資料來源

package com.ztesoft.backupOracle;

import java.io.IOException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import com.ztesoft.backupOracle.extractService.ExtractDataService;

/**
 * 
 * 
 * @ClassName: App
 * 
 * @Description: 入口類
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月24日 下午8:50:25
 */
public class App {
    public static void main(String[] args) {
        try {
            // 載入日誌框架 log4j2
            LoggerContext context = (LoggerContext) LogManager
                    .getContext(false);
            ResourceLoader loader = new PathMatchingResourcePatternResolver();
            Resource resource = loader.getResource("classpath:log4j2.xml");

            context.setConfigLocation(resource.getFile().toURI());

            // 載入spring配置資訊
            ApplicationContext ctx = new ClassPathXmlApplicationContext(
                    "classpath:spring-context.xml");
            // 從容器中獲取Bean
            ExtractDataService service = ctx.getBean("extractDataService",
                    ExtractDataService.class);
            // 從PR的RB例項中獲取資料
            service.selectDataFromPR_RB();
            // 從DR的RB例項中獲取資料
            service.selectDataFromDR_RB();
            // 從PR的CC例項中獲取資料
            service.selectDataFromPR_CC();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

附屬檔案

ExtractDataService.java

package com.ztesoft.backupOracle.extractService;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Service;

import com.ztesoft.backupOracle.dynamicDB.DataSource;

/**
 * 
 * 
 * @ClassName: ExtractDataService
 * 
 * @Description: 業務類,這裡暫時作為測試多資料來源切換用
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年7月24日 下午9:07:38
 */

@Service
public class ExtractDataService {

    private static final Logger logger = LogManager
            .getLogger(ExtractDataService.class.getName());

    private JdbcTemplate jdbcTemplate;

    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 
     * 
     * @Title: selectDataFromPR
     * 
     * @Description:
     * 
     * 
     * @return: void
     */
    @DataSource(name = DataSource.PR_RB)
    public void selectDataFromPR_RB() {
        String sql = "select  subs_id from owe_event_charge  where event_inst_id = 10229001 ";

        jdbcTemplate.query(sql, new RowCallbackHandler() {

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                logger.info(rs.getInt("subs_id"));
            }
        });
    }

    @DataSource(name = DataSource.DR_RB)
    public void selectDataFromDR_RB() {
        // 改為通過註解指定DB
        // DynamicDataSourceHolder.setDataSource(DBContextHolder.DATA_SOURCE_DR);
        String sql = " select  a.task_comments  from nm_task_type a  where a.task_name = 'ALARM_LOG_LEVEL' ";
        jdbcTemplate.query(sql, new RowCallbackHandler() {

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                logger.info(rs.getString("task_comments"));
            }
        });
    }

    @DataSource(name = DataSource.PR_CC)
    public void selectDataFromPR_CC() {
        // DBContextHolder.setDataSource(DBContextHolder.DATA_SOURCE_CC);
        String sql = "select  acc_nbr  from acc_nbr  where  acc_nbr_id = 82233858 ";
        jdbcTemplate.query(sql, new RowCallbackHandler() {

            @Override
            public void processRow(ResultSet rs) throws SQLException {
                logger.info(rs.getString("acc_nbr"));
            }
        });

    }
}

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- log4j2使用說明:
使用方式如下:
private static final Logger logger = LogManager.getLogger(實際類名.class.getName());
-->

<!--日誌級別以及優先順序排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration後面的status,這個用於設定log4j2自身內部的資訊輸出,可以不設定,當設定成trace時,你會看到log4j2內部各種詳細輸出-->
<!--monitorInterval:Log4j能夠自動檢測修改配置 檔案和重新配置本身,設定間隔秒數-->
<configuration status="info" monitorInterval="180">

    <!-- 檔案路徑和檔名稱,方便後面引用 -->
    <Properties>
        <Property name="backupFilePatch">D:/workspace/workspace-sts/backupOracle/log/</Property>
        <Property name="fileName">backupOracle.log</Property>
      </Properties>
    <!--先定義所有的appender-->
    <appenders>
        <!--這個輸出控制檯的配置-->
        <Console name="Console" target="SYSTEM_OUT">
             <!--控制檯只輸出level及以上級別的資訊(onMatch),其他的直接拒絕(onMismatch)-->
            <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
            <!-- 輸出日誌的格式-->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
        </Console>

        <!--這個會打印出所有的資訊,每次大小超過size,則這size大小的日誌會自動存入按年份-月份建立的資料夾下面並進行壓縮,作為存檔-->
        <RollingFile name="RollingFile" fileName="${backupFilePatch}${fileName}"
            filePattern="${backupFilePatch}$${date:yyyy-MM}/app-%d{yyyyMMddHHmmssSSS}.log.gz">
            <PatternLayout
                pattern="%d{yyyy.MM.dd 'at' HH:mm:ss.SSS z} %-5level %class{36} %L %M - %msg%xEx%n" />
            <!-- 日誌檔案大小 -->
            <SizeBasedTriggeringPolicy size="20MB" />
            <!-- 最多保留檔案數 DefaultRolloverStrategy屬性如不設定,則預設為最多同一資料夾下7個檔案,這裡設定了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </appenders>

    <!--然後定義logger,只有定義了logger並引入的appender,appender才會生效-->
    <loggers>
         <!--過濾掉spring和mybatis的一些無用的DEBUG資訊-->
         <logger name="org.springframework" level="INFO"></logger>
         <logger name="org.mybatis" level="INFO"></logger>
         <root level="trace">  
            <appender-ref ref="RollingFile"/>  
            <appender-ref ref="Console"/>  
         </root>  
    </loggers>
</configuration>

jdbc.properties

##########################
##
##
## dbcp datasource pool ,basic configuration first.
## the other parameters keep default for now , you can change them if you want 
##
##
##########################

#Database in Lapaz
jdbc.driverClassNamePR=oracle.jdbc.driver.OracleDriver
jdbc.urlPR=jdbc:oracle:thin:@172.25.243.4:1521:xx
jdbc.usernamePR=xxx
jdbc.passwordPR=xxxxxxxx



#Database in Scluz
jdbc.driverClassNameDR=oracle.jdbc.driver.OracleDriver
jdbc.urlDR=jdbc:oracle:thin:@172.25.246.1:1521:xx
jdbc.usernameDR=xxx
jdbc.passwordDR=xxxxxxx

#Database in Lapaz
jdbc.driverClassNameCC=oracle.jdbc.driver.OracleDriver
jdbc.urlCC=jdbc:oracle:thin:@172.25.243.3:1521:xx
jdbc.usernameCC=xxx
jdbc.passwordCC=xxxxxx

執行結果:

這裡寫圖片描述