Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Databáze v Java JDBC - Výpis dat a parametry

V minulém dílu našeho seriálu, Návrh MySQL databáze v IntelliJ IDE, jsme si připravili databázi s testovacími daty.

V dnešním tutoriálu se k naší MySQL databázi v Javě připojíme a budeme z ní číst hodnoty.

Instalace MySQL connectoru

Pro připojení k MySQL databázi v našemu Java projektu v IntelliJ IDE je nezbytné stáhnout a nakonfigurovat jej pomocí MySQL connectoru. MySQL connector je možné stáhnout z webu https://downloads.mysql.com/archives/c-j/:

Stažení MySQL connectoru - Databáze v Javě - JDBC

MySQL connector následně extrahujeme a uložíme v systému tak, abychom k němu měli přístup. Budeme využívat soubor mysql-connector-j-<verze>.jar. Jedná se o knihovnu, která nám umožní připojení k MySQL databázi a provádění dalších operací. Pro demonstrační účely byl v Java projektu vytvořen adresář lib/, kam byl .jar soubor uložen:

Umístění MySQL .jar souboru - Databáze v Javě - JDBC

Nakonec je zapotřebí propojit tuto knihovnu s Java projektem. Na horním panelu nástrojů klikneme na Soubor -> Struktura projektu. Otevře se nám okno projektu, kde vybereme položku Moduly a poté Závislosti:

Nastavení závislosti projektu - Databáze v Javě - JDBC

Načtení ovladače

V minulosti bylo třeba JDBC ovladač před použitím načíst. Dělalo se to tímto způsobem:

try {
    Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
    System.out.println("Chyba při načtení databázového ovladače");
}

Java si dnes již ovladač načte sama a tento kód tedy není třeba. Uvádíme ho jen proto, že je někdy ještě k vidění ve starších projektech nebo zastaralých tutoriálech.

Třídy pro práci s databází

S databází budeme pracovat pomocí svaté trojice tříd Connection, PreparedStatement a ResultSet. Všechny se nacházejí v balíčku java.sql.

Třída Connection

Connection zajišťuje databázové spojení. To je nutné vytvořit předtím, než se databáze na něco zeptáme. Při jeho vytváření uvedeme tzv. connection string. To je řetězec obsahující jméno databázového ovladače, URL serveru, kde databáze běží, dále název databáze, uživatelské jméno a heslo.

Vytvoření nové instance spojení bude v našem případě vypadat takto:

Connection spojeni = DriverManager.getConnection("jdbc:mysql://localhost/slovnicek_db?user=root&password=")

Třída PreparedStatement

PreparedStatement je databázový dotaz. Při vytvoření instance zadáváme SQL kód, který chceme na databázi spustit. Java obsahuje také třídu Statement, která se od PreparedStatement liší tím, že nemůže obsahovat parametry (o tom dále).

V našem případě si vytvoříme následující instanci dotazu:

PreparedStatement dotaz = spojeni.prepareStatement("SELECT * FROM slovo")

Vytvořili jsme jednoduchý SQL dotaz. Příkazem SELECT říkáme, že chceme z databázové tabulky vybrat data. Hvězdička označuje, že u výsledných řádků chceme vybrat hodnoty ze všech sloupců. FROM slovo označuje, že vybíráme z tabulky slovo. Dotaz tedy vybere všechny hodnoty všech slov.

Všimněme si, že se dotaz vytváří přes instanci spojení.

Třída ResultSet

ResultSet je kolekce výsledků, které vrátil nějaký SQL dotaz. ResultSet naplněný výsledky SQL příkazu SELECT získáme pomocí metody executeQuery() na instanci dotazu:

ResultSet vysledky = dotaz.executeQuery();

Uzavírání spojení

Pokud jste v Javě již pracovali se soubory, nebude pro vás žádným překvapením, že i databázové spojení se musí uzavřít. Malým překvapením však může být, že se musíme postarat o správné uzavření všech tří databázových objektů. Kdybychom to neudělali, zůstalo by spojení otevřené a server by se za nějakou dobu zahltil.

Nejjednodušší způsob je vytvořit objekty v bloku try-with-resources. Jakmile Java tento blok kódu opustí, sama se postará o uzavření instancí, které jsou v deklaraci bloku vytvořené:

try (Connection spojeni = DriverManager.getConnection("jdbc:mysql://localhost/slovnicek_db?user=root&password=");
    PreparedStatement dotaz = spojeni.prepareStatement("SELECT * FROM slovo");
    ResultSet vysledky = dotaz.executeQuery();) {

} catch (SQLException ex) {
    System.out.println("Chyba při komunikaci s databází");
}

Pokud se něco pokazí, informujeme o tom uživatele chybovou hláškou. Při ladění blok catch zakomentujeme, abychom mohli na chyby reagovat a kód opravit.

Výpis výsledků

V proměnné vysledky máme již načtená slovíčka z databáze. Zbývá je jen vypsat. ResultSet k tomu poskytuje metodu next(). Ta přesune aktuální pozici v kolekci na další prvek nebo vrátí false v případě, že jsme na konci výsledků.

K samotnému čtení hodnoty na aktuálním řádku výsledků slouží metody getInt(), getString(), getDate() a další. Metodám můžeme dát jako parametr buď název sloupce nebo jeho číselný index. U číselného indexu pozor, první sloupec má index 1:

