Tag Archives: oracle

Nelze se připojit na Oracle z Javy, ale sql*plus nemá problém…

Situace: sqlplus se na server připojí, ale javská aplikace dostane ORA-12505 „Listener nenašel takovou službu, jakou chcete“. Co s tím?

Java aplikace při pokusu o připojení k Oracle 10g dostane chybu

java.sql.SQLException: Vyjimka vstupu/vystupu: Connection refused (DESCRIPTION=(TMP=)(VSNNUM=169870080)(ERR=12505)(ERROR_STACK=(ERROR=(CODE=12505)(EMFI=4))))

ale SQL*PLUS se stejným nastavením normálně funguje? Jak je to možné?

Po chvíli hledání na netu jsem narazil na informaci, že je to způsobeno nevhodným nastavením serveru. Řešení je jednoduché: místo „prostého“ connection stringu ve tvaru

jdbc:oracle:thin:@server:port/instance

je nutno tučný text nahradit celým popisem konexe z TNSNAMES.ORA a do sekce „CONNECT_DATA“ přidat položku (SERVER=DEDICATED).

Tj. mám-li v TNSNAMES.ORA třeba

APPTEST.world =
(DESCRIPTION =
(ADDRESS_LIST =
(load_balance=off)
(failover=on)
(ADDRESS = (PROTOCOL = TCP) (Host = adb) (Port = 1529))
(ADDRESS = (PROTOCOL = TCP) (Host = apsdb) (Port = 1529))
)
(CONNECT_DATA = (service_name=APPTEST)(FAILOVER_MODE= (TYPE=SELECT) (METHOD=BASIC) (RETRIES=1440) (DELAY =5))
)
)

pak connection string pro Javu bude

jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS_LIST = (load_balance=off) (failover=on) (ADDRESS = (PROTOCOL = TCP) (Host = adb) (Port = 1529)) (ADDRESS = (PROTOCOL = TCP) (Host = apsdb) (Port = 1529)) ) (CONNECT_DATA = (service_name=APPTEST)(SERVER=DEDICATED)(FAILOVER_MODE= (TYPE=SELECT) (METHOD=BASIC) (RETRIES=1440) (DELAY =5)) ) )

a problém je vyřešen.

Původní zdroj: http://www.websina.com/bugzero/kb/oracle-connection.html

Docela mne překvapil i ten samotný fakt, že je možno takhle connection string zapsat.

 

Oracle si nevšimne rozpadu TCP spojení a jak z toho ven

Pokud se aplikace připojuje na Oracle v rámci lokálního počítače, vše funguje tak, jak má. Pokud ale přistupuje přes síť, používá zámky a někdo přetrhne spojení (vypne klientský počítač „natvrdo“, vytáhne síťový kabel), Oracle si nevšimne, že se spojení rozpadlo – a zámky zůstanou zamčené, dokud s tím DBA něco neudělá. Co s tím?

 

Existují dvě možnosti, jak to vyřešit.

 

Na „soft“ úrovni je to možné pomocí „resource profilů“ – konkrétně nastavením „IDLE_TIME“.

1) Nejprve povolíme profily v dané instanci Oracle:

alter system set resource_limit=true;

2) Pak uděláme profil s limitací IDLE_TIME na 3 minuty:

CREATE PROFILE LIMPROFILE LIMIT IDLE_TIME 3;

3) A nakonec tento profil přiřadíme k uživateli:

alter user appuser profile LIMPROFILE;

Co to udělá? Pokud v rámci spojení po zadanou dobu nepřijde žádný příkaz, spojení je přerušeno. Do „idle“ time se nepočítá čas, kdy databáze něco dělá – tj. pokud mi SELECT poběží 10 minut, je to v pořádku.

Tj. nekontrolujeme rozpad spojení, ale to, že se na něm nic neděje= budeme muset do aplikace dodělat nějaké „void“ akce typu SELECT * FROM DUAL, aby spojení nikdy nebylo neaktivní déle než zadaný čas.

Pozor! Spojení ukončené pro IDLE TIME se sice uzavře, transakce rollbacknou a zámky odemknou, ale spojení zůstane v tabulce SESSIONS ve stavu „SNIPED“. DBA jej musí smazat ručně (!!!).

 

Druhé řešení je lepší. V souboru network/admin/SQLNET.ORA na serveru je třeba založit novou konfigurační hodnotu:

SQLNET.EXPIRE_TIME=3

Tato hodnota říká, že pokud v TCP spojení na server více než 3 minuty neprojde žádný příkaz, server do něj pošle testovací paket, na který klientská Oracle knihovna odpoví. A pokud neodpoví, Oracle vezme spojení za mrtvé, korektně ukončí session (žádné „SNIPED“ stavy), rollbackne transakce a odemkne zámky.

Vedlejším efektem je malý nárůst síťového provozu (posílání testovacích paketů), ale za odstranění problémů se zamčenými a nedostupnými záznamy to stojí, ne?

 

Keywords: Oracle, DBA, locked record, session timeout