Friday 10 October 2014

Automated Test Concepts

Automated Test Concepts


Types of Tests

The type and amount of testing done by software companies varies greately, depending on the size of the application and on how much the software company affords to spend. Here is a list of some of the types of tests usually performed:
  • Unit Test: tests done for the smallest reasonable programming units, for example classes or global functions. Most frequently done by the developer using the debugger, usually during the coding phase.
  • Component Test: tests on the external interfaces of deployable components, for example DLLs, COM components an so on.
  • Regression Test: tests done on the whole system before a release, to check if previous functionality is still working.
  • Integration Test: tests done on all components working as a whole.
  • Stress Test: overload done on a system to test limit conditions, scalability and fault tolerance.
  • Business Test: checks done on a stable system to determine if the original requirements are fully implemented.
  • User Acceptance Test / Alpha Test: application is exposed to a number of 'friendly' users, which were not involved in development or previous testing.
  • User Acceptance Test / Beta Test: application is assumed to have nearly-commercial quality so it is exposed to 'non-friendly' users. The information gathered is fed into a final build of the system which becomes the commercial version.
Few companies actually perform the whole set of tests, and even they will skip some tests for small applications. Small to medium companies and individual developers will typically compress the testing phases in the following way:
  • The Unit and Component Tests are done as part of programming, in a fast compile-run-check cycle.
  • The IntegrationBusiness and Alpha Tests are done at the end of development as a single Functional Test, but usually without a formal test plan.
  • The Regression Test should duplicate the above test for each patch or new version, but this is difficult without a test plan to follow.
  • The Stress and Beta Tests are only done for larger applications.

Automated Tests

Many companies are recognizing the importance of automating the work of testers and including the auto-test as part of the regular build process. The results of the automatic test are seen as a measure of the current quality of the software. Combined with a code coverage tool it gives the answer to the all-elusive question: "How much of my code is currently running ok?"
Automated tests are not meant to completely replace manual testing. They cannot answer questions regarding the program's ease-of-use or user experience, and they cannot be used on small components during development. However they are far superior when it comes to Regression and Functional Testing, which as you've seen above are pretty much the only tests run in the real world.
Here are some of the advantages of having automated test scripts which can be run after each new build of the application:
  • Low Running Cost: running an automated test script before each release of a new version, patch or bugfix is a lot cheaper than a manual test.
  • Better Quality: especially for individual developers and small companies who would not employ a tester and will perform all testing themselves.
  • Consistency: the test script will perform the same checks every time it is run. A manual test will be affected by human error and it will tend to skip certain areas believed to be stable.
  • Speed: a script will execute many times faster than a manual test, giving you a full report on the quality of your product in a few minutes.
  • Formal: No more "testing-by-ear". A code coverage tool (if you wish to use one) can tell you how much code is tested. The test scripts can then tell you if what you test works fine. The result is the exact percentage of the code which is guaranteed to work fine.
  • Compactness: you can perform a full compatibility check by simply copying the application together with the test scripts on all the platforms where you believe it should work. It can give you the confirmation that all functionality works indeed as expected. Maybe in the not-so-distant future all applications will come with a "minimal self-test script" so that the user can be confident that his/her installation works as expected.

Common Pitfalls

