Kurs Hibernate – część 3 – Binary Large Object Block (BLOB)

Zapraszam na szybki kurs Hibernate. Wspólnie stworzymy cztery proste aplikacje bazodanowe w języku Java wykorzystujące mapowanie obiektowo-relacyjne (Object-Relational Mapping, ORM) za pomocą frameworku Hibernate. W trzeciej części kursu Hibernate zapisywanie bloków dużych obiektów binarnych.

Dla niecierpliwych: Jeśli chcesz szybko uruchomić opisywaną w tej części kursu JDBC aplikację bazodanową, pobierz plik .zip wskazany na końcu tego tekstu, a następnie zajrzyj do mojego artykułu o importowaniu istniejącego projektu z plikiem budowania Apache Ant do Eclipse.

Binary Large Object Block (BLOB)

W pierwszej części kursu JDBC używaliśmy interfejsu java.sql.Statement do wykonywania operacji na bazie danych. Korzystaliśmy z metody executeUpdate(…) do wykonywania operacji zapisujących dane w bazie danych, dokładniej do wstawienia nowych wierszy do tabeli PROGRAMISTA, a także z metody executeQuery(…) do wykonywania operacji pobierających dane z bazy danych, dokładniej do wykonania zapytania do bazy danych pobierającego zawartość tabeli PROGRAMISTA.

Pewną niedogodnością w podejściu z poprzedniej części kursu JDBC jest konieczność zapisania pełnej instrukcji SQL wykonywanej przez metodę interfejsu java.sql.Statement łącznie ze wszystkimi parametrami tej instrukcji, takimi jak wartości pól wstawianych wierszy czy wartości występujące w warunkach wykonywanych zapytań. W prostej aplikacji bazodanowej omawianej w pierwszej części kursu JDBC nie sprawiało to kłopotu, ale w większych aplikacjach bazodanowych takie podejście może być bardzo nieefektywne.

Interfejs java.sql.PreparedStatement

W tej części kursu JDBC zastąpimy interfejs java.sql.Statement interfejsem java.sql.PreparedStatement umożliwiającym wykonywanie parametryzowanych operacji na bazie danych, parametryzowane pobierania i zapisywania danych, oraz wykonywanie parametryzowanych instrukcji SQL.

Obiekt interfejsu java.sql.PreparedStatement otrzymuje się zazwyczaj w aplikacji bazodanowej w języku Java przez wywołanie metody prepareStatement(…) interfejsu java.sql.Connection z parametrem będącym łańcuchem znaków reprezentującym instrukcję SQL do wykonania, w którym występują znaki zapytania w miejscach występowania parametrów. Przykładowo, instrukcja conn.prepareStatement(„INSERT INTO programista(imie, nazwisko) VALUES (?, ?)”) tworzy obiekt interfejsu java.sql.PreparedStatement odpowiadający instrukcji SQL wstawiającej nowe wiersze do tabeli PROGRAMISTA z dwoma parametrami: pierwszy z parametrów odpowiada imieniu programisty, a drugi z parametrów odpowiada nazwisku programisty.

Przed wykonaniem parametryzowanej operacji na bazie danych należy ustawić wartości parametrów za pomocą właściwych metod interfejsu java.sql.PreparedStatement. Przykładowo, instrukcja pstmt.setString(1, „Andrzej”); ustawia wartość pierwszego parametru instrukcji SQL odpowiadającej obiektowi pstmt na Andrzej.

Operacje w bazie danych

Upewniwszy się, że w bazie danych wciąż istnieje tabela PROGRAMISTA utworzona w pierwszej części kursu JDBC, możemy przystąpić do napisania programu w języku Java z wykorzystaniem interfejsu JDBC, który wykona parametryzowane operacje bazodanowe na tabeli PROGRAMISTA. Całość programu zaimplementujemy w metodzie main klasy KursJDBC03, zapisanej oczywiście w pliku KursJDBC03.java. Dokładny kod całej klasy przedstawiam poniżej.

package pl.iprogramujesz.bazy.danych.kurs.jdbc;

import java.io.*;
import java.sql.*;

/*
	UWAGA 1: Przed kompilowaniem programu nalezy sprawdzic czy ustawienia polaczenia z baza danych sa poprawne (wiersz 15).
	UWAGA 2: Przed uruchomieniem programu nalezy utworzyc w bazie danych tabele PROGRAMISTA. Mozna zrobic to za pomoca nastepujacej instrukcji SQL (dla serwera baz danych PostgreSQL): CREATE TABLE programista (id SERIAL PRIMARY KEY, imie VARCHAR(80), nazwisko VARCHAR(80), zdjecie BYTEA);
	UWAGA 3: Przed uruchomieniem programu nalezy zmienic sciezke do przykladowego pliku ze zdjeciem (wiersz 27).
*/

public class KursJDBC03 {

	public static void main(String[] args) {
		try {
			DriverManager.registerDriver(new org.postgresql.Driver());
			Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres", "postgres", "iProgramujesz.pl");

			PreparedStatement pstmt = conn.prepareStatement("INSERT INTO programista(imie, nazwisko, zdjecie) VALUES (?, ?, ?)");

			pstmt.setString(1, "Andrzej");
			pstmt.setString(2, "Kowalski");

			File zdjecie = new File("D:\\iProgramujesz\\zdjecie.jpg");
			InputStream strumienWczytujacyZdjecieZPliku = new FileInputStream(zdjecie);
			pstmt.setBinaryStream(3, strumienWczytujacyZdjecieZPliku, (int) zdjecie.length());

			pstmt.executeUpdate();

			strumienWczytujacyZdjecieZPliku.close();

			pstmt.close();

			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("SELECT * FROM programista");
			while(rs.next()) {
				System.out.println(rs.getString("imie") + " " + rs.getString("nazwisko"));
				InputStream strumienWczytujacyZdjecieZBazyDanych = rs.getBinaryStream("zdjecie");
				OutputStream strumienZapisujacyZdjecieDoPliku = new FileOutputStream("D:\\iProgramujesz\\Programista" + rs.getInt("id") + ".jpg");
				byte[] bufor = new byte[1024];
				int k = strumienWczytujacyZdjecieZBazyDanych.read(bufor, 0, 1024);
				while(k != -1) {
					strumienZapisujacyZdjecieDoPliku.write(bufor, 0, k);
					k = strumienWczytujacyZdjecieZBazyDanych.read(bufor, 0, 1024);
				}
				strumienZapisujacyZdjecieDoPliku.close();
				strumienWczytujacyZdjecieZBazyDanych.close();
			}
			rs.close();
			stmt.close();

			conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Podsumowanie trzeciej części kursu JDBC

Jako podsumowanie tej części kursu JDBC, przygotowałem plik .zip zawierający całość aplikacji bazodanowej z JDBC. Jeśli nie wiesz jak szybko uruchomić pobraną aplikację przeczytaj mój artykuł o importowaniu istniejącego projektu z plikiem budowania Apache Ant do Eclipse.