while (vysledky.next()) {
    int id = vysledky.getInt(1);
    String cesky = vysledky.getString("cesky");
    String anglicky = vysledky.getString("anglicky");
    System.out.println("Id: " + id + ", česky: " + cesky + ", anglicky: " + anglicky);
}

Kódem výše iterujeme nad výsledky, získáváme jejich parametry a ty poté vypisujeme do konzole. Ukažme si ještě kompletní kód aplikace:

try (Connection spojeni = DriverManager.getConnection("jdbc:mysql://localhost/slovnicek_db?user=root&password=a");
    PreparedStatement dotaz = spojeni.prepareStatement("SELECT * FROM slovo");
    ResultSet vysledky = dotaz.executeQuery();) {

    while (vysledky.next()) {
        int id = vysledky.getInt(1);
        String cesky = vysledky.getString("cesky");
        String anglicky = vysledky.getString("anglicky");
        System.out.println("Id: " + id + ", česky: " + cesky + ", anglicky: " + anglicky);
    }

} catch (SQLException ex) {
    System.out.println("Chyba při komunikaci s databází");
}

Můžeme si zkusit, že aplikace opravdu vypíše všechna slovíčka z databáze:

Čtení z MySQL databáze pomocí JDBC v Javě - Databáze v Javě - JDBC

Předávání parametrů

Doveďme aplikaci opravdu do podoby slovníčku. Uživatele necháme zadat slovíčko v angličtině a to mu následně přeložíme do češtiny.

SQL injekce

SQL dotaz by měl nyní vybrat jen určitý řádek, je do něj tedy třeba dodat podmínky. Toho docílíme pomocí klauzule WHERE. Naivně bychom mohli vložit slovíčko od uživatele přímo do těla SQL dotazu:

// Tento kód je nebezpečný
Scanner scanner = new Scanner(System.in, "Windows-1250");
System.out.println("Zadej anglické slovíčko k překladu:");
String anglicky = scanner.nextLine();
try (Connection spojeni = DriverManager.getConnection("jdbc:mysql://localhost/slovnicek_db?user=root&password=");
    PreparedStatement dotaz = spojeni.prepareStatement("SELECT cesky FROM slovo WHERE anglicky=\"" + anglicky + "\"");
    ResultSet vysledky = dotaz.executeQuery();) {

    vysledky.next();
    String cesky = vysledky.getString("cesky");
    System.out.println("Překlad " + anglicky + ": " + cesky);
} catch (SQLException ex) {
    System.out.println("Chyba při komunikaci s databází");
}

Výsledek:

MySQL slovníček v Javě - Databáze v Javě - JDBC

Kód se příliš nezměnil. V SQL dotazu již nevybíráme všechny sloupce, ale pouze sloupec cesky. Kromě toho nám zde přibyla podmínka WHERE. Výsledky již nenačítáme ve while cyklu, jelikož nás zajímá pouze jeden.

Ačkoli se zdá, že aplikace funguje perfektně, opak je pravdou. Cokoli uživatel zadá, se vloží přímo do SQL dotazu. Co se stane, když zadá např. následující řetězec:

"; DROP TABLE slovo --

Na databázi se spustí příkaz k vymazání tabulky a máme po datech. To je ještě ten lepší případ, šikovnější uživatel by nám přes slovníček mohl třeba vytahat hesla uživatelů z jiné tabulky. A to už by byl problém. Věřme nebo ne, ale uživatelé takové vstupy opravdu zadávají a naše aplikace se jim musí bránit. Této technice útoku se říká SQL injection, protože se vkládá cizí SQL kód do našeho dotazu.

Předávání parametrů

Celý problém je samozřejmě v tom, že vkládáme vstup od uživatele přímo do SQL dotazu. V minulosti se proměnné ošetřovaly speciální funkcí, která tzv. zescapovala nebezpečné znaky (zejména uvozovky). Nejbezpečnější je ovšem používat PreparedStatements. Jde o dotaz, který obsahuje místo parametrů zástupné znaky, nejčastěji otazníky. Samotné hodnoty se do dotazu dosadí odděleně a sama databáze se postará o jejich bezpečné vložení do dotazu.

Přepišme naší aplikaci tak, aby používala parametrizované dotazy:

Scanner scanner = new Scanner(System.in, "Windows-1250");
System.out.println("Zadej anglické slovíčko k překladu:");
String anglicky = scanner.nextLine();
try (Connection spojeni = DriverManager.getConnection("jdbc:mysql://localhost/slovnicek_db?user=root&password=");
    PreparedStatement dotaz = spojeni.prepareStatement("SELECT cesky FROM slovo WHERE anglicky=?");) {
    dotaz.setString(1, anglicky);
    try (ResultSet vysledky = dotaz.executeQuery()) {
        vysledky.next();
        String cesky = vysledky.getString("cesky");
        System.out.println("Překlad " + anglicky + ": " + cesky);
    }
} catch (SQLException ex) {
    System.out.println("Chyba při komunikaci s databází");
}

Všimněme si otazníku v dotazu a volání metody setString(), která nastaví první parametr v dotazu na daný řetězec. Samozřejmě zde nalezneme i metody pro další datové typy. Naše aplikace je nyní bezpečná.

V následujícím kvízu, Kvíz - Základy práce s databází v Java JDBC, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 654x (18.28 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Návrh MySQL databáze v IntelliJ IDE
Všechny články v sekci
Databáze v Javě - JDBC
Přeskočit článek
(nedoporučujeme)
Kvíz - Základy práce s databází v Java JDBC
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
68 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity