Jak łączyć się z bazą danych na poziomie aplikacji - przykłady

Poniżej zamieszczam krótki i jak najprostsze przykłady na to jak w róznych językach programowania zrealizować połączenie do bazy danych

Przykładowa baza danych

W przykładach uzyjemy bazy danych MSSQL Server Express Edition, którą w wersji 2008 można ściągnąć stąd: MSSQL Server. Najlepiej ściągnąć wersję WT (With Tools), dzięki czemu będziemy mieli dostęp do Managment Studio.

Po zainstalowaniu wyonujemy następujący skrypt, mając uprawnienia admina. Z jakiś względów w Windows 7 (nie wiem jak w XP i Viscie) może pojawić się problem, że będziemy mieli uprawnienia dbo (database owner), tylko jesli uruchomimy Managment Studio jako admin (prawym klawisze, uruchom jao administrator). Można to obejść, stosując rozwiązanie stąd: Blog MSDN, Dariusz Parys. Jakkolwiek sobie ztym nie poradzimy należy wykonać następujący kod:


create database test
go

use test
go

create table t1(
	id INT PRIMARY KEY IDENTITY,
	nazwa VARCHAR(256),
	ilosc INT
)
go

create procedure sp_add_to_t1(@nazwa VARCHAR(256), @ilosc INT, @lastId smallint OUTPUT)
as
	begin tran
	insert into t1(nazwa, ilosc) values(@nazwa, @ilosc)
	select @lastId = max(id) from t1
	commit
go

declare @lastId INT
EXEC sp_add_to_t1 'Blabla', 10, @lastId OUTPUT
print @lastId
EXEC sp_add_to_t1 'Nabla', 20, @lastId OUTPUT
print @lastId