Large companies would spend tens of thousands for a large-scale automated test system, would employ a few people with QA experience for the auto-test project and may spend a few more thousands for training people in the said test system. However much of this investment effort may go to waste if they are not aware of some of the most common pitfalls and misconceptions about automated tests:
  • Myth: automated tests are all about recording mouse and keyboard clicks and playing them back. Truth: This practice creates so many problems that is better to avoid it completely. Here's just a quick list of reasons:
    1. data generated is esentially hard coded, maintaining it is a nightmare;
    2. the recorder doesn't know when you're waiting for a certain event, so if you pause for some reason it will generate a time delay;
    3. as a consequence the recorder will generate delays every time you stop typing or moving the mouse. However if you were really waiting for some window to appear, the generated delay may be too short in some cases;
    4. changes in the interface layout, tab order, screen resolution, system speed (timing) have a good change to cause the recorded script to fail;
    5. screen, mouse and keyboard are 'tied' during playback: you're not allowed to touch them as any change in the active window, current keyboard focus or mouse position may cause the script to fail.
    Although Q1 has methods which operate on the system mouse we recommend using them only as a last resort, because of the disadvantages mentioned.
  • Myth: Anybody can write the scripts once they've learned the language, therefore taking some testers to a several days training course will pay back fast. Truth: Writing automated scripts is essentially a programming task and should be approached as such. For example tests should be designed first rather than implemented ad-hoc, data should not be hard-coded but passed as parameters or read from external files, common functionality should go into helper functions and be placed in common files and so on. A person without programming experience will make some very expensive beginner's mistakes, regardless of the language they're using.
  • Maintainability: failure to isolate the test logic from the user interface makes the script very sensitive to UI changes, requiring frequent maintenance.

Best Practices

  • Design your scripts with maintainability in mind. One of the most important factors in minimizing future work is structuring the code correctly from the start. Of course you will architecture your code based on your needs and time, but in theory a well designed script should contain:
    • An Interface between the script and the tested application, containing objects which wrap around your application UI and functions. You would only use these objects to manipulate your application. The goal is to separate UI elements from the test logic, so that when the user interface changes you will only need to update the wrapper object instead of going through all the code. For example if you have an 'Account' dialog with controls which allow you to edit the account's details, create a wrapper class accountWindow with variables for the controls. In the script code refer to them as accountWindow.Name instead ofapp.dialog("Account").edit(3). The wrapper objects are also an excellent place to store related helper functions (for example in selftest.js the Q1wnd object contains functions for setting breakpoints and opening files)
    • The actual Tests written as independent functions which use the wrapper objects. Their content is completely up to you, but read below for some best practices.
    • Some Test Management code. If you have a large set of tests and you follow the recommandations below and make them independent, then you can group them into test packs and execute each pack as needed.
    As long as the test scripts are small, all these three layers can fit into the same file, but when the script code base grows larger it makes sense to place them into separate files and even folders, just as you would with your application source code.
  • Start with smoke tests. Smoke tests are intended to cover a lot of functionality but only superficially, without going into details. They are short and easy to write, making them perfect as a first task while you're more focused on how to structure the scripts. They will give an immediate benefit and will be the most cost effective as they'll probably be run hundreds of times during the application's development. If you take an XP (extreme-programming) approach you can include the smoke tests into the build process and consider a programming task done when all the tests are running cleanly.
  • Make tests robust. There are three main requirements you must implement in order to create a solid and really automatic test suite:
    • self-configuration: the test should not require manual setup in order to run. If it needs some options to be set or certain data to be added to the database, it should do it itself. The ultimate goal is to have a test which runs at the click of a button. Automating such small steps may seem as extra work, but it will really save you lots of time in the long run.
    • independence: a test should not depend on a previous test to succeed, or to leave the data in a certain state. As much as possible each test should set up its own preconditions and clean up after itself, if it destroys data. This will achieve two goals: 1. tests can be replayed any number of times without manual intervention, and 2. you can run tests in any order, or run just a subset at a time.
    • recovery: if you have a large set of tests which take a long time to execute (hours), you may run into the following problem: a test fails and brings the application into an unexpected state, causing all other tests to fail. For example the application may crash, deadlock, or it may simply display a modal dialog box which no test knows how to close. If your leave your tests running and come back after a few hours, it is very annoying to find out they stopped after just two minutes. To solve this problem you can either kill and restart your application at the beginning of each pack of tests, or use exception handling to detect problems (ex: window not found) and to attempt to correct them.
  • Reuse as much as possible. Q1 makes use of Windows Scripting technologies to allow you to make the maximum out of the various script languages and ActiveX objects available. This version of Q1 does not allow mixing of different languages in the same script, but if you want to take advantage of this you can create separate files and run them independently. Also, have a look at all the COM and ActiveX components which implement various functionalities, for example the FileSystemObject for working with files and folders, ADO for working with databases, Accessibility for manipulating controls which don't have Q1 wrappers, MSXML for working with XML data files and so on. Whatever you need, chances are there is a COM component out there, which you can use in Q1. As many of them are free, a little research can save you both time and money.


