Tech Life

Ilustrační obrázek

Upgrade na Connector/J 5.1

07. 10. 2010 10:45    kategorie: Tech Life    autor: VMe    komentářů: 0

Na našich projektech používáme většinou databázový systém MySQL, a protože je píšeme v Javě, používáme oficiální JDBC driver pro MySQL - Connector/J. Dlouhou dobu jsme používali “osvědčenou” a stabilní verzi 3.1.x, ale přechod na MySQL 5.1 si vyžádal i novou verzi driveru.
 

Bohužel nežijeme v ideálním světě, takže nestačilo jenom vyměnit driver, ale byly potřeba zásahy i na dalších místech. Jak si ale ukážeme dále, nebylo to zase tak obtížné.

Změny mezi Connector/J 3.1.x a 5.1.x obecně

Základní popis rozdílů mezi verzemi Connector/J je zde. Stručně ho lze shrnout tak, že verze 5.0 přidává podporu pro distribuované transakce implementací standardu XA, verze 5.1 přináší podporu JDBC 4.0 (určitě ale neimplementuje všechny nepovinné funkce) a hlavně je to jediná verze oficiálně kompatibilní s MySQL serverem 5.1 a výše.

Navíc je u nových verzí Connector/J vidět snaha o striktní dodržování specifikace JDBC a odstranění odchylek od standardu v předchozích verzích.

Nyní už ke konkrétním problémům, na které jsme při tomto upgrade narazili. Rozhodně je ale neberte jako seznam všech změn mezi výše uvedenými verzemi Connector/J. Ten můžete nalézt zde.

Změna mechanismu obnovy mrtvých spojení do databáze

Tento bod se týká zejména změny významu parametru autoReconnect.Původní implementace byla taková, že pokud byl tento parametr zapnutý, tak sám driver před každým dotazem do databáze ověřoval, jestli je spojení stále aktivní, a pokud nebylo, pokusil se ho znovu navázat. Obnova spojení byla tedy před JDBC klientem ukryta.

Nové verze Connector/J tento mechanismus implementují poněkud jinak. Dotaz nad mrtvým spojením do databáze vždy vyhodí výjimku. Pokud je parametr autoReconnect zapnutý, tak se driver před dalším dotazem pokusí spojení znovu otevřít. Vyhazování výjimky je tedy pro JDBC klienta podstatný rozdíl.

Nicméně celý tento mechanismus byl, podle autorů driveru, od začátku jenom berlička pro connection pooly, které nedokázaly samy validovat a obnovovat spojení do databáze. Dnes už je ale situace naštěstí jiná a odpovědnost za obnovu mrtvých spojení lze přenést na connection pool, který je typicky součástí aplikačního serveru.

Například náš oblíbený servletový kontejner Tomcat standardně používá connection pool DBCP, který tento mechanismus podporuje. Dělá to tak, že před vytažením spojení z poolu provede jednoduchý validační dotaz. Pokud ten způsobí výjimku, spojení se vyhodí z poolu a vybere se jiné. Tento mechanismus se dá konfigurovat (např. je možné spojení validovat ještě v jiných okamžicích), vždy je ale nutné nastavit minimálně parametr validationQuery, který musí obsahovat dotaz, který vrací minimálně jeden řádek. Typicky se používá triviální dotaz SELECT 1.

Například definice datového zdroje:

<Resource
	name="jdbc/jmeno"
	driverClassName="com.mysql.jdbc.Driver"
	...
	username="UZIVATEL"
	password="HESLO"
	url="jdbc:mysql://muj.server/moje_databaze?autoReconnect=true"/>

By se měla změnit na:

<Resource
	name="jdbc/jmeno"
	driverClassName="com.mysql.jdbc.Driver"
	...
	username="UZIVATEL"
	password="HESLO"
	validationQuery="SELECT 1"
	url="jdbc:mysql://muj.server/moje_databaze"/>

Změna chování ResultSetMetaData.getColumnName

Tento problém se týká rozdílu mezi jménem a aliasem (v terminologii JDBC - label) sloupce ve výsledku SQL dotazu a při upgradu jsou jím postižené zejména metody používající tento vzor:

  1. Map<String, Object> getResultSetMap(ResultSet rs) throws Exception {  
  2.         Map<String, Object> rm = new HashMap<String, Object>();  
  3.         ResultSetMetaData rsmd = rs.getMetaData();  
  4.         for (int i=1; i<=rsmd.getColumnCount(); i++) {  
  5.                 String colName = rsmd.getColumnName(i); // (*)  
  6.                 Object val = rs.getObject(colName);  
  7.                 rm.put(colName, val);  
  8.         }  
  9.         return rm;  
  10. }  

Problém je v tom, že podle specifikace JDBC vrací metoda getColumnName vždy jméno sloupce v databázovém schématu. V případě, že dotaz pro sloupce vytváří aliasy pomocí SQL klauzule AS, nastane problém, protože metody ResultSet.getXXX očekávají jako argument právě alias a ne jméno sloupce v definici tabulky (přičemž pokud alias není explicitně definován, pak je stejný jako jméno sloupce). Ve výše uvedené metodě je tedy potřeba použít metodu getColumnLabel, která vrací právě alias sloupce.

Ve starších verzích Connector/J obě metody vracely alias sloupce. Implementace getColumnName byla tedy v rozporu se specifikací JDBC a v novějších verzích už je opravená. Při upgradu je tedy třeba zkontrolovat, jestli tuto metodu používáte správně.

Statement.getGeneratedKeys

Na tento problém můžete narazit, jenom pokud tuto metodu používáte nesprávně. Smíte jí zavolat jenom pokud jste Statement vytvořili (např. pomocí Connection.prepareStatement) s příznakem RETURN_GENERATED_KEYS. Starší verze Connector/J dovolovaly metodu volat i na Statementu, který byl vytvořen bez výše uvedeného příznaku. Za určitých okolností mohly dokonce vracet nesprávné výsledky. Od verze 5.1.7 už v takovém případě metoda vyhazuje výjimku.

Toto byly hlavní problémy, na které jsme při upgradu narazili. Je z nich celkem zřejmé, že se vyplatí řídit se JDBC specifikací a ne chováním konkrétního driveru, který s ní může být v určitých okrajových případech v rozporu.

Sdílet odkaz:
tisk

Diskuze k článku

K článku nebyl zatím přidán komentář.

Přidat příspěvek

 

Kontakt pro média


Máte zájem o další informace, odborný článek či přednášku na konferenci? Kontaktujte nás prosím na pr@etnetera.cz.

RSS - Tech life


RSS kanál Tech Life Blogu

Offlineblog

Offlineblog

Ljama


Komix z prostředí imaginární firmy.

ljama

Ještě jste ho nečetli? Tak tudy ...

 
Doporučujeme: Nabídka práce, volná pracovní místa - pracovní portál SPRÁVNÝKROK.CZ