Friday, March 22, 2013

SQLite PHP tutorial

This is a PHP programming tutorial for the SQLite database. It covers the basics of SQLite programming with PHP language. There are two ways to code PHP scripts with SQLite library. We can use procedural functions or OOP objects and methods. In this tutorial, we use the classical procedural style. You might also want to check the PHP tutorial , SQLite tutorial or SQLite Perl tutorial on ZetCode.

Installation

To work with this tutorial, you must install several packages. The apache2, libapache2-mod-php5, php5-sqlite packages. sqlite command line tool is optional, but recommended.
The document root directory is a directory, where you place your html and php files. It is a place, where the apache server looks for the files, that make up the web site.
The document root for apache2 server can be changed at /etc/apache2/sites-available/default file. This is for Ubuntu.
DocumentRoot /var/www/
This is a portion of the above mention configuration file. The default document root directory is /var/www.
We should also edit the php.ini file to turn the magic quotes off. Since PHP 5.3.0 they are off by default. On my system, I have currently PHP 5.2.6 so I had to edit the php.ini file. It is located at /etc/php5/apache2/php.ini on my system.
Magic Quotes is a process that automatically escapes incoming data to the PHP script. It's preferred to code with magic quotes off and to instead escape the data at runtime, as needed. We are going to use sqlite_escape_string() function to escape strings if necessary.
; Magic quotes
;

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off

; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off

; Use Sybase-style magic quotes (escape ' with '' instead of \').
magic_quotes_sybase = Off
This is a portion of the php.ini file. Magic quotes are off. If you edited the file while apache was running, you must restart the apache server.
We are also going to create a directory, where we will have our sqlite database files. In the document root directory, /var/www on my Ubuntu system, we create a directory called db.
$ pwd
/var/www
$ ls -ld db
drwxrwxrwx 2 root root 4096 2009-12-01 22:04 db
A web server must have a write & execute access to the directory. It is convenient to have a read access too.
$ pwd
/var/www/db
$ ls -l test.db 
-rw-rw-rw- 1 root root 6144 2009-12-01 22:04 test.db
Inside the db directory, we create a test.db file with read and write access rights.
SQLite database is called a zero configuration database. The only problems that could arise are insufficient access rights.

First example

Our first example will test the version of the SQLite library and the version of the PHP language. If it works, we have all installed correctly.
We create a simple PHP script and give it a name version.php. We place it into the document root directory. It is /var/www on my system. Ensure, that the apache server is running.
$ /etc/init.d/apache2 status
 * Apache is running (pid 22965).
We check, if the apache server is running. To start the server, we can use the /etc/init.d/apache2 start command.
<?php
echo sqlite_libversion();
echo "<br>";
echo phpversion();
?>
Now we start the browser and locate to http://localhost/version.php
The PHP code shows 2.8.17 and 5.2.6-2ubuntu4.5 strings on my system. You should get something similar.
First example
Figure: First example

Creating a table

In the following PHP code, we will create a database table.
<?php
$dbhandle = sqlite_open('db/test.db', 0666, $error);
if (!$dbhandle) die ($error);

$stm = "CREATE TABLE Friends(Id integer PRIMARY KEY," . 
       "Name text UNIQUE NOT NULL, Sex text CHECK(Sex IN ('M', 'F')))";
$ok = sqlite_exec($dbhandle, $stm, $error);

if (!$ok)
   die("Cannot execute query. $error");

echo "Database Friends created successfully";

sqlite_close($dbhandle);
?>
Besides creating a database table, we do some error checking.
$dbhandle = sqlite_open('db/test.db', 0666, $error);
The sqlite_open() function opens a SQLite database. The function has three parameters. The first parameter is the filename of the database. According to the documentation, the second parameter is ignored currently. The 0666 is the recommended value. If we cannot open the database, an error message is put into the $error variable.
if (!$dbhandle) die ($error);
The sqlite_open() function returns a database handle on success or FALSE on error. The die()function outputs an error message and terminates the script.
$stm = "CREATE TABLE Friends(Id integer PRIMARY KEY," . 
    "Name text UNIQUE NOT NULL, Sex text CHECK(Sex IN ('M', 'F')))";
The $stm variable holds the SQL statement to create a Friends database table. Note that there are two strings concatenated with the dot operator.
$ok = sqlite_exec($dbhandle, $stm, $error);
The sqlite_exec() executes a result-less statement against the database. The first parameter is the database handle, that we obtained with the sqlite_open() function. The second parameter is the statement, that we are about to execute. And the last parameter is the possible error message. This is usually due to a syntax error. The function returns TRUE for success or FALSE for failure.
if (!$ok)
   die("Cannot execute query. $error");
We check for possible errors. There could be two types of errors. SQL syntax error or insufficient permissions.
echo "Database Friends created successfully";
If all went OK, we print a message 'Database Friends created successfully'. If there is some error, this message is not printed, because the die() function terminates the execution of the PHP script.
sqlite_close($dbhandle);
We close the database handle. It is not necessary to do it explicitly. PHP language does it automatically. But it is a good programming practice to do it.

Inserting data

In the following example, we will insert some data into the Friends database.
<?php
   
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$stm1 = "INSERT INTO Friends VALUES(1,'Jane', 'F')";
$stm2 = "INSERT INTO Friends VALUES(2,'Thomas', 'M')";
$stm3 = "INSERT INTO Friends VALUES(3,'Franklin', 'M')";

$ok1 = sqlite_exec($dbhandle, $stm1);
if (!$ok1) die("Cannot execute statement.");

$ok2 = sqlite_exec($dbhandle, $stm2);
if (!$ok2) die("Cannot execute statement.");

$ok3 = sqlite_exec($dbhandle, $stm3);
if (!$ok3) die("Cannot execute statement.");

echo "Data inserted successfully";

sqlite_close($dbhandle);

?>
We insert some data. We don't retrieve any data. Therefore we use again the sqlite_exec()function.
$stm1 = "INSERT INTO Friends VALUES(1,'Jane', 'F')";
$stm2 = "INSERT INTO Friends VALUES(2,'Thomas', 'M')";
$stm3 = "INSERT INTO Friends VALUES(3,'Franklin', 'M')";
Here we have three statements that will insert three rows into the Friends database.
$ok1 = sqlite_exec($dbhandle, $stm1);
if (!$ok1) die("Cannot execute statement.");
We execute the first statement. If something goes wrong, the script is terminated.
What if we wanted to add a name like O'Neil? The single quote ' character belongs to some unsafe characters. Using them could lead to problems. We must properly escape them. The single quote character is escaped by using another single quote character. '' Note that it is easily confused with a double quote character.
<?php
   
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);

$name = "O'Neill";
$name_es = sqlite_escape_string($name);

$stm = "INSERT INTO Friends VALUES(4,'$name_es', 'M')";

$ok1 = sqlite_exec($dbhandle, $stm);
if (!$ok1) die("Cannot execute statement.");

echo "Data inserted successfully";

sqlite_close($dbhandle);

?>
In this code example, we add a fourth row to the Friends table.
$name = "O'Neil";
We have a name with a single quote character in it.
$name_es = sqlite_escape_string($name);
To escape the string, we use the sqlite_escape_string() function. The returned string is O''Neill.
$stm = "INSERT INTO Friends VALUES(4,'$name_es', 'M')";
We build the SQL statement with the $name_es variable.
sqlite> SELECT * FROM Friends;
Id          Name        Sex       
----------  ----------  ----------
1           Jane        F         
2           Thomas      M         
3           Franklin    M         
4           O'Neil      M   
We look with the sqlite command line tool, what we have in the table. All is OK.

Retrieving data

There are multiple ways, how we can retrieve data from a table.
<?php
   
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$query = "SELECT Name, Sex FROM Friends";
$result = sqlite_query($dbhandle, $query);
if (!$result) die("Cannot execute query.");

$row = sqlite_fetch_array($result, SQLITE_ASSOC); 
print_r($row);
echo "<br>";

sqlite_rewind($result);
$row = sqlite_fetch_array($result, SQLITE_NUM); 
print_r($row);
echo "<br>";

sqlite_rewind($result);
$row = sqlite_fetch_array($result, SQLITE_BOTH); 
print_r($row);
echo "<br>";

sqlite_close($dbhandle);

?>
To fetch data from the table, we can use the sqlite_fetch_array().
$query = "SELECT Name, Sex FROM Friends";
$result = sqlite_query($dbhandle, $query);
We build a SELECT query and execute the query with the sqlite_query() function. The function returns a result set, e.g. all data from the query.
The sqlite_fetch_array() does two things. Moves the pointer to the next row and returns that row from the result set. The row is is an array. We can control how the data is organized in the array, by using three result type flags. SQLITE_ASSOC, SQLITE_NUM, SQLITE_BOTH. Using the first flag we will have an associative array. Using the second one, we will have a numerical array. The third option is the default option also. Using this flag, we will have both arrays with associative indexes and numerical indexes. The print_r() function returns a human readable representation of a variable. In our case, we can inspect what we have in an array.
$row = sqlite_fetch_array($result, SQLITE_ASSOC); 
print_r($row);
echo "<br>";
Here we fetch the first row from the result set. We use the SQLITE_ASSOC flag. Which means, we can access data from the array using string indexes. The indexes are column names of the table. These are Name and Sex column names. Note that the SQL select statement did not include the id column.
sqlite_rewind($result);
The sqlite_rewind() function makes the pointer point to the first row of the result set. We use this function because we want to compare three flags on the same row. For the sake of the clarity of the explanation.
Retrieving data
Figure: Retrieving data
In the following example, we will traverse the data using the associative indexes.
<?php
   
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$query = "SELECT Name, Sex FROM Friends";
$result = sqlite_query($dbhandle, $query);
if (!$result) die("Cannot execute query.");

while ($row = sqlite_fetch_array($result, SQLITE_ASSOC)) {
    echo $row['Name']  . " : " . $row['Sex'];
    echo "<br>";
}

sqlite_close($dbhandle);

?>
We traverse all data in our table. More specifically, four rows in the Friends table.
while ($row = sqlite_fetch_array($result, SQLITE_ASSOC)) {
    echo $row['Name']  . " : " . $row['Sex'];
    echo "<br>";
}
We can use the while loop to go through all rows of the result set. The sqlite_fetch_array()returns FALSE, if the next position is beyond the final row and the loop stops.
echo $row['Name']  . " : " . $row['Sex'];
We get the data from the array using the string indexes. These are the column names of the Friends table.
while ($row = sqlite_fetch_array($result, SQLITE_NUM)) {
    echo $row[0]  . " : " . $row[1];
    echo "<br>";
}
Same loop with the SQLITE_NUM flag.

Columns & rows

Next, we are going to count the number of rows and columns in our result set.
<?php
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$query = "SELECT * FROM Friends LIMIT 2";
$result = sqlite_query($dbhandle, $query);
if (!$result) die("Cannot execute query.");


$rows = sqlite_num_rows($result);
$cols = sqlite_num_fields($result);

echo "The result set has $rows rows and 
      $cols columns";

sqlite_close($dbhandle);

?>
The functions get the numbers from the result set. This means, that the number of rows and columns calculated depend on the SQL statement, that we use to obtain the data from the database table.
$query = "SELECT * FROM Friends LIMIT 2";
Here we build the SQL query. We get all columns from the table. And we limit the number of rows to 2.
$rows = sqlite_num_rows($result);
$cols = sqlite_num_fields($result);
The sqlite_num_rows() returns the number of rows in our result set. sqlite_num_fields() returns the number of columns/fields from the result set.
We get this string 'The result set has 2 rows and 3 columns'.
The next PHP script will display the data from the Friends table with the names of the columns.
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$query = "SELECT Name, Sex FROM Friends";
$result = sqlite_query($dbhandle, $query);
if (!$result) die("Cannot execute query.");

$rows = sqlite_num_rows($result);

$field1 = sqlite_field_name($result, 0);
$field2 = sqlite_field_name($result, 1);

echo "<table style='font-size:12;font-family:verdana'>";
echo "<thead><tr>";
echo "<th align='left'>$field1</th>";
echo "<th align='left'>$field2</th>";
echo "</tr></thead>";

for ($i = 0; $i < $rows; $i++) {
    $row = sqlite_fetch_array($result, SQLITE_NUM); 
    echo "<tr>";
    echo "<td>$row[0]</td>";
    echo "<td>$row[1]</td>";
    echo "</tr>";
}

echo "</table>";

sqlite_close($dbhandle);

?>
$field1 = sqlite_field_name($result, 0);
$field2 = sqlite_field_name($result, 1);
The sqlite_field_name() returns the name of a particular field. Our SQL query returns two columns. The first function returns 'Name', the second 'Sex'.
echo "<thead><tr>";
echo "<th align='left'>$field1</th>";
echo "<th align='left'>$field2</th>";
echo "</tr></thead>";
We put the two column names into the html table header.
for ($i = 0; $i < $rows; $i++) {
    $row = sqlite_fetch_array($result, SQLITE_NUM); 
    echo "<tr>";
    echo "<td>$row[0]</td>";
    echo "<td>$row[1]</td>";
    echo "</tr>";
}
We use yet another way to retrieve data from the result set. We count the number of rows. And use the for cycle to go through the data.
The next PHP script will display column types of the Friends table.
<?php
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$cols = sqlite_fetch_column_types('Friends', $dbhandle, SQLITE_ASSOC);

foreach ($cols as $column => $type) {
    echo "Column name: $column Column type: $type";
    echo "<br>";
}

sqlite_close($dbhandle);
?>
$cols = sqlite_fetch_column_types('Friends', $dbhandle, SQLITE_ASSOC);
The sqlite_fetch_column_types() function returns an array of column types from a particular table. The table name is the first parameter of the function.
foreach ($cols as $column => $type) {
    echo "Column name: $column Column type: $type";
    echo "<br>";
}
We go through the array using the foreach keyword.

Listing available tables

The next example will list all available tables from the current database.
sqlite> .tables
Books    Cars     Friends
Using the sqlite3 tool we list the available tables.
<?php
$dbhandle = sqlite_open('db/test.db', 0666, $error);

if (!$dbhandle) die ($error);
    
$query = "SELECT name, sql FROM sqlite_master WHERE type='table'";
$result = sqlite_query($dbhandle, $query, SQLITE_NUM);
if (!$result) die("Cannot execute query.");

while (sqlite_has_more($result)) {
    $row = sqlite_fetch_array($result);
    echo "table: $row[0], sql: $row[1]";
    echo "<br>";
}

sqlite_close($dbhandle);

?>
We use the sqlite_master table to obtain the list of tables for the database.
$query = "SELECT name, sql FROM sqlite_master WHERE type='table'";
This is the query. The name column of the sqlite_master table gives us the table name. The sql column gives us the SQL used to create that table.
while (sqlite_has_more($result)) {
    $row = sqlite_fetch_array($result);
    echo "table: $row[0], sql: $row[1]";
    echo "<br>";
}
The while loop goes through the rows of the result set. We use a new function. sqlite_has_more()returns TRUE if there are more rows available from the result set, or FALSE otherwise.

Simple form example

In our last example, we will work with a simple html form. Submitting the form, we add a new friend to the Friends table.
<html>
<head>
<title>SQLite PHP tutorial</title>
</head>
<body style="font-size:12;font-family:verdana">

<form action="add.php" method="post">

<p>
Name: <input type="text" name="name"><br>
Male: <input type="radio" value="M" name="gender"><br>
Female: <input type="radio" value="F" name="gender">
</p>

<p>
<input type="submit">
</p>

</form>


</body>
</html>
In our html form we have one text box and one radio box. We enter a name of a friend in the text box. The radio box determines the gender. The action property of the html form points to the add.php script. This means, that upon submitting the form the add.php script will run.
<?php

$gender = $_POST['gender'];
$name = $_POST['name'];

$name_es = sqlite_escape_string($name);

if (!empty($name)) {

   $dbhandle = sqlite_open('db/test.db', 0666, $error);

   if (!$dbhandle) die ($error);
   
   $stm = "INSERT INTO Friends(Name, Sex) VALUES('$name_es', '$gender')";
   $ok = sqlite_exec($dbhandle, $stm, $error);

   if (!$ok) die("Error: $error");  
   echo "Form submitted successfully";
}
?>
This is the add.php script.
$gender = $_POST['gender'];
$name = $_POST['name'];
We retrieve the data from the submitted form.
$name_es = sqlite_escape_string($name);
The data from the text box is potentionally unsafe; 'tainted'. We use the sqlite_escape_string. It escapes a string for use as a query parameter. This is common practice to avoid malicious sql injection attacks.
$stm = "INSERT INTO Friends(Name, Sex) VALUES('$name_es', '$gender')";
Here we build the SQL statement.
$ok = sqlite_exec($dbhandle, $stm, $error);
Statement is executed.
Form example
Figure: Form example

This was the SQLite PHP tutorial. We covered some basics of programming SQLite with PHP language. We used procedural style of code.

MySQL Java tutorial

This is a Java tutorial for the MySQL database. It covers the basics of MySQL programming with Java. In this tutorial, we use the MySQL Connector/J driver. It is the official JDBC driver for MySQL. The examples were created and tested on Ubuntu Linux. You might also want to checkPostgreSQL Java tutorial, Apache Derby tutorial or MySQL tutorial on ZetCode.

JDBC

JDBC is an API for the Java programming language that defines how a client may access a database. It provides methods for querying and updating data in a database. JDBC is oriented towards relational databases. From a technical point of view, the API is as a set of classes in the java.sql package. To use JDBC with a particular database, we need a JDBC driver for that database.

About MySQL database

MySQL is a leading open source database management system. It is a multi user, multithreaded database management system. MySQL is especially popular on the web. It is one of the parts of the very popular LAMP platform. Linux, Apache, MySQL, PHP. Currently MySQL is owned by Oracle. MySQL database is available on most important OS platforms. It runs under BSD Unix, Linux, Windows or Mac. Wikipedia and YouTube use MySQL. These sites manage millions of queries each day. MySQL comes in two versions. MySQL server system and MySQL embedded system.