Monday 22 September 2014

Recording a screen of what you are testing using selenium...

The screenrecorder used to track the where is the issue and which button/ui element is not working and also
 its usefull for showing the proof of bugs to dev..

import static org.monte.media.FormatKeys.EncodingKey;
import static org.monte.media.FormatKeys.FrameRateKey;
import static org.monte.media.FormatKeys.KeyFrameIntervalKey;
import static org.monte.media.FormatKeys.MIME_AVI;
import static org.monte.media.FormatKeys.MediaTypeKey;
import static org.monte.media.FormatKeys.MimeTypeKey;
import static org.monte.media.VideoFormatKeys.CompressorNameKey;
import static org.monte.media.VideoFormatKeys.DepthKey;
import static org.monte.media.VideoFormatKeys.ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE;
import static org.monte.media.VideoFormatKeys.QualityKey;

import java.awt.AWTException;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.junit.Test;
import org.monte.media.Format;
import org.monte.media.FormatKeys.MediaType;
import org.monte.media.math.Rational;
import org.monte.screenrecorder.ScreenRecorder;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class Login {
@Test
public static void main(String[] args) throws IOException, AWTException {
ScreenRecorder screenRecorder;

GraphicsConfiguration gconfig = GraphicsEnvironment
.getLocalGraphicsEnvironment().getDefaultScreenDevice()
.getDefaultConfiguration();

screenRecorder = new ScreenRecorder(gconfig, new Format(MediaTypeKey,
MediaType.FILE, MimeTypeKey, MIME_AVI), new Format(
MediaTypeKey, MediaType.VIDEO, EncodingKey,
ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE, CompressorNameKey,
ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE, DepthKey, (int) 24,
FrameRateKey, Rational.valueOf(15), QualityKey, 1.0f,
KeyFrameIntervalKey, (int) (15 * 60)), new Format(MediaTypeKey,
MediaType.VIDEO, EncodingKey, "black", FrameRateKey,
Rational.valueOf(30)), null);

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
screenRecorder.start();
driver.manage().window().maximize();
driver.get("enter your url");
//do some opertion here.
screenRecorder.stop();
//driver.close();
}

}

the recorded vidio is saved in your C:\Users\ngowda\Videos//screenrecorder.

Tuesday 26 August 2014

Guidelines for Automation framework design

Introduction
A Framework defines a set of guidelines for all phases of test automation: Requirement Analysis, Script Design, Execution, Reporting and maintenance. A framework can be a wrapper around some complex internal architecture which makes it easy to use for the end user. It also enforces a set of standards for implementation

