sobota, 3 marca 2012

JDBC + MySQL

Wstęp.

Trochę czasu minęło od ostatniego wpisu. Nie mam nic na swoje usprawiedliwienie. W tym semestrze realizuję projekt z przedmiotu Programowanie Obiektowe. Używamy tam języka Java. Pomyślałem sobie, że zamiast chodzić na laboratoria, wezmę projekt i będę nad tym siedział w domu - jest okazja do nauki nowych rzeczy: obsługa bazy danych  za pomocą JDBC i Sockety Java. Ma to być aplikacja klient-serwer umożliwiająca studentom rozwiązywanie udostępnianych przez nauczyciela testów. Przy tej okazji myślę, że naskrobię parę wpisów. Oto pierwszy z nich.

Przygotowania - czego potrzebujemy.

JDBC zapewnia połączenie pomiędzy Javą a relacyjną bazą danych, umożliwia przesyłanie do niej zapytań SQL. Nie narzuca nam z jakiej bazy musimy korzystać, dlatego oprócz systemu zarządzania bazą danych (DBMS) potrzebujemy sterowników JDBC (JDBC Driver), które możemy pobrać od dostawcy bazy danych.

My będziemy korzystać z systemu zarządzania bazą danych MySQL.
  1. Instalacja serwera MySQL
    • Linux
    • Możemy zainstalować wykonując polecenie:
      sudo apt-get install mysql-server
    • Windows
    • Pobieramy i uruchamiamy plik instalacyjny. Pod tym systemem, aby dostać się do MySQL Monitora uruchamiamy program MySQL Command Line Client.
       
    • Pobranie sterownika JDBC 
    •      Pobierz MySQL Connector/J, czyli oficjalny sterownik JDBC dla MySQL
    Administracja serwerem SQL - przygotowanie bazy danych

    Polecam otworzenie tej całkiem fajnej ściągawki, szczególnie, jeśli jesteś początkującym adeptem technik zapytań SQL jak ja.

    Logujemy się do serwera MySQL wydając w terminalu polecenie
    mysql -u root -p
    Po parametrze -u podajemy nazwę użytkownika, a parametr -p mówi, że wymagane jest hasło. Nie podajemy po nim hasła, zostanie ono pobrane po zatwierdzeniu polecenia. Po udanym zalogowaniu w  MySQL Monitorze możemy zrobić co chcemy - oczywiście o ile umiemy się posługiwać językiem SQL.

    Tworzymy nowego użytkownika, ponieważ łączenie się do bazy użytkownikiem root nie jest zalecane. Nadajemy mu także prawa do łączenia się z bazą danych.
    create user sqluser identified by 'secret';
    grant usage on *.* to sqluser@localhost identified by 'secret';
    Następnie tworzymy naszą testową bazę danych oraz umożliwiamy do niej pełny dostęp użytkownikowi sqluser łączącemu się z localhost. Uaktualniamy prawa dostępu do bazy.
    create database pgoralik_test; 
    grant all privileges on pgoralik_test.* to sqluser@localhost;
    flush privileges;
    Wyjdźmy i połączmy się nowo utworzonym użytkownikiem - tak dla testu. Następnie wybierzmy bazę danych na której chcemy operować.
    use pgoralik_test 
    Utwórzmy tabelę i dodajemy jakiś jeden rekord. Sprawdźmy czy się udało.
    create table student (NumerIndeksu INT not null auto_increment primary key, 
                          Imie VARCHAR(45), 
                          Nazwisko VARCHAR(45), 
                          GrupaDziekanska INT );
    
    insert into student values(default, 'Jan', 'Kowalski', 21);
    select * from student;
    Myślę, że tyle wystarczy. Umiemy już utworzyć bazę danych dzięki narzędziom dostarczanym przez MySQL. Możemy też oczywiście te zapytania wysyłać z poziomu programu napisanego w Javie i w ten sposób tworzyć bazę. Ale skoro mamy już bazę, to nasz program będzie tylko z niej korzystał.

    Tworzymy aplikację korzystającą z bazy danych MySQL.

    Mamy już pobrany sterownik JDBC. Musimy dodać go do projektu (Project->Properties->Java Build Path->Add external JARs).

    Następnie tworzymy klasę MySQLTest, która korzystając z JDBC będzie wysyłać zapytania do utworzonej wcześniej bazy danych.

    public class MySQLTest {
     // Tworzymy połączenie z bazą danych
     public Connection getConnection() throws SQLException {
         conn = DriverManager.getConnection("jdbc:mysql://" + serverName + ":" + portNumber + "/" + databaseName + 
                                            "?useUnicode=true" +
                                            "&characterEncoding=utf-8" +
                                            "&user=" + userName + 
                                            "&password=" + password);
        
         System.out.println("Connected to database " + databaseName);
         return conn;
     }
     
     Connection databaseConnection;
     String userName = "sqluser", 
            password = "secret",
            serverName = "localhost",
            portNumber = "3306",
            databaseName = "pgoralik_test";
    }

    Dodajmy metodę, która pobierze wszystkie dane z danej tabeli.
     // Wyświetl wszystkie dane z tabeli
     void viewTable(String table) throws SQLException {
      String query = "select NumerIndeksu, Imie, Nazwisko, GrupaDziekanska from " + databaseName + "." + table;
      Statement stmt = null;
      try {
       stmt = databaseConnection.createStatement();
       ResultSet rs = stmt.executeQuery(query);
       // Dopóki zbiór wyników posiada jakieś dane to wypisuj
       while (rs.next()) {
                 int numerIndeksu = rs.getInt("NumerIndeksu");
                 String imie = rs.getString("Imie");
                 String nazwisko = rs.getString("Nazwisko");
                 int grupa = rs.getInt("GrupaDziekanska");
                 
                 System.out.println(numerIndeksu + "\t" + imie + "\t" + nazwisko + "\t" + grupa);
             }
       
      } catch (SQLException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      } finally {
          // Zamknij obiekt Statement, aby natychmiast zwolnić jego pamięć
        if (stmt != null) { stmt.close(); }
      }
     }
    
    Kod wydaje się mówić za siebie. Dorzućmy jeszcze zapis do bazy danych. W przypadku użycia zapytań insert, delete, update używamy Statement.executeUpdate(), który zwraca ilość zmodyfikowanych wierszy.
     void insertNewStudent(String imie, String nazwisko, int grupa) throws SQLException {
      String query = "insert into " + databaseName + ".student values(default, '" + imie + "','" + nazwisko + "'," + grupa + ")";
      Statement stmt = null;
      try {
       stmt = databaseConnection.createStatement(); 
          int rows = stmt.executeUpdate(query);
          System.out.println("Zmodyfikowano " + rows + " wierszy");
      } catch (SQLException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      } finally {
          // Zamknij obiekt Statement, aby natychmiast zwolnić jego pamięć
        if (stmt != null) { stmt.close(); }
      }
     }
    
    Teraz pozostało przetestować naszą klasę.
    public static void main(String[] args) {
      MySQLTest test = new MySQLTest();
      try {
       test.databaseConnection = test.getConnection();
       test.viewTable("student");
       test.insertNewStudent("Van", "Wilder", 123);
       
      } catch (SQLException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
       return;
      }
     }
    
    Widać, że wieczny student został ujęty w spisie studentów, pewnie prędko z niego nie zniknie. W celu głębszego poznania JDBC zachęcam do zapoznania się z odpowiednim tutorialem java w linku poniżej.

    Przydatne linki:
    http://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html - połączenie z bazą danych i inne lekcje
    http://www.pantz.org/software/mysql/mysqlcommands.html - ściągawka z zapytaniami SQL

    4 komentarze:

    1. Warto dodać, że zamiast MySQL można użyć też jego bardziej otwartego forka - MariaDB. Jest tworzony przez pierwotnych twórców MySQL, w pełni z nim kompatybilny, używa się go dokładnie tak samo i nie słychać o jakichś problemach wynikających z jego użycia.

      OdpowiedzUsuń
    2. Dzięki za uwagę. Szczerze mówiąc, nie rozglądałem się za różnymi możliwościami, bo mam z góry narzucone, że mam użyć MySQL. Rozumiem, że skoro MariaDB jest kompatybilny, to MySQL Connector/J też zapewni nam połączenie z tą bazą? Bo na ich stronie jakoś nie widzę czegoś takiego.

      OdpowiedzUsuń
    3. Tak powinno być, bo to jest "drop-in replacement" - wyrzucasz jedno, wrzucasz drugie. http://kb.askmonty.org/en/mariadb-versus-mysql
      Hibernate nie zauważył różnicy. :)

      OdpowiedzUsuń