Before we start

For this tutorial, we need to have several libraries installed. We need to install mysql-server and mysql-client packages. The first package has the MySQL server and the second one contains, among others, the mysql monitor tool. We need to install the JDK, Java Development Kit, for compiling and running Java programs. Finally, we need the MySQL Connector/J driver. If you are using Netbeans IDE, than you have already the driver at hand. Inside the Projects tab, right click on the Libraries node and select Add Library option. From the list of options, select MySQL JDBC Driver.

Netbeans project libs
Figure: Netbeans project libs

If you want to compile the examples from the command line, go to the sitehttp://www.mysql.com/products/connector/ and download the MySQL connector for the Java language.
$ javac zetcode/Version.java
$ java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Version
5.5.9
Assuming, that you have put the connector jar file into the lib directory and using package zetcode, you compile and run the first example this way.

If you don't already have MySQL installed, we must install it.
$ sudo apt-get install mysql-server
This command installs the MySQL server and various other packages. While installing the package, we are prompted to enter a password for the MySQL root account.
Next, we are going to create a new database user and a new database. We use the mysql client.
$ service mysql status
mysql start/running, process 1238
We check if the MySQL server is running. If not, we need to start the server. On Ubuntu Linux, this can be done with the service mysql start command.

$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 5.0.67-0ubuntu6 (Ubuntu)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema | 
| mysql              | 
+--------------------+
2 rows in set (0.00 sec)
We use the mysql monitor client application to connect to the server. We connect to the database using the root account. We show all available databases with the SHOW DATABASES statement.
mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.02 sec)
We create a new testdb database. We will use this database throughout the tutorial.
mysql> CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'test623';
Query OK, 0 rows affected (0.00 sec)

mysql> USE testdb;
Database changed

mysql> GRANT ALL ON testdb.* TO 'testuser'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> quit;
Bye
We create a new database user. We grant all privileges to this user for all tables of the testdb database.

MySQL version