Problem Statement
There is no standard set of guidelines available on developing a framework and what all considerations need to be taken during the development of the same. There are different white papers which go over types of framework and how they work. But none of them defines what all factors go in to the design of the same
Design guidelines
This paper covers different aspect of a framework and key features it needs to have based on the requirements.
  1. Selection of a framework – Different types of frameworks that exist are:
    • Data Driven framework – Used when flow of the application remains constant, only the data changes. The data is provided by external medium e.g. – excel sheet, XML etc…
    • Keyword driven framework – This framework provides generic keywords that can be used with any type of application. It also provides abstraction from the type of automation tool used and type of being application tested, e.g. – it can test a similar Web and Windows application with the same test case
    • Hybrid framework – A hybrid framework is the one which takes advantages from both Data Driven and keyword driven frameworks. These frameworks do not implement generic keywords but implement business logic keywords based on the application being tested. For ex – Login, Logout could be application specific keyword that can be used.
  2. Don’t reinvent the wheel – A framework should try and use the power of the automation tool rather than re-defining the whole language by implementing new keywords. Developing a keyword driven framework is time consuming and costly. A Hybrid framework can be developed in a shorter time period and with less cost.
  3. Reusability -The framework should allow highest possible reusability. Combining individual actions into business logic provides re-usability. E.g. – Combing actions like “Enter username”, “Enter password” and “Click Login” into one re-usable component “Login”
  4. Support of different application versions -A framework should allow re-use of baselines scripts in case different versions/flavors of an applications are to be tested. There are two different ways to support different applications
    • Copy and Modify – This method involves creating copies of the baseline scripts and modifying them for a specific application version
    • Re-use and Upgrade – This method involves re-using baseline script and providing a upgrade code for specific version of application. This ensures maximum re-usability and should be preferred.
  5. Support of script versioning – Scripts should be stored in a version control system like CVS, Microsoft® VSS etc…This ensures recovery from any disaster.
  6. Different environment for development and production – Automation should be considered as any other development project. Test scripts should be created and debugged in Test environment. Once tested then only should be deployed to the production environment. This holds true for any emergency releases also
  7. Externally Configurable – Configurable items of a script should be kept in an external file. This would contain configuration like Application URL, version, path etc…This allows running the same script against different environment. Ensure that location of the configuration file is not hard coded. Hard coded files would allow running on any environment but only one at a time. Keeping the configuration relative to current test path allows overcoming this limitation
  8. Self configurable – Ideally a framework should be self configurable. Once deployed to a system, no manual configuration changes should be required and scripts should automatically configure the required settings
  9. Minimal changes required for any object changes -Most common issues faced during automation are object identification changes. Framework should be able to patch such changes easily. This can be achieved by storing all object identification settings at a shared location. This could be an external XML file, excel file, database or automation proprietary format. There are two possible way to load this object identification configuration
    • Static – In this all the object definitions are loaded into the memory at the start of the test. Any changes made to object definition can only be loaded by stopping and re-running the test
    • Dynamic –Object definition is pulled as per request. This approach is a bit slow as compared to the static one. But in case of huge scripts where the fix needs to be made at run-time this is suitable.
  10. Execution – Framework might need to cater to below requirements (on need bases)
    • Execution of a individual test case
    • Execution of a test batch (combination of tests)
    • Re-execution of only failed test cases
    • Execution of a test case/test batch based on result of another test case/test batch
  11. There could be many other needs based on the project requirement. A framework might not implement all of them, but should be flexible enough to accommodate such requirements in future
  12. Status monitoring – A framework should allow monitoring the execution status in real time and should be capable of sending alerts in case of failure. This ensures quick turnaround time in event of a failure
  13. Reporting – Different applications have different reporting needs. Some require combined results for a test batch and some require individual level test report for each test case in test batch. The framework should be flexible enough to generate required reports
  14. Minimum dependency on Automation tool for changes – Some fixes can only be made by opening the script in the automation tool and then saving it. Scripts should be developed in such a way that modification is possible even without the unavailability of the automation tool. This deflates company cost by reducing the number of licenses required. It also allows anyone to make changes to the script without having the need to setup the tool
  15. Easy debugging -Debugging takes a lot of time during automation and hence special care needs to be taken for this part. Keyword driven frameworks which use external data source (like a excel spread sheet) to read scripts keywords and process the same are difficult to debug.
  16. Logging – Log generation is important part of execution. It is very important to generate debug information at various points in a test case. This information can help find problem area quickly and reduce the time to make a fix at the same time
  17. Easy to Use – The framework should be easy to learn and use. It is time consuming and costly to train a resource on a framework. A well documented framework is easier to understand and implement
  18. Flexible – Framework should be flexible enough to accommodate any enhancements without impacting existing test cases
  19. Performance impacts – A framework should also consider the performance impacts of the implementation. A complex framework which increases the load time or execution time of scripts is never desirable. Techniques like caching, compiling all code into single library while execution etc… should be used to improve performance whenever possible
  20. Framework Support Tools – External Tools can be developed to perform tasks that help in framework design. Some example tasks would be
    • Uploading scripts from local folder to HP Quality Center
    • Associating library files to currently open scripts
    • Synchronizing local files with HP Quality Center.
  21. Coding Standards – Coding standards ensures scripts that are consistent, readable and easily maintainable. Coding standard should define all the below listed things
    • Naming convention for variables, subs, functions, file names, script names etc… Ex – i_VarName for interger, fn_i_FuncName for function returning interger
    • Library, subs, functions comment header. This should include information like version history, created by, last modified by, last modified date, description, parameters, example
    • Object naming conventions. Ex – txt_FieldName for a text box

