• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 使用jaydebeapi同時連接兩個不同數據庫(oracle+mysql)的問題

    標簽: jaydebeapi oracle mysql  jaydebeapi 多個數據庫

    在使用jaydebeapi只連接一種數據庫時,是沒問題的,但是如果需要同時連接兩種數據庫,比如同時連接oracle和mysql

    例如以下測試代碼:

    import jaydebeapi  ##使用jdbc驅動連接數據庫
    import pandas as pd
    
    dirver='oracle.jdbc.driver.OracleDriver'
    jarFile='D:\\WORK\\PYScript\\BiDataMonitor\\jdbc\\64\\ojdbc14.jar'
    addr_='xxx.xxx.xxx.xxx'+':'+'1521'+'/'+'xxx'
    url='jdbc:oracle:thin:@'+addr_
    print('url',url)
    DBUser='用戶名'
    DBPwd='密碼'
    conn=jaydebeapi.connect(dirver,[url,DBUser,DBPwd],jarFile) ##使用jdbc驅動連接數據庫
    sql_str="select 'oracle' from dual"
    df=pd.read_sql_query(sql_str,conn)
    print(df)
    conn.close()
    
    
    dirver='com.mysql.jdbc.Driver'
    jarFile='D:\\WORK\\PYScript\\BiDataMonitor\\jdbc\\64\\mysql-connector-java-5.1.30.jar'
    addr_='xxx.xxx.xxx.xxx'+':'+'3306'+'/'+'xxx'
    url='jdbc:mysql://'+addr_
    print('url',url)
    DBUserMySql='用戶名'
    DBPwdMySql='密碼'
    conn2=jaydebeapi.connect(dirver,[url,DBUserMySql,DBPwdMySql],jarFile)
    sql_str="select 'mysql' from dual"
    df=pd.read_sql_query(sql_str,conn2)
    print(df)
    conn2.close()

    在連接第二種數據庫時,就會報錯誤:

    Py4JJavaError: An error occurred while calling z:java.sql.DriverManager.getConnection.
    : java.sql.SQLException: No suitable driver found for jdbc:mysql://10.1.164.5:3306/vvm
    	at java.sql.DriverManager.getConnection(Unknown Source)
    	at java.sql.DriverManager.getConnection(Unknown Source)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    	at java.lang.reflect.Method.invoke(Unknown Source)
    	at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
    	at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    	at py4j.Gateway.invoke(Gateway.java:282)
    	at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    	at py4j.commands.CallCommand.execute(CallCommand.java:79)
    	at py4j.GatewayConnection.run(GatewayConnection.java:214)
    	at java.lang.Thread.run(Unknown Source)

    錯誤信息中顯示,找不到渠道,而實際上并不是驅動或者jar包的問題。

    要分析和解決這個問題,還需要從jaydebeapi的源碼中分析,打開jaydebeapi源碼(下載地址:https://pypi.python.org/pypi/JayDeBeApi3),從報錯信息中我們可以得到,是在...jaydebeapi\__init__.py", line 68


    jaydebeapi.connect方法源碼如下:

    # DB-API 2.0 Module Interface connect constructor
    def connect(jclassname, driver_args, jars=None, libs=None):
        """Open a connection to a database using a JDBC driver and return
        a Connection instance.
    
        jclassname: Full qualified Java class name of the JDBC driver.
        driver_args: Argument or sequence of arguments to be passed to the
               Java DriverManager.getConnection method. Usually the
               database URL. See
               http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html
               for more details
        jars: Jar filename or sequence of filenames for the JDBC driver
        libs: Dll/so filenames or sequence of dlls/sos used as shared
              library by the JDBC driver
        """
    
        if _gateway_is_running():
            gateway = java_gateway.JavaGateway()
        else:
            driver_args = [driver_args] if isinstance(driver_args, str) else driver_args
    
            if jars:
                classpath = os.pathsep.join(jars) if isinstance(jars, list) else jars
            else:
                classpath = None
    
            if libs:
                javaopts = libs if isinstance(libs, list) else [libs]
            else:
                javaopts = []
    
            gateway = java_gateway.JavaGateway.launch_gateway(
                port=25333, classpath=classpath, javaopts=javaopts, die_on_exit=True)
    
            java_gateway.java_import(gateway.jvm, 'java.sql.DriverManager')
            gateway.jvm.Class.forName(jclassname)
    
        connection = gateway.jvm.DriverManager.getConnection(*driver_args)
        if _converters is None:
            types_map = {}
            for type in gateway.jvm.Class.forName("java.sql.Types").getFields():
                types_map[type.getName()] = type.getInt(None)
            _init_converters(types_map)
    
        return Connection(connection, _converters)

    報錯信息中提示的68行也就是:

    connection = gateway.jvm.DriverManager.getConnection(*driver_args)

    其實,我不需要跟深層次是剖析,只需要分析下jaydebeapi.connect方法即可,該方法大概是邏輯是:

                    判斷 java_gateway是否running
                |----------是---|-----否-----|	
                |				 |
    	獲取gateway實例		    1、初始化參數
    				    2、創建gateway實例

    問題就出在這里,第一次連接oracle時,通過右邊分支先初始化參數,然后創建了gateway實例,但是第二次調用jaydebeapi.connect方法連mysql時,由于_gateway_is_running()返回真,所以走左邊分支,直接獲取了上一次連接oracle時創建gateway實例,其中最重要的兩個個參數jclassname和classpath,也就是“oracle.jdbc.driver.OracleDriver”和"ojdbc14.jar"

            gateway = java_gateway.JavaGateway.launch_gateway(
                port=25333, classpath=classpath, javaopts=javaopts, die_on_exit=True)
    
            java_gateway.java_import(gateway.jvm, 'java.sql.DriverManager')
            gateway.jvm.Class.forName(jclassname)

    而第二次連mysql時,用的是mysql的連接,所以當然就是報No suitable driver found for jdbc錯誤。

    明白了報錯的原因,下面就來需求解決方法

    解決的方法應該有多種,我這里采取了最簡單,最暴力的方法,就是在判斷_gateway_is_running()時,將其關閉,然后重新重建新的gateway實例,這樣雖然簡單,但是如果頻繁連接數據庫時,就會因為不能重用上一次實例而消耗額外的資源。

    通過幫助函數可知,gateway實例有一個shutdown方法

    修改后的connect方法如下:

    # DB-API 2.0 Module Interface connect constructor
    def connect(jclassname, driver_args, jars=None, libs=None):
        """Open a connection to a database using a JDBC driver and return
        a Connection instance.
    
        jclassname: Full qualified Java class name of the JDBC driver.
        driver_args: Argument or sequence of arguments to be passed to the
               Java DriverManager.getConnection method. Usually the
               database URL. See
               http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html
               for more details
        jars: Jar filename or sequence of filenames for the JDBC driver
        libs: Dll/so filenames or sequence of dlls/sos used as shared
              library by the JDBC driver
        """
    
        if _gateway_is_running():
            gateway = java_gateway.JavaGateway()
            gateway.shutdown()
        else:
            pass
        driver_args = [driver_args] if isinstance(driver_args, str) else driver_args
    
        if jars:
            classpath = os.pathsep.join(jars) if isinstance(jars, list) else jars
        else:
            classpath = None
    
        if libs:
            javaopts = libs if isinstance(libs, list) else [libs]
        else:
            javaopts = []
    
        gateway = java_gateway.JavaGateway.launch_gateway(
            port=25333, classpath=classpath, javaopts=javaopts, die_on_exit=True)
    
        java_gateway.java_import(gateway.jvm, 'java.sql.DriverManager')
        gateway.jvm.Class.forName(jclassname)
    
        connection = gateway.jvm.DriverManager.getConnection(*driver_args)
        if _converters is None:
            types_map = {}
            for type in gateway.jvm.Class.forName("java.sql.Types").getFields():
                types_map[type.getName()] = type.getInt(None)
            _init_converters(types_map)
    
        return Connection(connection, _converters)


    然后卸載jaydebeapi,用修改后的源碼重新安裝一次即可,源碼安裝方法,可以查看之前的一篇博客:

    https://blog.csdn.net/cakecc2008/article/details/79073181




    版權聲明:本文為cakecc2008原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/cakecc2008/article/details/79786378

    智能推薦

    如何同步兩個不同數據庫?用datax輕松解決(Java,mysql)

    項目中要將現場的數據,同步到云端,記錄一下實現過程,(目前只會簡單使用),希望可以幫助到需要的人。 首先要安裝一個python, 鏈接:https://pan.baidu.com/s/14Sk3pVMVWUzdKoq_wpCfnw  提取碼:v7n5    安裝很簡單,雙擊圖標,然后一路Next就可以,要記住安裝的路徑,下面要用的。 安裝之后,要配置一下環境變量,直接...

    Mybatis學習總結:框架簡介+傳統JDBC連接數據庫+Mybatis操作數據庫的兩個簡單應用

    Mybatis框架簡介: Mybatis是一種支持普通SQL查詢,存儲過程和高級映射的持久層框架(懂不懂先拿小本本記下來了),該框架幾乎消除了所有的JDBC代碼和參數的手工設置以及對結果集的檢索和封裝,Mybatis可以用簡單的XML或注解用于配置和原始映射,將接口和普通的Java對象映射成為數據庫中的記錄 為對比出與傳統jdbc的區別,先用傳統方式連接數據庫 給出一份查詢planegame數據庫...

    【數據庫】 175. 組合兩個表 ---左右連接

    1 題目描述 2 解題思路 因為表 Address 中的 personId 是表 Person 的外關鍵字,所以我們可以連接這兩個表來獲取一個人的地址信息。 考慮到可能不是每個人都有地址信息,我們應該使用 outer join 而不是默認的 inner join。這個題目要選擇用左連接。 題目說: 1)無論 person 是否有地址信息,都需要基于上述兩表提供 person 的以下信息: Firs...

    Unity_Shader高級篇_13.1_Unity Shader入門精要

    13.4 再談邊緣檢測 在12.3中,我們曾使用Sobel算子對屏幕圖像進行邊緣測試,實現描邊的效果。但是,這種直接利用顏色信息進行邊緣檢測的方法會產生很對我們不希望得到的邊緣線,如圖13.8所示。 可以看出,物體的紋理、陰影等位置也被描上黑邊,而這往往不是我們希望看到的。在本節中,我們將學習如何在深度和法線上進行邊緣檢測,這些圖像不會受紋理和光照的影響,而僅僅保存了當前渲染物體的模型信息,通過這...

    Seata AT 模式 原理詳解

    目錄 前提 整體機制 寫隔離 讀隔離 工作機制 一階段 二階段-回滾 二階段-提交 附錄 回滾日志表 前提 基于支持本地 ACID 事務的關系型數據庫。 Java 應用,通過 JDBC 訪問數據庫。 整體機制 兩階段提交協議的演變: 一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。 二階段: 提交異步化,非常快速地完成。 回滾通過一階段的回滾日志進行反向補償。 寫隔離 ...

    猜你喜歡

    Python爬蟲 | 滑動驗證碼**

    極驗驗證碼:需要手動拼合滑塊來完成的驗證,相對圖形驗證碼識別難度上升了幾個等級。下面用程序識別并通過極驗驗證碼的驗證,其中有分析識別思路、識別缺口位置、生成滑塊拖動、模擬實現滑塊拼合通過驗證等步驟。需要用到Chrome 瀏覽器,并配置 ChromeDriver ,要用到的 Python 庫是 Selenium。 1、 對極驗驗證碼了解   極驗驗證碼官網:http://www.geetest.co...

    MobaXterm root用戶連接虛擬機時出現Access denied

    1.linux打開ssh服務 2.新建連接 首先在romote host中填入要連接的主機ip specify username中填入連接的用戶名 port為連接端口默認為22 輸入連接用戶的密碼 linux默認不顯示密碼 發現密碼正確但是連接不上 問題解決 /etc/ssh/sshd_config 配置問題: #PermitRootLogin prohibit-password將該行改為Perm...

    Linux C 預處理命令

    預處理命令 一、宏定義 C語言標準允許在程序中用一個標識符來表示一個字符串,成為宏。標識符為宏名 ,在編譯預處理時,將程序中所有的宏名用相應的字符串來替換,這個過程稱為宏替換,宏分為兩種:無參數的宏和有參數的宏。 1.無參數的宏 無參數宏定義的一般形式為:#define 標識符字符串 “#”代表本行是編譯預處理命令。define是宏定義的關鍵詞,標識符是宏名。字符串是宏名所...

    有意思的算法(一)----冒泡排序

        冒泡排序的基本思想是:每次比較兩個相鄰的元素,如果它們的順序錯誤就把他們交換過來。     下面舉一個具體的例子來介紹一下冒泡排序。     有12,35,99,18,76五個數進行從大到小的排序,既然是從大到小排序,也就是說越小的越靠后,可不要把這句當成廢話,這可是最關...

    cordova學習筆記_創建一個cordova項目

    環境和工具 webstorm Node.js JDK git 打開git bash,進入你要創建項目的目錄,鍵入以下命令 進入cordovaDemo這個文件夾: 添加Android平臺 cordova platforms add android platforms中已經有了一個Android平臺 下面打開webstorm,然后file - open 找到cordovaDemo打開 現在在webst...

    精品国产乱码久久久久久蜜桃不卡