If the following program runs OK, then we have everything installed OK. We check the version of the MySQL server.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Version {

    public static void main(String[] args) {

        Connection con = null;
        Statement st = null;
        ResultSet rs = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {
            con = DriverManager.getConnection(url, user, password);
            st = con.createStatement();
            rs = st.executeQuery("SELECT VERSION()");

            if (rs.next()) {
                System.out.println(rs.getString(1));
            }

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(Version.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (st != null) {
                    st.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Version.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
We connect to the database and get some info about the MySQL server.
String url = "jdbc:mysql://localhost:3306/testdb";
This is the connection url for the MySQL database. Each driver has a different syntax for the url. In our case, we provide a host, a port and a database name.
con = DriverManager.getConnection(url, user, password);
We establish a connection to the database, using the connection url, user name and password.
st = con.createStatement();
The createStatement() method of the connection object creates a Statement object for sending SQL statements to the database.
rs = st.executeQuery("SELECT VERSION()");
The createStatement() method of the connection object executes the given SQL statement, which returns a single ResultSet object. The ResultSet is a table of data returned by a specific SQL statement.
if (result.next()) {
    System.out.println(result.getString(1));
}
A ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next() method moves the cursor to the next row. If there are no rows left, the method returns false. The getString() method retrieves the value of a specified column. The first column has index 1.
} catch (SQLException ex) {
    Logger lgr = Logger.getLogger(Version.class.getName());
    lgr.log(Level.SEVERE, ex.getMessage(), ex);

}
In case of an exception, we log the error message. For this console example, the message is displayed in the terminal.
try {
    if (rs != null) {
        rs.close();
    }
    if (st != null) {
        st.close();
    }
    if (con != null) {
        con.close();
    }
...
Inside the finally block, we close the database resources. We also check if the objects are not equal to null. This is to prevent null pointer exceptions. Otherwise we might get a NullPointerException, which would terminate the application and leave the resources not cleaned up.
} catch (SQLException ex) {
    Logger lgr = Logger.getLogger(Version.class.getName());
    lgr.log(Level.WARNING, ex.getMessage(), ex);
}
We log an error message, when the resources could not be closed.
java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Version
5.5.9
This is the output of the program on my system.

Creating and populating tables

Next we are going to create database tables and fill them with data. These tables will be used throughout this tutorial.
DROP TABLE IF EXISTS Books, Authors, Testing, Images;

CREATE TABLE IF NOT EXISTS Authors(Id INT PRIMARY KEY AUTO_INCREMENT, 
    Name VARCHAR(25)) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS Books(Id INT PRIMARY KEY AUTO_INCREMENT, 
    AuthorId INT, Title VARCHAR(100), 
    FOREIGN KEY(AuthorId) REFERENCES Authors(Id) ON DELETE CASCADE)
    ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS Testing(Id INT) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS Images(Id INT PRIMARY KEY AUTO_INCREMENT, 
    Data MEDIUMBLOB);

INSERT INTO Authors(Id, Name) VALUES(1, 'Jack London');
INSERT INTO Authors(Id, Name) VALUES(2, 'Honore de Balzac');
INSERT INTO Authors(Id, Name) VALUES(3, 'Lion Feuchtwanger');
INSERT INTO Authors(Id, Name) VALUES(4, 'Emile Zola');
INSERT INTO Authors(Id, Name) VALUES(5, 'Truman Capote');

INSERT INTO Books(Id, AuthorId, Title) VALUES(1, 1, 'Call of the Wild');
INSERT INTO Books(Id, AuthorId, Title) VALUES(2, 1, 'Martin Eden');
INSERT INTO Books(Id, AuthorId, Title) VALUES(3, 2, 'Old Goriot');
INSERT INTO Books(Id, AuthorId, Title) VALUES(4, 2, 'Cousin Bette');
INSERT INTO Books(Id, AuthorId, Title) VALUES(5, 3, 'Jew Suess');
INSERT INTO Books(Id, AuthorId, Title) VALUES(6, 4, 'Nana');
INSERT INTO Books(Id, AuthorId, Title) VALUES(7, 4, 'The Belly of Paris');
INSERT INTO Books(Id, AuthorId, Title) VALUES(8, 5, 'In Cold blood');
INSERT INTO Books(Id, AuthorId, Title) VALUES(9, 5, 'Breakfast at Tiffany');
We have a books.sql file. It creates four database tables, Authors, Books, Testing and Images. Three tables are of InnoDB type. InnoDB databases support foreign key constraints and transactions. We place a foreign key constraint on the AuthorId column of the Books table. We fill the Authors and Books tables with initial data.
mysql> source books.sql
Query OK, 0 rows affected (0.07 sec)
Query OK, 0 rows affected (0.12 sec)
Query OK, 1 row affected (0.04 sec)
...
We use the source command to execute the books.sql script.

Prepared statements

Now we will concern ourselves with prepared statements. When we write prepared statements, we use placeholders instead of directly writing the values into the statements. Prepared statements increase security and performance.
In Java a PreparedStatement is an object which represents a precompiled SQL statement.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Prepared {

    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            String author = "Trygve Gulbranssen";
            con = DriverManager.getConnection(url, user, password);

            pst = con.prepareStatement("INSERT INTO Authors(Name) VALUES(?)");
            pst.setString(1, author);
            pst.executeUpdate();

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(Prepared.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Prepared.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }
}
We add a new author to the Authors table.
pst = con.prepareStatement("INSERT INTO Authors(Name) VALUES(?)");
Here we create a prepared statement. When we write prepared statements, we use placeholders instead of directly writing the values into the statements. Prepared statements are faster and guard against SQL injection attacks. The ? is a placeholder, which is going to be filled later.
pst.setString(1, author);
A value is bound to the placeholder.
pst.executeUpdate();
The prepared statement is executed. We use the executeUpdate() method of the statement object when we don't expect any data to be returned. This is when we create databases or execute INSERT, UPDATE, DELETE statements.
$ java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Prepared
mysql> select * from Authors;
+----+--------------------+
| Id | Name               |
+----+--------------------+
|  1 | Jack London        |
|  2 | Honore de Balzac   |
|  3 | Lion Feuchtwanger  |
|  4 | Emile Zola         |
|  5 | Truman Capote      |
|  6 | Trygve Gulbranssen |
+----+--------------------+
6 rows in set (0.00 sec)
We have a new author inserted into the table.

For the following two examples, we will use the Testing table. We will execute a normal statement and a prepared statement 1000 times. We check, if there is some difference in execution time.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;


public class NotPrepared {

    public static void main(String[] args) {

        Connection con = null;
        Statement st = null;

        String cs = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(cs, user, password);

            st = con.createStatement();

            for (int i=1; i<=1000; i++) {
                String query = "INSERT INTO Testing(Id) VALUES(" + 2*i + ")";
                st.executeUpdate(query);
            }

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(NotPrepared.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (st != null) {
                    st.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(NotPrepared.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }
}
The first example uses the normal Statement object.
for (int i=1; i<=1000; i++) {
    String query = "INSERT INTO Testing(Id) VALUES(" + 2*i + ")";
    st.executeUpdate(query);
}
We build the query and execute it 1000 times.
$ /usr/bin/time java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/NotPrepared
1.09user 0.18system 0:46.37elapsed 2%CPU (0avgtext+0avgdata 92144maxresident)k
0inputs+96outputs (1major+6160minor)pagefaults 0swaps
We use the time command to measure the time, that the program ran. Note that we use a standard linux command, not the built-in bash time command. It took 46s to insert 1000 rows into the table using the Statement object.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Prepared2 {

    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        
        String cs = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(cs, user, password);

            pst = con.prepareStatement("INSERT INTO Testing(Id) VALUES(?)");

            for (int i = 1; i <= 1000; i++) {
                pst.setInt(1, i * 2);
                pst.executeUpdate();
            }

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(Prepared2.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Prepared2.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }
}
Now we use the PreparedStatement to do the same task.
pst = con.prepareStatement("INSERT INTO Testing(Id) VALUES(?)");
We create the prepared statement using the prepareStatement() method.
for (int i = 1; i <= 1000; i++) {
    pst.setInt(1, i * 2);
    pst.executeUpdate();
}
We bind a value to the prepared statement, execute it in a loop thousand times.
$ /usr/bin/time java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Prepared2
1.08user 0.10system 0:32.99elapsed 3%CPU (0avgtext+0avgdata 90400maxresident)k
0inputs+96outputs (1major+6129minor)pagefaults 0swaps
Now it took 33s to insert 1000 rows. We have saved 13s using prepared statements.

Retrieving data

Next we will show, how to retrieve data from a database table. We get all data from the Authors table.
package zetcode;

import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Retrieve {
    
    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {
            
            con = DriverManager.getConnection(url, user, password);
            pst = con.prepareStatement("SELECT * FROM Authors");
            rs = pst.executeQuery();

            while (rs.next()) {
                System.out.print(rs.getInt(1));
                System.out.print(": ");
                System.out.println(rs.getString(2));
            }

        } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Retrieve.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Retrieve.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
We get all authors from the Authors table and print them to the console.
pst = con.prepareStatement("SELECT * FROM Authors");
rs = pst.executeQuery();
We execute a query that selects all columns from the Authors table. We use the executeQuery()method. The method executes the given SQL statement, which returns a single ResultSet object. The ResultSet is the data table returned by the SQL query.
while (rs.next()) {
      System.out.print(rs.getInt(1));
      System.out.print(": ");
      System.out.println(rs.getString(2));
}
The next() method advances the cursor to the next record. It returns false, when there are no more rows in the result set. The getInt() and getString() methods retrieve the value of the designated column in the current row of this ResultSet object as an int/String in the Java programming language.
java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Retrieve
1: Jack London
2: Honore de Balzac
3: Lion Feuchtwanger
4: Emile Zola
5: Truman Capote
6: Trygve Gulbranssen
We have Ids and Names of authors printed to the console.

Properties

It is a common practice to put the configuration data outside the program in a separate file. This way the programmers are more flexible. We can change the user, a password or a connection url without needing to recompile the program. It is especially useful in a dynamic environment, where is a need for a lot of testing, debugging, securing data etc.
In Java, the Properties is a class used often for this. The class is used for easy reading and saving of key/value properties.
db.url=jdbc:mysql://localhost:3306/testdb
db.user=testuser
db.passwd=test623
We have a database.properties file, in which we have three key/value pairs. These are dynamically loaded during execution of the program.
package zetcode;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Retrieve2 {

    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        Properties props = new Properties();
        FileInputStream in = null;

        try {
            in = new FileInputStream("database.properties");
            props.load(in);

        } catch (FileNotFoundException ex) {

            Logger lgr = Logger.getLogger(Retrieve2.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } catch (IOException ex) {

            Logger lgr = Logger.getLogger(Retrieve2.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {
            
            try {
                 if (in != null) {
                     in.close();
                 }
            } catch (IOException ex) {
                Logger lgr = Logger.getLogger(Retrieve2.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }

        String url = props.getProperty("db.url");
        String user = props.getProperty("db.user");
        String passwd = props.getProperty("db.passwd");

        try {

            con = DriverManager.getConnection(url, user, passwd);
            pst = con.prepareStatement("SELECT * FROM Authors");
            rs = pst.executeQuery();

            while (rs.next()) {
                System.out.print(rs.getInt(1));
                System.out.print(": ");
                System.out.println(rs.getString(2));
            }


        } catch (Exception ex) {
            Logger lgr = Logger.getLogger(Retrieve2.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Retrieve2.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
We connect to the testdb database and print the contents of the Authors table to the console. This time, we load the connection properties from a file. They are not hard coded in the proram.
Properties props = new Properties();
FileInputStream in = null;

try {
    in = new FileInputStream("database.properties");
    props.load(in);
...
The Properties class is created. The data is loaded from the file called database.properties, where we have our configuration data.
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String passwd = props.getProperty("db.passwd");
The values are retrieved with the getProperty() method.

Multiple statements

It is possible to execute multiple SQL statements in one query. The allowMultiQueries must be set to enable multiple statements in MySQL.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Multiple {


    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        String cs = "jdbc:mysql://localhost:3306/testdb?allowMultiQueries=true";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(cs, user, password);

            String query = "SELECT Id, Name FROM Authors WHERE Id=1;"
                    + "SELECT Id, Name FROM Authors WHERE Id=2;"
                    + "SELECT Id, Name FROM Authors WHERE Id=3";

            pst = con.prepareStatement(query);
            boolean isResult = pst.execute();

            do {
                rs = pst.getResultSet();

                while (rs.next()) {
                    System.out.print(rs.getInt(1));
                    System.out.print(": ");
                    System.out.println(rs.getString(2));
                }

                isResult = pst.getMoreResults();
            } while (isResult);


        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(Multiple.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                Logger lgr = Logger.getLogger(Multiple.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
In the code example, we retrieve three rows from the Authors table. We use three SELECTstatements to get three rows.
String cs = "jdbc:mysql://localhost:3306/testdb?allowMultiQueries=true";
We enable multiple statements queries in the database URL by setting the allowMultiQueriesparameter to true.
String query = "SELECT Id, Name FROM Authors WHERE Id=1;"
        + "SELECT Id, Name FROM Authors WHERE Id=2;"
        + "SELECT Id, Name FROM Authors WHERE Id=3";
Here we have a query with multiple statements. The statements are separated by a semicolon.
boolean isResult = pst.execute();
We call the execute() method of the prepared statement object. The method returns a boolean value indicating if the first result is a ResultSet object. Subsequent results are called using thegetMoreResults() method.
do {
    rs = pst.getResultSet();

    while (rs.next()) {
        System.out.print(rs.getInt(1));
        System.out.print(": ");
        System.out.println(rs.getString(2));
    }

    isResult = pst.getMoreResults();
} while (isResult);
The processing of the results is done inside the do/while loop. The ResultSet is retrieved with thegetResultSet() method call. To find out, if there are other results, we call the getMoreResults()method.
java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Multiple
1: Jack London
2: Honore de Balzac
3: Lion Feuchtwanger
The output of the example. The first three rows were retrieved from the Authors table.

Column headers

Next we will show, how to print column headers with the data from the database table. We refer to column names as MetaData. MetaData is data about the core data in the database.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ColumnHeaders {


    public static void main(String[] args) {
        
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        String cs = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(cs, user, password);
            String query = "SELECT Name, Title From Authors, " +
               "Books WHERE Authors.Id=Books.AuthorId";
            pst = con.prepareStatement(query);

            rs = pst.executeQuery();

            ResultSetMetaData meta = rs.getMetaData();

            String colname1 = meta.getColumnName(1);
            String colname2 = meta.getColumnName(2);

            Formatter fmt1 = new Formatter();
            fmt1.format("%-21s%s", colname1, colname2);
            System.out.println(fmt1);

            while (rs.next()) {
                Formatter fmt2 = new Formatter();
                fmt2.format("%-21s", rs.getString(1));
                System.out.print(fmt2);
                System.out.println(rs.getString(2));
            }

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(ColumnHeaders.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (rs != null) {
                    rs.close();
                }
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                
                Logger lgr = Logger.getLogger(ColumnHeaders.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
In this program, we select authors from the Authors table and their books from the Books table. We print the names of the columns returned in the result set. We format the output.
String query = "SELECT Name, Title From Authors, " +
    "Books WHERE Authors.Id=Books.AuthorId";
This is the SQL statement which joins authors with their books.
ResultSetMetaData meta = rs.getMetaData();
To get the column names we need to get the ResultSetMetaData. It is an object that can be used to get information about the types and properties of the columns in a ResultSet object.
String colname1 = meta.getColumnName(1);
String colname2 = meta.getColumnName(2);
From the obtained metadata, we get the column names.
Formatter fmt1 = new Formatter();
fmt1.format("%-21s%s", colname1, colname2);
System.out.println(fmt1)
We print the column names to the console. We use the Formatter object to format the data.
while (rs.next()) {
    Formatter fmt2 = new Formatter();
    fmt2.format("%-21s", rs.getString(1));
    System.out.print(fmt2);
    System.out.println(rs.getString(2));
}
We print the data to the console. We again use the Formatter object to format the data. The first column is 21 characters wide and is aligned to the left.
$ java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/ColumnHeaders
Name                 Title
Jack London          Call of the Wild
Jack London          Martin Eden
Honore de Balzac     Old Goriot
Honore de Balzac     Cousin Bette
Lion Feuchtwanger    Jew Suess
Emile Zola           Nana
Emile Zola           The Belly of Paris
Truman Capote        In Cold blood
Truman Capote        Breakfast at Tiffany
Output of the program.

Writing images

Some people prefer to put their images into the database, some prefer to keep them on the file system for their applications. Technical difficulties arise when we work with millions of images. Images are binary data. MySQL database has a special data type to store binary data called BLOB(Binary Large Object).
For this example, we use the Images table.
package zetcode;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class WriteImage {

    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        FileInputStream fin = null;

        String cs = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";                 

        try {

            File img = new File("woman.jpg");
            fin = new FileInputStream(img);

            con = DriverManager.getConnection(cs, user, password);

            pst = con.prepareStatement("INSERT INTO Images(Data) VALUES(?)");
            pst.setBinaryStream(1, fin, (int) img.length());
            pst.executeUpdate();

        } catch (FileNotFoundException ex) {
            Logger lgr = Logger.getLogger(WriteImage.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(WriteImage.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }
                if (fin != null) {
                    fin.close();
                }

            } catch (IOException ex) {
                Logger lgr = Logger.getLogger(WriteImage.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(WriteImage.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
In the preceding example, we read a jpg image from the current working directory and insert in into the Images table.
pst = con.prepareStatement("INSERT INTO Images(Data) VALUES(?)");
This is the SQL to insert an image.
File img = new File("woman.jpg");
fin = new FileInputStream(img);
We create a File object for the image file. To read bytes from this file, we create a FileInputStreamobject.
pst.setBinaryStream(1, fin, (int) img.length());
The binary stream is set to the prepared statement. The parameters of the setBinaryStream()method are the parameter index to bind, the input stream and the number of bytes in the stream.
pst.executeUpdate();
We execute the statement.

Reading images

In the previous example, we have inserted an image into the database table. Now we are going to read the image back from the table.
package zetcode;

import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ReadImage {


    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement pst = null;
        FileOutputStream fos = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(url, user, password);

            String query = "SELECT Data FROM Images LIMIT 1";
            pst = con.prepareStatement(query);
            
            ResultSet result = pst.executeQuery();
            result.next();

            fos = new FileOutputStream("woman2.jpg");

            Blob blob = result.getBlob("Data");
            int len = (int) blob.length();

            byte[] buf = blob.getBytes(1, len);

            fos.write(buf, 0, len);

        } catch (IOException ex) {
            Logger lgr = Logger.getLogger(ReadImage.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);               

        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(ReadImage.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (pst != null) {
                    pst.close();
                }
                if (con != null) {
                    con.close();
                }
                if (fos != null) {
                    fos.close();
                }

            } catch (IOException ex) {
                Logger lgr = Logger.getLogger(ReadImage.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(ReadImage.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
We read one image from the Images table.
String query = "SELECT Data FROM Images LIMIT 1";
We select one record from the table.
fos = new FileOutputStream("woman2.jpg");
The FileOutputStream object is created to write to a file. It is meant for writing streams of raw bytes such as image data.
Blob blob = result.getBlob("Data");
We get the image data from the Data column by calling the getBlob() method.
int len = (int) blob.length();
We figure out the length of the blob data. In other words, we get the number of bytes.
byte[] buf = blob.getBytes(1, len);
The getBytes() method retrieves all bytes of the Blob object, as an array of bytes.
fos.write(buf, 0, len);
The bytes are written to the output stream. The image is created on the filesystem.

Transaction support

A transaction is an atomic unit of database operations against the data in one or more databases. The effects of all the SQL statements in a transaction can be either all committed to the database or all rolled back.
The MySQL database has different types of storage engines. The most common are the MyISAM and the InnoDB engines. There is a trade-off between data security and database speed. The MyISAM tables are faster to process and they do not support transactions. On the other hand, the InnoDB tables are more safe against the data loss. They support transactions. They are slower to process.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Transaction {

    public static void main(String[] args) {

        Connection con = null;
        Statement st = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(url, user, password);
            st = con.createStatement();

            con.setAutoCommit(false);

            st.executeUpdate("UPDATE Authors SET Name = 'Leo Tolstoy' "
                    + "WHERE Id = 1");
            st.executeUpdate("UPDATE Books SET Title = 'War and Peace' "
                    + "WHERE Id = 1");
            st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina' "
                    + "WHERE Id = 2");

            con.commit();

        } catch (SQLException ex) {

            if (con != null) {
                try {
                    con.rollback();
                } catch (SQLException ex1) {
                    Logger lgr = Logger.getLogger(Transaction.class.getName());
                    lgr.log(Level.WARNING, ex1.getMessage(), ex1);
                }
            }

            Logger lgr = Logger.getLogger(Transaction.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);
            
        } finally {

            try {
                if (st != null) {
                    st.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                Logger lgr = Logger.getLogger(Transaction.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
In this program, we want to change the name of the author on the first row of the Authors table. We must also change the books associated with this author. A good example where a transaction is necessary. If we change the author and do not change the author's books, the data is corrupted.
con.setAutoCommit(false);
To work with transactions, we must set the autocommit to false. By default, a database connection is in autocommit mode. In this mode each statement is committed to the database, as soon as it is executed. A statement cannot be undone. When the autocommit is turned off, we commit the changes by calling the commit() or roll it back by calling the rollback() method.
st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina' "
        + "WHERE Id = 2");
The third SQL statement has an error. There is no Titl column in the table.
con.commit();
If there is no exception, the transaction is committed.
if (con != null) {
    try {
        con.rollback();
    } catch (SQLException ex1) {
        Logger lgr = Logger.getLogger(Transaction.class.getName());
        lgr.log(Level.WARNING, ex1.getMessage(), ex1);
    }
}
In case of an exception, the transaction is rolled back. No changes are committed to the database.
$ java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Transaction
Sep 24, 2011 2:53:19 PM zetcode.Transaction main
SEVERE: Unknown column 'Titl' in 'field list'
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Titl' 
    in 'field list'
...

mysql> SELECT Name, Title From Authors, Books WHERE Authors.Id=Books.AuthorId;
+-------------------+----------------------+
| Name              | Title                |
+-------------------+----------------------+
| Jack London       | Call of the Wild     |
| Jack London       | Martin Eden          |
| Honore de Balzac  | Old Goriot           |
| Honore de Balzac  | Cousin Bette         |
| Lion Feuchtwanger | Jew Suess            |
| Emile Zola        | Nana                 |
| Emile Zola        | The Belly of Paris   |
| Truman Capote     | In Cold blood        |
| Truman Capote     | Breakfast at Tiffany |
+-------------------+----------------------+
9 rows in set (0.01 sec)
An exception was thrown. The transaction was rolled back and no changes took place.

However, without a transaction, the data is not safe.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Update {

    public static void main(String[] args) {

        Connection con = null;
        Statement st = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

            con = DriverManager.getConnection(url, user, password);
            st = con.createStatement();

            st.executeUpdate("UPDATE Authors SET Name = 'Leo Tolstoy' "
                    + "WHERE Id = 1");
            st.executeUpdate("UPDATE Books SET Title = 'War and Peace' "
                    + "WHERE Id = 1");
            st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina' "
                    + "WHERE Id = 2");

            con.close();
            
        } catch (SQLException ex) {
            Logger lgr = Logger.getLogger(Update.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
                if (st != null) {
                    st.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {

                Logger lgr = Logger.getLogger(Update.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
We have the same example. This time, without the transaction support.
$ java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/Update
Sep 24, 2011 3:05:08 PM zetcode.Update main
SEVERE: Unknown column 'Titl' in 'field list'
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Titl' 
    in 'field list'
...

mysql> SELECT Name, Title From Authors, Books WHERE Authors.Id=Books.AuthorId;
+-------------------+----------------------+
| Name              | Title                |
+-------------------+----------------------+
| Leo Tolstoy       | War and Peace        |
| Leo Tolstoy       | Martin Eden          |
| Honore de Balzac  | Old Goriot           |
| Honore de Balzac  | Cousin Bette         |
| Lion Feuchtwanger | Jew Suess            |
| Emile Zola        | Nana                 |
| Emile Zola        | The Belly of Paris   |
| Truman Capote     | In Cold blood        |
| Truman Capote     | Breakfast at Tiffany |
+-------------------+----------------------+
9 rows in set (0.00 sec)
An exception is thrown again. Leo Tolstoy did not write Martin Eden. The data is corrupted.

Batch updates

When we need to update data with multiple statements, we can use batch updates. Batch updates are available for INSERT, UPDATE, DELETE statements as well as for CREATE TABLE and DROP TABLE statements.
package zetcode;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;


public class BatchUpdate {

        public static void main(String[] args) {

        Connection con = null;
        Statement st = null;

        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "testuser";
        String password = "test623";

        try {

          con = DriverManager.getConnection(url, user, password);

          con.setAutoCommit(false);
          st = con.createStatement();

          st.addBatch("DELETE FROM Authors");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(1, 'Jack London')");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(2, 'Honore de Balzac')");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(3, 'Lion Feuchtwanger')");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(4, 'Emile Zola')");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(5, 'Truman Capote')");
          st.addBatch("INSERT INTO Authors(Id, Name) VALUES(6, 'Umberto Eco')");

          int counts[] = st.executeBatch();

          con.commit();

          System.out.println("Committed " + counts.length + " updates");

        } catch (SQLException ex) {

            if (con != null) {
                try {
                    con.rollback();
                } catch (SQLException ex1) {
                    Logger lgr = Logger.getLogger(BatchUpdate.class.getName());
                    lgr.log(Level.WARNING, ex1.getMessage(), ex1);
                }
            }

            Logger lgr = Logger.getLogger(BatchUpdate.class.getName());
            lgr.log(Level.SEVERE, ex.getMessage(), ex);

        } finally {

            try {
 
                if (st != null) {
                    st.close();
                }
                if (con != null) {
                    con.close();
                }

            } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(BatchUpdate.class.getName());
                lgr.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
    }
}
This is an example program for a batch update. We delete all data from the Authors table and insert new data. We add one new author, Umberto Eco to see the changes.
st.addBatch("DELETE FROM Authors");
st.addBatch("INSERT INTO Authors(Id, Name) VALUES(1, 'Jack London')");
st.addBatch("INSERT INTO Authors(Id, Name) VALUES(2, 'Honore de Balzac')");
st.addBatch("INSERT INTO Authors(Id, Name) VALUES(3, 'Lion Feuchtwanger')");
...
We use teh addBatch() method to add a new command to the statement.
int counts[] = st.executeBatch();
After adding all commands, we call the executeBatch() to perform a batch update. The method returns an array of committed changes.
con.commit();
Batch updates are committed in a transaction.
java -cp .:lib/mysql-connector-java-5.1.13-bin.jar zetcode/BatchUpdate 
Committed 7 updates

mysql> SELECT * FROM Authors;
+----+-------------------+
| Id | Name              |
+----+-------------------+
|  1 | Jack London       |
|  2 | Honore de Balzac  |
|  3 | Lion Feuchtwanger |
|  4 | Emile Zola        |
|  5 | Truman Capote     |
|  6 | Umberto Eco       |
+----+-------------------+
6 rows in set (0.00 sec)
We execute the BatchUpdate program. The SELECT statement shows that the Authors table was successfully updated. It has a new author, Umerto Eco.