Summary
Automation should be considered as a development project and not just record and playback of events. Starting automated testing with a good framework ensures low maintenance. Guidelines discussed in this paper can be used as input for developing requirements for a framework.

Monday 4 August 2014

Selenium Web driver Architecture.

Architectural Themes

Before we start looking at the individual pieces to understand how they're wired together, it's useful to understand the the overarching themes of the architecture and development of the project. Succinctly put, these are:
·         Keep the costs down.
·         Emulate the user.
·         Prove the drivers work…
·         …but you shouldn't need to understand how everything works.
·         Lower the bus factor.
·         Have sympathy for a JavaScript implementation.
·         Every method call is an RPC call.
·         We are an Open Source project.
Before starting the automation using any automation tool, it is very important to know how that tool works and how it is architecture. This will helps to take the good advantage of the tool at the same time it will helps to make right automation framework. In my further posts I will start explain how to use selenium and how to create selenium framework in details but before that let’s get an overview of Selenium web driver architecture. Selenium can be a little bit confusing. As a beginner you will find how simply you can record and play the selenium scripts but it is not straight forward to how it’s doing that. At first glance it might appear that Selenium is actually driving the browser directly from your code but there’s actually a little bit more going on here and it’s going to help us understand how we can remote execute our test by looking at this basic architecture. So here’s a picture of the architecture for Selenium Web Driver, which is the current version of Selenium. 
Selenium web driver architecture mainly divided into three parts
1.    Language level bindings
2.    Selenium Web driver API
3.    Drivers
1) Language Level Bindings:
You can see at the Left hand side here we’ve got some bindings and these are language level bindings and with which you can implement the Selenium webdriver code. In simple words these the languages in which are making an framework, will interact with the Selenium Webdriver and work on various browsers and other devices. So we have a common API that we use for Selenium that has a common set of commands and we have various bindings for the different languages. So you can see there’s Java, Java, Python, Ruby, there’s also some other bindings and new bindings can be added very easily.
2) Selenium Web driver API:
Now these bindings communicate with Selenium Web driver API and This API send the commands taken from language level bindings interpret it and sent it to Respective driver. Right now don’t worry about how it works. I will explain them in upcoming posts. In basic term it contains set of common library which allow sending command to respective drivers.
3) Drivers:
Drivers here at the right hand side, you see we have various internet browser specific drivers such as IE driver, a Firefox, Chrome, and other drivers such as HTML unit which is an interesting one. It works in headless mode which makes text execution faster. It also contains mobile specific drivers as well. But the basic idea here is that each one of these drivers knows how to drive the browser that it corresponds to. So the Chrome driver knows how to handle the low level details of Chrome browser and drive it to do things like clicking button, going into pages, getting data from the browser itself, the same thing for Firefox, IE, and so on.

How all blocks work together?
So what’s happening here is you’re going to write your test in let’s say in Java and you’re going to be using common Selenium API and that Java binding is going to be sending command across this common Web Driver API. Now on the other end is going to be listening a driver, It’s going to interpret those commands and it’s going to execute them on the actual browser and then it’s going to return the result backup using the Web Driver API to your code where you can look at that result.
Let’s take more closure look that how exactly that works
Let say you have written test using java (binding code) against Selenium API and that binding code is going to issue commands across Web Driver wire protocol this is a rest-based web service that is able to interpret those commands. The driver server is just a little executable that runs each one of the drivers has this driver server that basically listens on a port on your local machine when you run your tests and it’s waiting for these commands to come in. And when these commands come in it interprets those commands and then automates the browser and then returns those results back.

I hope this will give some clear idea about how Selenium Web driver being architect.

Wednesday 23 July 2014

Database testing using java:

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.
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 site http://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 SELECT statements 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 allowMultiQueries parameter 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 the getMoreResults() 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 the getResultSet() 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 FileInputStream object.
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.