{"id":25,"date":"2009-10-05T11:49:37","date_gmt":"2009-10-05T09:49:37","guid":{"rendered":"http:\/\/touk.pl\/blog\/?p=25"},"modified":"2023-03-16T16:08:40","modified_gmt":"2023-03-16T15:08:40","slug":"obejscie-problemow-z-zaleznosciami-pakietu","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2009\/10\/05\/obejscie-problemow-z-zaleznosciami-pakietu\/","title":{"rendered":"Rozwi\u0105zanie problem\u00f3w z zale\u017cno\u015bciami pakietu poprzez synonimy"},"content":{"rendered":"<h2 id=\"problem\">Problem<\/h2>\n<p>Bior\u0119 udzia\u0142 w utrzymywaniu pewnego systemu typu ODS. Jednym z powa\u017cniejszych problem\u00f3w podczas wgrywania poprawek jest sprawa zale\u017cno\u015bci mi\u0119dzy pakietami. Przypu\u015b\u0107my, \u017ce trzeba zmieni\u0107 pakiet A, od kt\u00f3rego zale\u017c\u0105 pakiety B1 i B2, kt\u00f3re s\u0105 wykorzystywane w ramach jakiej\u015b sesji. Zmiana w A powoduje, \u017ce najbli\u017csze uruchomienia pakiet\u00f3w B1 lub B2 bez tworzenia nowej sesji zako\u0144cz\u0105 si\u0119 b\u0142\u0119dem &#8220;ORA-04061: existing state of package has been invalidated&#8221;, je\u015bli tylko w A s\u0105 jakiekolwiek zmienne globalne. To zachowanie Oracle&#8217;a wynika z faktu, \u017ce zmienne globalnych pakiet\u00f3w trwaj\u0105 przez ca\u0142y czas \u017cycia sesji. Przy zmianie kodu pakietu mog\u0142y si\u0119 one zmieni\u0107, dlatego musz\u0105 zosta\u0107 zainicjowane na nowo. Poniewa\u017c zresetowanie zmiennych w czasie trwania sesji mog\u0142oby prowadzi\u0107 do niesp\u00f3jno\u015bci &#8211; Oracle rzuca opisany powy\u017cej wyj\u0105tek. Ten mechanizm jest dok\u0142adniej opisany na stronie<br \/>\n<a rel=\"nofollow\" href=\"http:\/\/oraclequirks.blogspot.com\/2007\/03\/ora-04061-existing-state-of-package-has.html\">http:\/\/oraclequirks.blogspot.com\/2007\/03\/ora-04061-existing-state-of-package-has.html<\/a> Zmiana pakietu &#8211; zar\u00f3wno specyfikacji jak i cia\u0142a pakietu &#8211; nie jest mo\u017cliwa je\u015bli co\u015b z niego korzysta &#8211; w takim wypadku komenda zast\u0105pienia pakietu przez now\u0105 wersj\u0119 ( CREATE OR REPLACE PACKAGE [BODY]) czeka a\u017c pakiet przestanie by\u0107 u\u017cywany. Ale wystarczy, aby jaki\u015b nowy proces zaczyna\u0142 korzysta\u0107 z pakietu zanim stary przestanie to robi\u0107 i nast\u0119puje zag\u0142odzenie. Nie mo\u017cna wgra\u0107 nowej wersji pakietu. Takie zjawiska bardzo utrudniaj\u0105 wdra\u017canie, trzeba zabija\u0107 procesy korzystaj\u0105ce ze zmienianego pakietu. Wypracowa\u0142em nawet skrypt, kt\u00f3ry zabija wszystkie sesje blokuj\u0105ce jak\u0105\u015b sesj\u0119 uruchomion\u0105 z mojego komputera i mojego u\u017cytkownika systemu operacyjnego:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"oracledb\">DECLARE\r\n  CURSOR c_sql_hist(pp_machine VARCHAR2, pp_osuser VARCHAR2) IS\r\n    SELECT ash.blocking_session, ash.blocking_session_status, ash.blocking_session_serial#, s.program, s.module, s.action\r\n      FROM v$active_session_history ash\r\n      JOIN v$session s ON ash.blocking_session = s.sid\r\n                      AND ash.blocking_session_serial# = s.serial#\r\n     WHERE ash.session_id in ( select sid from v$session where machine = pp_machine\r\n     and osuser = pp_osuser )\r\n       AND ash.sample_time &gt; SYSDATE - 2 \/ 24 \/ 3600\r\n     ORDER BY sample_time DESC;\r\n  v_r c_sql_hist%ROWTYPE;\r\n\r\n  v_my_machine v$session.MACHINE%TYPE;\r\n  v_my_osuser v$session.osuser%TYPE;\r\nBEGIN\r\n  select machine, osuser into v_my_machine, v_my_osuser from v$session\r\n  where sid = ( Select Sid from v$mystat where rownum = 1);\r\n\r\n  for i in 1..10000 loop  -- just to prevent infinite execution\r\n    dbms_output.put_line('step: ' || i );\r\n    OPEN c_sql_hist(v_my_machine, v_my_osuser);\r\n    FETCH c_sql_hist\r\n      INTO v_r;\r\n    IF NOT c_sql_hist%NOTFOUND THEN\r\n      dbms_output.put_line(v_r.blocking_session || ' ' || v_r.blocking_session_status || ' ' || v_r.blocking_session_serial# || ' ' || v_r.program || ' ' ||\r\n                           v_r.module || ' ' || v_r.action);\r\n      execute immediate ' ALTER SYSTEM KILL SESSION ''' || v_r.blocking_session || ',' || v_r.blocking_session_serial# || '''';\r\n    else\r\n      exit;\r\n    END IF;\r\n    CLOSE c_sql_hist;\r\n    dbms_lock.sleep(0.5); -- sleep is used to get new blocking sessions\r\n  end loop;\r\nEND;<\/pre>\n<p>Opisane powy\u017cej problemy z zale\u017cno\u015bciami doprowadzi\u0142y do sytuacji, w kt\u00f3rych r\u00f3\u017cne pakiety narz\u0119dziowe, kt\u00f3re powinny by\u0107 zgromadzone w jednym centralnym schemacie zosta\u0142y skopiowane do wszystkich schemat\u00f3w. Dzi\u0119ki temu mo\u017cna je zmienia\u0107 bez konieczno\u015bci zabijania wszystkich proces\u00f3w dzia\u0142aj\u0105cych na bazie, ale jest to rozwi\u0105zanie fatalne z punktu widzenia utrzymania kodu.<\/p>\n<h2 id=\"rozwiazanie\">Rozwi\u0105zanie<\/h2>\n<p>Stosowanym przez nas rozwi\u0105zaniem tego problemu jest, aby odwo\u0142ania do pakiet\u00f3w odbywa\u0142y si\u0119 poprzez synonimy. Je\u015bli jest potrzeba zmieni\u0107 pakiet &#8211; tworzymy jego now\u0105 wersj\u0119 a po przetestowaniu przepina si\u0119 synonim, aby na ni\u0105 wskazywa\u0142. Najbli\u017csze uruchomienie tego synonimu w ramach sesji powoduje, \u017ce uruchamiany jest nowy pakiet. Jego zmienne s\u0105 inicjalizowane na nowo, ale nie jest to problem, poniewa\u017c pe\u0142ni\u0105 funkcje cache&#8217;a a nie s\u0142u\u017c\u0105 do przechowywania stanu. Wyst\u0119puje dodatkowe ograniczenie, \u017ce nie mog\u0105 chodzi\u0107 r\u00f3wnocze\u015bnie dwie wersje tej samej procedury lub pakietu, kt\u00f3rych synonimy wskazuj\u0105 na odmienne obiekty. Dlatego je\u015bli uruchomi si\u0119 B1, przepnie synonim na A_v2, po czym ponownie uruchomi B1 (po\u015brednio lub bezpo\u015brednio) to to drugie uruchomienie B1 nie rozpocznie si\u0119 dop\u00f3ki pierwsze &#8211; na starym synonimie &#8211; si\u0119 nie sko\u0144czy. Nie jest to jednak praktyczny problem. Opisane obej\u015bcie pozwala na sprawniejszy rozw\u00f3j i wdra\u017canie kodu bazodanowego. Konieczna jest tylko \u015bwiadomo\u015b\u0107 dzia\u0142ania mechanizmu i powy\u017cszych ogranicze\u0144. Nale\u017ca\u0142o r\u00f3wnie\u017c wypracowa\u0107 praktyk\u0119 nazewnictwa (przyk\u0142adowo dodawanie na ko\u0144cu nazwy TO_CHAR(sysdate, &#8216;$MM_DD&#8217;) czyli znaku dolara oraz miesi\u0105cu i dnia wdro\u017cenia wersji). Konieczne jest r\u00f3wnie\u017c nadanie innym schematom tych samych praw do nowej wersji pakietu, kt\u00f3re mieli do starej wersji.<\/p>\n","protected":false},"excerpt":{"rendered":"Problem Bior\u0119 udzia\u0142 w utrzymywaniu pewnego systemu typu ODS. Jednym z powa\u017cniejszych problem\u00f3w podczas wgrywania poprawek jest sprawa&hellip;\n","protected":false},"author":8,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[687,13],"class_list":{"0":"post-25","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-db","8":"tag-oracle"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/25","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=25"}],"version-history":[{"count":11,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions"}],"predecessor-version":[{"id":15298,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/25\/revisions\/15298"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=25"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=25"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}