Poniżej znajdują się przykłądy dla różnych języków (PHP, Java, C#, Python). Serdecznie przepraszam, jesli Państwa ulubionego języka na liście nie będzie. Jesli ktoś chciałby aby takowy się pojawił, zachęcam do przeprowadzenia poszukiwan w sieci i stworzenia podobnego poradnika - z chęcią umieściłbym go na stronie za zgodą autora.

PHP

Aby móc testować aplikacje napisane w PHP możemy zainstalować serwer Apache, bardzo prostym i szybkim sposobem na testowanie jest XAMPP dla Windows lub LAMPP dla linux, które można pobrać stąd: XAMPP Home Page (Użytkownicy linux mogą użyć do instalacji narzedzi typu apt, aptitude, itp) Razem z xampp otrzymujemy bazę danych mysql, której także można uzyć w projekcie, chociaż ze względu na to że omawialiśmy głównie MSSQL Server i to że ten ostatni wspiera trochę lepiej procedury składowane i triggery to do projektu polecałbym to rozwiązanie.

Lista obsługiwanych baz wraz z listami funkcji PHP:
http://www.php.net/manual/en/refs.database.vendors.php

lista funkcji związanych z MySQL Server w PHP:
http://www.php.net/manual/en/ref.mysql.php

Jeśli ktoś nie zetknął się nigdy z PHP warto poczytać do czego on służy:
http://pl.wikipedia.org/wiki/PHP
i pomyśleć o przeczytaniu jakiegoś tutorialu:
PHP na w3schools

Po zainstalowaniu xampp, sprawdzamy czy działa. Należy uruchomić apache'a: z katalogu w którym zainstalowaliśmy xampp należy uruchomić (windows) apache_start.bat lub z paska narzędzi ikonka httpd. W linuxie powinien zainstalowac się jako proces i biec w tle, ale jesli trzeba można go uruchomić httpd -k start (najlepiej poczytać man httpd).

Wchodzimy do katalogu (katalog instalacyjny xampp, w skrócie dalej nazwany XAMPP_HOME)/htdocs, tworzymy nowy katalog np. o nazwie test a w nim plik o nazwie index.php (możemy stworzyć plik o innej nazwie np. test.php ale wtedy inaczej odniesiemy się do naszego pliku w przeglądarce). Edytujemy plik i wpisujemy kod:


	<?
		echo ("Hello world!");
	?>
	
Uruchamiamy przeglądarkę i wpisujemy: localhost/test (localhost/test/test.php jeśli nadaliśmy plikowi nazwę test zamiast index). Powinno w przeglądarce pojawić się hello world!.

Aby mozna się było łaczyć z bazą MS SQL potrzebujemy sterownika. Niestety domyślny sterownik nie jest wspierany od wersji PHP 5, więc musimy skorzystać z czegoś innego.

Pobieramy Microsoft Drivers for PHP for SQL Server. Instalujemy, wybierając podczas instalacji miejsce folderu rozszerzeń PHP. Domyślnym miejcem jest (XAMPP_HOME)/php/ext, tak więc ten katalog wybieramy. Po zainstalowaniu przechodzimy do tego katalogu - znajdziemy w nim plik pomocy SQLSRV_Help.chm - bardzo przydatny przy pracy z tym sterownikiem.

Ostatnią rzeczą jaką musimy zrobić, to zmodyfikować plik php.ini w katalogu (XAMPP_HOME)/php. Nalezy w nim znaleźć miejsce w którym jest wiele wpisów postaci extension=nazwa_pliku.dll. Najlepiej na samym dole listy dodać jeszcze jeden wpis: extension=php_sqlsrv_53_ts_vc9.dll (numerki w nazwie pliku oznaczają wersje PHP - dla XAMPPa działa wpis który podałem, dla własnych instalacji - może trzeba będzie wybrać inny)

Restartujemy Apache'a z paska zadań można włączyć ikonkę HTTPD i kliknąc stop a nastpnie start (z linii komend to pewnie httpd -k restart).

Teraz już możemy nawiązać połączenie z bazą danych, pobierać dane i wyświetlać w tabelce na stronie (podmień kod w pliku index.php):

<!-- początek pliku index.php -->
<?
	//nazwa komputera\nazwa instancji 
	//(domyslna nazwa instancji = SQLEXPRESS)
	$server = 'MACHINAZAGLADY4\SQLEXPRESS';
	//$server = '(local)';
	
	//user dodany tak jak robiliśmy to na pierwszych zajęciach 
	//(w zakładce Security\Logins w Management Studio)
	$user = 'test';
	//hasło do powyższego konta
	$pass = 'tajnehaslo';
	
	$connectionInfo = array( "UID"=>$user,
				"PWD"=>$pass,
				"Database"=>"test");		

	// Connect to MSSQL
	$link = sqlsrv_connect( $server, $connectionInfo);

	if (!$link) {
		//die(komunikat) - zakończ skrypt z komunikatem
		die('Nie udało się połączyć');
	}
?>
<html>
<head>
	<title>PHP + MS SQL</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>

<body>
	Można mieszać PHP z html. Tam gdzie chcemy wywołać 
	kod PHP umiesczamy znaczniki <? i ?> a 
	wewnątrz nich kod PHP.
	<table>
	<tr><th>Id</th><th>Nazwa</th><th>Ilość</th></tr>
	<?
		//kod php może być podzielony na kilka bloków - wszystkie zmienne
		//które zadeklarowaliśmy wczesniej i wszystkie operacje
		//które wykonaliśmy nadal są aktywne
	
		// wybierz wszystko z tabeli t1
		$dataset = sqlsrv_query($link, 'SELECT * FROM t1');
		$row = sqlsrv_fetch_array($dataset);
		while($row){
			echo ("<tr><td>{$row[0]}</td><td>{$row[1]}</td><td>{$row[2]}</td></tr>");
			$row = sqlsrv_fetch_array($dataset);
		}
		//warto posprzątać po sobie
		sqlsrv_free_stmt($dataset);
	?>
	</table>
	Poniżej wyświetlamy formularz wstawiania nowych danych, 
	formularz pozwala wyslac dane do serwera Apache, 
	przekazując dane w postaci par klucz-wartość: kluczem jest 
	to co wpiszemy w atrybucie 'name' danego pola, a wartoscią 
	będzie to co użytkownik wpisze w to pole. Formularz może 
	mieć określoną akcję - stronę (skrypt PHP) który zostanie 
	wywołany oraz method, oznaczający sposób wysłania danych. 
	Dostępne są dwa sposoby wysłania danych: POST i GET.<br/>	
	<form action = "index.php" method = "POST">
		Nazwa: <input type = "text" name = "pole_nazwa"/> <br/>
		Ilość: <input type = "text" name = "pole_ilosc"/><br/>
		<input type = "submit" value = "dodaj">
	</form>
	<?
		//a tu kod obsługujący. Tak naprawdę powinien być
		//na samej górze strony, ale ze względów dydaktycznych
		//umieściłem go na dole. Z tego powodu wstawiony wiersz
		//będzie widoczny w tabeli dopiero po odświeżeniu strony.
		
		//dane podane przez uzytkownika wyciagamy z tabeli request
		//podajac nazwy pól z formularza
		$nowy_nazwa = $_REQUEST['pole_nazwa'];
		$nowy_ilosc = $_REQUEST['pole_ilosc'];
		
		//sprawdzamy czy user podał dane
		if ($nowy_nazwa && $nowy_ilosc){
			//tak można wykonać procedurę składowaną z paramtrami
			//zwrócić uwagę nalezy na ? zamiast nazw parametrów
			$tsql = "{call sp_add_to_t1(?, ?, ?)}";
			//zdefinuj nową zmienną na parametr zwracający dane
			$lastId = 4; //trzeba zainicjalizować go na wartośc typu jaki ma być zwrócony. 
			//Uwaga: Nie wolno na null, albo pozostawiać niezainicjalizowanego

			//ustal parametry jako tablicę dwuelementowych tablic
			$params = array(
					array($nowy_nazwa, SQLSRV_PARAM_IN), //standardowy parametr
					array($nowy_ilosc, SQLSRV_PARAM_IN), //standardowy parametr
					array($lastId, SQLSRV_PARAM_OUT), //ten będzie parametrem OUT
				);            
			//wykonaj zapytanie
			$result = sqlsrv_query($link, $tsql, $params);
			if (!$result){
				//tak można wypisać błędy które się pojawiły
				die( print_r( sqlsrv_errors(), true));
			}
			//ta linijka jest potrzebna, aby pozbyć się 
			//wszlekich zalegających danych, tylko tak pojawi 
			//się wartośc parametru OUT
			while(sqlsrv_next_result($result)){};
			//wyświetl info
			echo ('Dodano wiersz o id = ' . $lastId);
		}
	?>
</body>
</html>
<?
		// na koniec warto zamknąc połączenie		
		sqlsrv_close( $link);
?>
<!-- koniec pliku index.php -->

O formatkach w HTML mozna poczytać np. tutaj (w3schools). Teraz możemy zacząć budować naszą własną aplikację internetową!

Java

ABy skorzystać z mozliwości łaczenia się z bazą danych danego producenta zazwyczaj należy zaopatrzyć się w konkretne sterowniki. Co ciekawe kod łaczenia się z bazą danych będzie zazwyczaj taki sam dla wszystkich dostawców, jedyne co należy wymienić to sterownik (o ile nie chcemy korzystać ze specyficznych dla danej bazy danych funkcjonalności - wtedy należy zrezygnować z korzystania z DriverManager i napisać cały kod ręcznie).

Sterowniki dostępu do baz danych dla Javy nazywane są JDBC i jesli ktoś chce się połaczyć z jakąś bazą danych najczęsciej poszukuje w google słów [nazwa bazy danych] JDBC, a google zazwyczaj wyświetla stronę ze sterownikami jak i wiele tutoriali jak ich użyć. Najpopularniejsze sterowniki dla baz danych:

Prosta aplikacja wykorzystująca GUI Swing

Poniżej znajduje się kod aplikacji okienkowej komunikującej się z bazą danych. Projekt NetBeans można pobrać tutaj i od razu skompilować (oczywiście po dodaniu brakujących bibliotek - linki do pobrania znajują się powyżej - nalezy pobrać MS SQL Server Driver Microsoftu lub jTDS Driver).

Pobierz projekt NetBeans

UWAGA biblioteki dodajemy najprościej (w obu typach projektów) klikając w katalog Libraries prawym klawiszem i wybierając Add jar/folder


/*
 * TestForm.java
 *
 * Created on 2012-01-18, 14:02:18
 */
package test;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Types;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

/**
 * @author Robson
 */
public class TestForm extends javax.swing.JFrame {
    //nazwa użytkownika
    //nie Windows Authentication - trzeba go stworzyć w Security/Logins
    //oraz nadać mu uprawnienia odpowiednie do bazy danych test
    //dodatkowo w przykłądzie zakłądamy, że została dla niego ustawiona
    //default baza danych jako test
    String dbUser = "test";
    //hasło dla usera
    //tworząc hasło w Security/Logins warto wyłaczyć Enforce password policy
    //w przeciwnym wypadku system nie pozwoli na tak proste hasło
    String dbPass = "tajnehaslo";
    //adres bazy danych - nazwa_komputera\nazwa_instancji
    //domyślna nazwa instancji dla MS SQL Server Express Edition to SQLEXPRESS
    String dbAddress = "MACHINAZAGLADY4\\SQLEXPRESS"; //jesli używamy MS SqL Driver
    //String dbAddress = "MACHINAZAGLADY4;instance=SQLEXPRESS"; //jesli używamy jTDS Driver, 
					//przy czym domyślna instancja nie działa - nalezy użyć samej nazwy servera
    //String dbAddress = "MACHINAZAGLADY4"; //jesli używamy jTDS Driver dla domyślnej instancji
    //Nazwa klasy sterownika JDBC i string wyboru sterownika - dwie linnie dla każdego z typu sterowników!
    String dbDriverClass = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; //jesli uzywamy MSSQL Driver
    String dbDriverSelect = "jdbc:sqlserver://";//jesli uzywamy MSSQL Driver
    //String dbDriverClass = "net.sourceforge.jtds.jdbc.Driver"; //jeśli używamy jTDS driver
    //String dbDriverSelect = "jdbc:jtds:sqlserver://"; //jeśli używamy jTDS driver

    Connection connection = null;

    //pomocnicza funkcja - pobiera wszystkie dane z tabeli
    void refreshTable() {
		try {
			//tworzymy obiekt zapytań (statement)
			Statement statement = connection.createStatement();

			//tworzymy dane dla tabeli - tzw. Model
			//dla ciekawskich: można poczytać o idei Model-View-Controller w Swing
			Statement countStmt = connection.createStatement();
			ResultSet countRs = countStmt.executeQuery("select count(*) from t1");
			countRs.next();
			TableModel model = new DefaultTableModel(new String[]{"Id", "Nazwa", "Ilosc"}, 
									countRs.getInt(1));
			//UWAGA DO POWYŻSZEGO:
			//niestety DefaultTableModel - jedyny model dla tabeli domyślnie
			//dostępny w javie nie może mieć zmiennej ilości wierszy...
			//(dużo) lepszym rozwiązaniem byłoby zrobienie własnego modelu
			//przykład jak to zrobić jest tutaj:
			//http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data
			//Table model (i Column model) pozwala na bardzo dużą swobodę w tym co
			//można umieszczać w tabeli, możemy przykłądowo
			//umiescić w komórce nawet cały JPanel z przyciskami, polami edycji itp.
			//to jest związane z ideą MVC w Swing

			//wywołujemy zapytanie
			ResultSet rs = statement.executeQuery("select * from t1");
			//pobieramy ilośc elementów (uwaga na batch'e!)	    	    

			int i = 0;
			//pobieramy wszystkie dane
			while (rs.next()) {
			//rs.next przesuwa kursor o jedną pozycję dalej, przy czym na
			//początku pozycja jest przed pierwszą daną (tak jakby na -1)
			//dzięki temu pętla wyciągająca dane jest prostsza

			int id = rs.getInt(1); //możemy pobierać po numerze kolumny
			int ilosc = rs.getInt("ilosc");  //albo po nazwie pola (zalecane)
			String nazwa = rs.getString("nazwa"); //warto określić jaki typ danych chcemy pobrać 
								//(nie trzeba potem rzutować)

			//UWAGA: we własnym TableModel można poniższe rozwiązać ładniej!
			model.setValueAt(id, i, 0);
			model.setValueAt(nazwa, i, 1);
			model.setValueAt(ilosc, i, 2);

			i++;
			}
			mainTable.setModel(model);
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    /** Creates new form TestForm */
    public TestForm() {
		initComponents();
		try {
			Class.forName(dbDriverClass);
			System.out.println("Connection string := "+dbDriverSelect + dbAddress);
			connection = DriverManager.getConnection(dbDriverSelect + dbAddress, dbUser, dbPass);
		} catch (Exception e) {
			System.out.println("Nie udało się połączyć: ");
			e.printStackTrace();
		}
		refreshTable();
    }   

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
		// TODO add your handling code here:
		String nazwa = nazwaText.getText();
		int ilosc = -1;
		try {
			ilosc = Integer.parseInt(iloscText.getText());
		} catch (Exception e) {
			//gdyby ktoś źle wpisał, możemy dac mu znać
			JOptionPane.showMessageDialog(this, "Niepoprawna watość!");
			return;
		}

		try {
			//callable statement słuzy do wywoływania funkcji i procedur
			//jeśli chcemy wywołać funkcję, która zwraca skalar
			//możemy to zrobić pisząc jako parametr
			//"{call ? = sp_add_to_t1(?, ?, ?)}"
			//i zmieniając typ pierwszego parametru na OUT (zobacz poniżej)
			CallableStatement statement = connection.prepareCall("{call sp_add_to_t1(?, ?, ?)}");
			//ustaw pierwszy parametr (zwróć uwagę na typ)
			statement.setString(1, nazwa);
			//ustaw drugi parametr (zwróc uwagę na typ)
			statement.setInt(2, ilosc);
			//ustaw 3 parametr jako OUT (zwracający dane)
			statement.registerOutParameter(3, Types.INTEGER);
			//wykonaj zapytanie (wszystkie parametry musza być określone inaczej exception)
			statement.execute();
			//pobierz zwróconą wartość
			int id = statement.getInt(3);
			//wyświetl ją
			JOptionPane.showMessageDialog(this, "Dodano nowy wiersz o id = " + id);
			//odswież tabelę
			refreshTable();
			//gdyby procedura zwróciła jakieś dane to można je tu jeszcze pobrać
			//while (rs.next()) {
			//}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }//GEN-LAST:event_addButtonActionPerformed



	//KOD PONIŻEJ ZOSTAŁ WYGENEROWANY AUTOMATYCZNIE PRZEZ EDYTOR NETBEANS
	//wyrzuciłem jego część, gdyż nie wnosi nic do projektu, a tylko zaciemnia i 
	//rozciąga stronę - kompilujący się kod można pobrać z linku na mojej stronie
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {

			public void run() {
			new TestForm().setVisible(true);
			}
		});
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addButton;
    private javax.swing.JTextField iloscText;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable mainTable;
    private javax.swing.JTextField nazwaText;
    // End of variables declaration//GEN-END:variables
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // &lt;editor-fold defaultstate="collapsed" desc="Generated Code"&gt;//GEN-BEGIN:initComponents
    private void initComponents() {

        //... (tutaj wyciąłem kod budujący formatkę)
        
    }// &lt;/editor-fold&gt;//GEN-END:initComponents
}

Technologia Java Servlet (J2EE)

Projekt NetBeans można pobrać tutaj i od razu skompilować (oczywiście po dodaniu brakujących bibliotek - linki do pobrania znajują się powyżej - nalezy pobrać MS SQL Server Driver Microsoftu lub jTDS Driver).

UWAGA biblioteki dodajemy najprościej (w obu typach projektów) klikając w katalog Libraries prawym klawiszem i wybierając Add jar/folder

Pobierz projekt Netbeans

Nie będę wklejał całego kodu tutaj, gdyż jest już bardziej skomplikowany i podzielony siłą rzeczy (technologii JSP) na wiele plików. Najwazniejsze to zapamiętać:

  • Za przetwarzanie danych odpowiedzialny jest tzw. servlet, który następnie zwraca informację której strony użyć aby wyświetlić dane. Przetwarzanie danych następuje w jednej z funkcji: doPost(), doGet() lub doRequest() (w uproszczeniu).
  • Jako return z powyższych funkcji zwracamy nazwę zarejestrowanej strony w pliku web.xml
  • web.xml jest plikiem konfiguracyjnym aplikacji napisanej w technologii JSP (i w innych JavaEE też), znajduje się w katalogu WEB-INF
  • początkujący programiści najlepiej zrobią jeśli będą używać początkowo widoku czystego xml edytując plik web.xml - jest dużo łatwiej coś skopiować/wkleić itp niż próbować rozumieć o co chodzi w tych kreatorach Netbeansa, zapewniam.
  • Aby uruchomić projekt klikamy prawym klawiszem i dajemy Run. Czasem warto zrobic operację Rebuild all i dopiero potem Run, co sprawi że projekt zostanie w całości wysłany na serwer a nie tylko zmiany - czasem Netbeans może nam 'zepsuć' projekt na serwerze wysyłając tylko zmiany, gdy nie rozpozna że coś zmieniło się w jakimś pliku
  • pierwsze uruchomienie może trwać długo - ponieważ startuje wbudowany server www - glasfish. Jesli coś nam nie działa w aplikacji warto przejżeć logi serwera - znajdują się w jednej z zakładek, którą otwiera Netbeans podczas uruchamiania projektu.
  • nalezy upewnić się, że posiada się Netbeans'a z JavaEE - ożna to rozpoznać po tym, że w New project mamy zakładki Java Web i Java EE
  • jesli chcemy stworzyć nowy projekt od zera polecam zacząć od Java Web/Web application. Java EE może okazać się trochę zbyt abstrakcyjna na początek...

Poniżej zamieszczam krótki poradnik, jak dodac nową funkcję w przykładowej aplikacji.

Powiedzmy, że chcemy dodać opcję wyszukiwania po nazwie w naszej tabeli T1. Wykonując poniższe instrukcje nalezy pamiętać o pojawiających się żaróweczkach z informacjami o błędach - pozwalają one bardzo łatwo usunąc te błędy, zazwyczaj wybieramy po prostu klikając w nie pierwszą proponowaną podpowiedź (choć czasem warto się na chwilę zatrzymać i zastanowić, szczególnie gdy mamy bardzo wiele podpowiedzi).

  1. Klikamy prawym klawiszem na nazwie pakietu z servletami i klikamy New->Servlet... (jesli nie ma go na liście to Other... i znajdujemy go w odpowiedniej zakładce). pisujemy nazwę jaka się nam podoba np. SearchServlet, klikamy next. W następnym okienku możemy skonfigurować plik web.xml dla naszego servletu. Zaznaczamy add information to application descriptor (web.xml) (lub podobnie brzmiący checkbox). Wypełniamy: servlet name (dowolny, może być taki jak nazwa klasy), URL patterns - tutaj wpisujemy jaki ma być adres servletu - to jest wazne, gdyż to będziemy zwracać jako return w innych servletach, które będą chciały wywołać ten servlet, np. na stronie JSP w atrybucie action formatki HTML. Klikamy finish.

  2. Pojawia się klasa servletu z funkcją processRequest() którą nalezy uzupełnić. Jesli jestesmy ciekawscy możemy rozwinąć ukryte częscie przez Netbeans'a i zobaczyć że processRequest jest wywoływany przez doPost() i doGet() (jak myślisz, dlaczego?).

    Wpiszmy następujący kod:

    
    String pole_nazwa;
    if ((pole_nazwa = request.getParameter("pole_nazwa")) != null) {
    	Database db = new Database();
    	List<EncjaT1> lista = db.findAll(pole_nazwa);
    	HttpSession s = request.getSession();
    	s.setAttribute("found", lista);
    }
    
    response.sendRedirect("SearchView");
    		
    Kod nie będzie chciał się skompilować, gdyż nie ma funkcji findAll w Database.
  3. Dodajemy funkcję findAll() w Database (Klasa jest pakiecie model):
    
    public List<EncjaT1> findAll(String szukana) {
    	List<EncjaT1> ret = new LinkedList<EncjaT1>();
    	try {
    	    //tworzymy obiekt zapytań (statement)
    	    Statement statement = connection.createStatement();
    	    //wywołujemy zapytanie, wklejanie zmiennych w zapytanie w ten sposób 
    	    //jest bardzo złą praktyką - lepiej zrobić funkcję 
    	    //składowaną i zrobić callable statement lub jeśli już musimy robić 
    	    //zapytanie, to wykorzystać PreparedStatement 
    	    //(poczytać w dokumentacji)
    	    ResultSet rs = statement.executeQuery("select * from t1 where nazwa = '" + szukana + "'");
    	    //pobieramy ilośc elementów (uwaga na batch'e!)
    	    while(rs.next()){
    		int id = rs.getInt(1);
    		String nazwa = rs.getString(2);
    		int ilosc = rs.getInt(1);
    		ret.add(new EncjaT1(id, ilosc, nazwa));
    	    }
    	} catch (Exception e) {
    	    e.printStackTrace();
    	}
    	return ret;
    }
    		
  4. teraz tworzymy ostatni element - widok wyświetlający dane. Klikamy w folder WEB-INF i wybieramy New->JSP, nazywamy ją searchview. W sekcji <body> wpisujemy:

    
    <form action = "SearchServlet" method = "POST">
    	Nazwa: <input type = "text" name = "pole_nazwa"/> <br/>
    	<input type = "submit" value = "szukaj">
    </form>
    <table>
    <tr><th>Id</th><th>Nazwa</th><th>Ilość</th></tr>
    <%
    	List<EncjaT1> tabelaT1 = (List<EncjaT1>)session.getAttribute("found");
    	if (tabelaT1!=null){	        
    		for (EncjaT1 encja : tabelaT1){
    			out.print("<tr><td>"+encja.getId()
    					+"</td><td>"+encja.getNazwa()
    					+"</td><td>"+encja.getIlosc()
    					+"</td></tr>");
    		}
    	}
    %>
    </table>
    

    Teraz zostaje dodać informacje do deskryptora projektu (web.xml), aby zadziałał ładnie redirect w servlecie.

    W pliku web.xml dodajemy linie

    
    <servlet>
    	<servlet-name>SearchView</servlet-name>
    	<jsp-file>/WEB-INF/searchview.jsp</jsp-file>
    </servlet> 
    <servlet-mapping>
    	<servlet-name>SearchView</servlet-name>
    	<url-pattern>/SearchView</url-pattern>
    </servlet-mapping>   
    
    Znaczenia poszczególnych wpisów można się domyśleć. Servlet-mapping pozwala przypisywac servletom ładne url-e, natomiast znacznik servlet pozwala definiować servlety poprzez podanie ich klasy lub strony jsp z kórej będą wygenerowane.

  5. Rozwiązujemy wszystkie problemy z żaróweczkami Netbeansa i kompilujemy projekt, uruchamiamy i patrzymy czy działa wisując do paska adresu adres strony szukania: http://localhost:8080/JSPServletWithMSSQL/SearchView, JSPServletWithMSSQL to nazwa naszej aplikacji, a /SearchView to ładny, zdefiniowany w web.xml URL dla strony.

Nie jest to jedyne rozwiązanie - można je łatwiej nawet zrobić pisząc kod servletu wyszukującego w stronie JSP, ale chciałem pokazać jak mozna to zrobić w pełnej krasie.

C#

Poniżej znajduje się kod aplikacji okienkowej komunikującej się z bazą danych. Projekt Visual Studio można pobrać tutaj i od razu skompilować. Visual Studio Express Edition można pobrać tutaj: Visual Studio 2008 Express Edition - nalezy pobrać paczkę vcssetup.exe. Mozna tez zainstalować sobie lepszą wersję z MSDNAA na naszej uleczelni: http://msdn.ii.uj.edu.pl.

Za pomoc w stworzeniu tego materiału chciałbym podziękować panu Szymonowi Stawickiemu.

Pobierz projekt VS2008

Poniżej kod:


public partial class Form1 : Form
{
	//to jest porzebne, aby wyświetlić dane w tabelce
	private BindingSource bindingSource1 = new BindingSource();

	//ten connection string pozwala łączyć się poprzez windows authentication i co ciekawe - działa :)
	//ale to pewnie dlatego, że korzystamy w całości z technologii firmy Microsoft :)
	string strConnection = 
		@"Provider=SQLOLEDB.1;Integrated Security=SSPI;Data Source=MACHINAZAGLADY4\SQLEXPRESS;Initial Catalog=test";
	//a to pozwala łaczyć się tak jak w pozostałych przypadkach
	//string strConnection = 
	//	@"Provider=SQLOLEDB.1;Password=tajnehaslo;Persist Security Info=True;"+
	//	"User ID=test;Data Source=MACHINAZAGLADY4\SQLEXPRESS;Initial Catalog=test";

	//tworzy tabelkę z danymi - dodaje kolumny itp.
	public void tableInit()
	{
		//aby nie tworzył sam kolumn
		//czasem C# potrafi sam je zrobić np. na podstawie danych z tabeli z 
		//bazy danych, ale tym razem robimy to sami - gdyż korzystamy z obiektów 
		//a nie z klasy DataSet'u (dla ciekawskich - można o tym poczytać)
		dataGridView1.AutoGenerateColumns = false;
		dataGridView1.AutoSize = false;
		dataGridView1.DataSource = bindingSource1;

		//nowa kolumna
		DataGridViewColumn columnId = new DataGridViewTextBoxColumn();
		columnId.DataPropertyName = "Id";
		columnId.Name = "ID";
		dataGridView1.Columns.Add(columnId);

		//nowa kolumna
		DataGridViewColumn columnNazwa = new DataGridViewTextBoxColumn();
		columnNazwa.DataPropertyName = "Nazwa";
		columnNazwa.Name = "Nazwa";
		dataGridView1.Columns.Add(columnNazwa);

		//nowa kolumna
		DataGridViewColumn columnIlosc = new DataGridViewTextBoxColumn();
		columnIlosc.DataPropertyName = "Ilosc";
		columnIlosc.Name = "Ilość";
		dataGridView1.Columns.Add(columnIlosc);

		//dodajemy testowy obiekt
		bindingSource1.Add(new EncjaT1(0, "TEST", 123));
	}

	//łączy się z bazą i wypełnia tabelkę danymi
	public void refreshTable()
	{
		//jak widać z poniższego 
		OleDbConnection connection = null;
		OleDbDataReader reader = null;

		try
		{
			//tworzymy połączenie
			connection = new OleDbConnection(this.strConnection);

			//łączymy się
			connection.Open();

			//tworzymy nowe polecenie
			OleDbCommand command = new OleDbCommand("SELECT id, nazwa, ilosc FROM T1", connection);
			reader = command.ExecuteReader();

			//wyczyśmy stare dane
			bindingSource1.Clear();

			//czytamy dane
			while (reader.Read())
			{
				//w C# kolumny numerowane od zera...
				int id = reader.GetInt32(0);
				string nazwa = reader.GetString(1);
				int ilosc = reader.GetInt32(2);
				bindingSource1.Add(new EncjaT1(id, nazwa, ilosc));
			}
		}

		catch (Exception e)
		{
			MessageBox.Show(e.Message, "Error",
			MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}

		finally
		{
			connection.Close();
			reader.Close();
		}
	}

	public void addNewtoT1(){

		OleDbConnection connection = null;

		string nazwa = textBox1.Text;
		int ilosc = -1;
		try
		{
			ilosc = int.Parse(textBox2.Text);

			//nowe połączenie
			connection = new OleDbConnection(this.strConnection);
			connection.Open();

			//procedura
			OleDbCommand command = new OleDbCommand("sp_add_to_t1", connection);
			command.CommandType = CommandType.StoredProcedure;

			//parametry
			command.Parameters.Add("@nazwa", OleDbType.VarChar, 256);
			command.Parameters.Add("@ilosc", OleDbType.Integer);
			command.Parameters.Add("@lastId", OleDbType.SmallInt);

			//wartości
			command.Parameters["@nazwa"].Value = nazwa;
			command.Parameters["@ilosc"].Value = ilosc;
			command.Parameters["@lastId"].Direction = ParameterDirection.Output; //kierunek
		
			//wywołujemy coś, co nie zwraca danych - mówimy systemowi żeby nie zwracał resultSeta (readera)
			command.ExecuteNonQuery();
			//pobieramy zwróconą wartość
			string lastId = command.Parameters["@lastId"].Value.ToString();

			MessageBox.Show(lastId, "Dodano", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}
		catch (Exception e)
		{
			MessageBox.Show(e.Message, "Error",
							MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}
	}

	public Form1()
	{
		InitializeComponent();
		//wywołujemy stworzenie struktury tabelki
		tableInit();
		//wypełniamy tabelkę
		refreshTable();
	}

	private void button1_Click(object sender, EventArgs e)
	{
		addNewtoT1();
		refreshTable();
	}
}

public class EncjaT1
{
	public string Nazwa { get; set; }
	public int Id { get; set; }
	public int Ilosc { get; set; }

	public EncjaT1()
	{
	}

	public EncjaT1(int id, string nazwa, int ilosc)
	{
		this.Nazwa = nazwa;
		this.Id = id;
		this.Ilosc = ilosc;
	}
}

Python

W budowie