Lecture 12_Java Programming note for BCA, B.Sc. CSIT and BIT and BE
Lecture 12_Java Programming note for BCA, B.Sc. CSIT and BIT and BE
A database is an organized collection of data. There are many different strategies for organizing data to
facilitate easy access and manipulation. A database management system(DBMS) provides mechanisms
for storing, organizing, retrieving and modifying data form any users. Database management systems
allow for the access and storage of data without concern for the internal representation of data.
Today’s most popular database systems are relational databases.A language called SQL—pronounced
“sequel,” or as its individual letters—is the international standard language used almost universally with
relational databases to perform queries (i.e., to request information that satisfies given criteria) and to
manipulate data.
Some popular relational database management systems (RDBMSs) are Microsoft SQL Server, Oracle,
Sybase, IBM DB2, Informix, PostgreSQL and MySQL. The JDK now comes with a pure-Java RDBMS called
Java DB—Oracles’s version of Apache Derby.
Java programs communicate with databases and manipulate their data using the Java Database
Connectivity (JDBC™) API. A JDBC driver enables Java applications to connect to a database in a particular
DBMS and allows you to manipulate that database using the JDBC API.
JDBC Introduction
The JDBC API is a Java API that can access any kind of tabular data, especially data stored in a Relational
Database.
JDBC helps to write Java applications that manage these three programming activities:
• Retrieve and process the results received from the database in answer to your query
JDBC Driver Manager — The JDBC DriverManager class defines objects which can connect Java
applications to a JDBC driver. DriverManager has traditionally been the backbone of the JDBC architecture.
It is quite small and simple.
JDBC Test Suite — The JDBC driver test suite helps you to determine that JDBC drivers will run your
program. These tests are not comprehensive or exhaustive, but they do exercise many of the important
features in the JDBC API.
JDBC-ODBC Bridge — The Java Software bridge provides JDBC access via ODBC drivers. Note that you
need to load ODBC binary code onto each client machine that uses this driver. As a result, the ODBC driver
is most appropriate on a corporate network where client installations are not a major problem, or for
application server code written in Java in a three-tier architecture.
• A type 2 driver is written partly in Java and partly in native code; it communicates with the client
API of a database. When you use such a driver, you must install some platform-specific code in
addition to a Java library.
• A type 3 driver is a pure Java client library that uses a database-independent protocol to
communicate database requests to a server component, which then translates the requests into
a database-specific protocol. This can simplify deployment since the database-dependent code is
located only on the server.
• A type 4 driver is a pure Java library that translates JDBC requests directly to a database-specific
protocol.
Most database vendors supply either a type 3 or type 4 driver with their database. Furthermore, a
number of third-party companies specialize in producing drivers with better standards conformance,
support for more platforms, better performance, or, in some cases, simply better reliability than the
drivers that are provided by the database vendors.
Communication between the client and middle tier can occur through HTTP (when you use a web browser
as the client), RMI (when you use an application), or another mechanism. JDBC manages the
communication between the middle tier and the back-end database. Figure below shows the basic three
tier architecture.
Extract the zip file to a folder, you’ll see file ‘mysql-connector-java-5.1.20-bin.jar’ which is the library file
that we want. Just copy the file to the library folder, for example to “C:\Program Files\Java\jdk1.7\lib”
also to the “C:\Program Files\Java\jdk1.7\jre\lib directory.
In the services tab of the netbeans , right click the database and click on 'new connection'. Under the
'new connection wizard', click on the 'Driver Combobox' and select the 'mySQL Connector/J driver' and
click on 'next' untill the wizard completes.
// DisplayAuthors.java
// Displaying the contents of the Authors table.
import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
while(resultSet.next())
{
for ( int i = 1; i <= numberOfColumns; i++ )
System.out.printf( "%-8s\t",resultSet.getObject( i ));
System.out.println();
} // end while
} // end try
catch(SQLException sqlException)
{
sqlException.printStackTrace();
} // end catch
finally // ensure resultSet, statement and connection are closed
{
try
{
resultSet.close();
statement.close();
connection.close();
} // end try
catch ( Exception exception )
{
exception.printStackTrace();
} // end catch
} // end finally
} // end main
} // end class DisplayAuthors
output
ResultSet Interface
The ResultSet interface provides methods for retrieving and manipulating the results of executed queries,
and ResultSet objects can have different functionality and characteristics. These characteristics are type,
concurrency, and cursor holdability.
ResultSet Types
The type of a ResultSet object determines the level of its functionality in two areas: the ways in which the
cursor can be manipulated, and how concurrent changes made to the underlying data source are reflected
by the ResultSet object.
The sensitivity of a ResultSet object is determined by one of three different ResultSet types:
(a) TYPE_FORWARD_ONLY: The result set cannot be scrolled; its cursor moves forward only, from before
the first row to after the last row. The rows contained in the result set depend on how the underlying
database generates the results. That is, it contains the rows that satisfy the query at either the time the
query is executed or as the rows are retrieved.
(b) TYPE_SCROLL_INSENSITIVE: The result can be scrolled; its cursor can move both forward and
backward relative to the current position, and it can move to an absolute position. The result set is
insensitive to changes made to the underlying data source while it is open. It contains the rows that
satisfy the query at either the time the query is executed or as the rows are retrieved.
(c)TYPE_SCROLL_SENSITIVE: The result can be scrolled; its cursor can move both forward and backward
relative to the current position, and it can move to an absolute position. The result set reflects changes
made to the underlying data source while the result set remains open.
Note: Not all databases and JDBC drivers support all ResultSet types. The method
DatabaseMetaData.supportsResultSetType returns true if the specified ResultSet type is supported and
false otherwise.
ResultSet Concurrency
The concurrency of a ResultSet object determines what level of update functionality is supported.
There are two concurrency levels:
CONCUR_READ_ONLY: The ResultSet object cannot be updated using the ResultSet interface.
CONCUR_UPDATABLE: The ResultSet object can be updated using the ResultSet interface.
The following ResultSet constants may be supplied to the Connection methods createStatement,
prepareStatement, and prepareCall:
HOLD_CURSORS_OVER_COMMIT: ResultSet cursors are not closed; they are holdable: they are held
open when the method commit is called. Holdable cursors might be ideal if your application uses mostly
read-only ResultSet objects.
CLOSE_CURSORS_AT_COMMIT: ResultSet objects (cursors) are closed when the commit method is
called. Closing cursors when this method is called can result in better performance for some applications.
// query database
resultSet = statement.executeQuery(
"SELECT AuthorID, FirstName, LastName FROM authors" );
while ( resultSet.next() )
{
int id = rs.getInt("AuthorID");
String firstName = rs.getString("FirstName");
String lastName = rs.getString("LastName");
System.out.println(id+ "\t" + firstName+
"\t" + lastName );
} // end while
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
Cursors
As mentioned previously, you access the data in a ResultSet object through a cursor, which points to one
row in the ResultSet object. However, when a ResultSet object is first created, the cursor is positioned
before the first row.There are other methods available to move the cursor:
next: Moves the cursor forward one row. Returns true if the cursor is now positioned on a row and false
if the cursor is positioned after the last row.
previous: Moves the cursor backward one row. Returns true if the cursor is now positioned on a row
and false if the cursor is positioned before the first row.
first: Moves the cursor to the first row in the ResultSet object. Returns true if the cursor is now
positioned on the first row and false if the ResultSet object does not contain any rows.
last: Moves the cursor to the last row in the ResultSet object. Returns true if the cursor is now
positioned on the last row and false if the ResultSet object does not contain any rows.
beforeFirst: Positions the cursor at the start of the ResultSet object, before the first row. If the ResultSet
object does not contain any rows, this method has no effect.
afterLast: Positions the cursor at the end of the ResultSet object, after the last row. If the ResultSet
object does not contain any rows, this method has no effect.
relative(int rows): Moves the cursor relative to its current position.
absolute(int row): Positions the cursor on the row specified by the parameter row.
Note that the default sensitivity of a ResultSet is TYPE_FORWARD_ONLY, which means that it cannot be
scrolled; you cannot call any of these methods that move the cursor, except next, if your ResultSet cannot
be scrolled.
try {
// establish connection to database
connection = DriverManager.getConnection(
DATABASE_URL, "root", "" );
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs= statement.executeQuery(
"SELECT * FROM authors");
while (uprs.next()) {
uprs.updateString( "LastName","Sharma");
uprs.updateRow();
}
}
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
The field ResultSet.TYPE_SCROLL_SENSITIVE creates a ResultSet object whose cursor can move both
forward and backward relative to the current position and to an absolute position. The field
ResultSet.CONCUR_UPDATABLE creates a ResultSet object that can be updated. See the ResultSet
Javadoc for other fields you can specify to modify the behavior of ResultSet objects.
The method ResultSet.updateString updates the specified column (in this example, LastName with the
specified float value in the row where the cursor is positioned. ResultSet contains various updater
methods that enable you to update column values of various data types. However, none of these updater
methods modifies the database; you must call the method ResultSet.updateRow to update the database.
try {
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
uprs.moveToInsertRow();
uprs.updateInt("AuthorID",9);
uprs.updateString("FirstName","Subash");
uprs.updateString("LastName","Pakhrin");
uprs.insertRow();
uprs.beforeFirst();
}
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
The same stipulations for using strings in getter methods also apply to updater methods.
The method ResultSet.moveToInsertRow moves the cursor to the insert row. The insert row is a special
row associated with an updatable result set. It is essentially a buffer where a new row can be constructed
by calling the updater methods prior to inserting the row into the result set. For example, this method
calls the method ResultSet.updateString to update the insert row's COF_NAME column to Kona.
The method ResultSet.insertRow inserts the contents of the insert row into the ResultSet object and into
the database.
Note: After inserting a row with the ResultSet.insertRow, you should move the cursor to a row other than
the insert row. For example, this example moves it to before the first row in the result set with the method
ResultSet.beforeFirst. Unexpected results can occur if another part of your application uses the same
result set and the cursor is still pointing to the insert row.
The list, which is associated with a Statement object at its creation, is initially empty. You can add SQL
commands to this list with the method addBatch and empty it with the method clearBatch. When you
have finished adding statements to the list, call the method executeBatch to send them all to the database
to be executed as a unit, or batch.
try {
connection = DriverManager.getConnection(
DATABASE_URL, "root", "" );
connection.setAutoCommit(false);
statement = connection.createStatement();
statement.addBatch(
"INSERT INTO authors " +
"VALUES('15','Hari','Shrestha')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('16','Ram','Acharya')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('17','Shyam','Gautam')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('18','Govinda','Paudel')");
} catch(BatchUpdateException b) {
b.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
The following line disables auto-commit mode for the Connection object con so that the transaction will
not be automatically committed or rolled back when the method executeBatch is called.
connection.setAutoCommit(false);
To allow for correct error handling, you should always disable auto-commit mode before beginning a
batch update.
The method Statement.addBatch adds a command to the list of commands associated with the
Statement object statement. In this example, these commands are all INSERT INTO statements, each one
adding a row consisting of three column values.
The following line sends the four SQL commands that were added to its list of commands to the database
to be executed as a batch:
Note that statement uses the method executeBatch to send the batch of insertions, not the method
executeUpdate, which sends only one command and returns a single update count. The DBMS executes
the commands in the order in which they were added to the list of commands, so it will first add the row
of values for "Hari" , then add the row for "Ram", then "Shyam" , and finally "Govinda". If all four
commands execute successfully, the DBMS will return an update count for each command in the order in
which it was executed. The update counts that indicate how many rows were affected by each command
are stored in the array updateCounts.
If all four of the commands in the batch are executed successfully, updateCounts will contain four
values, all of which are 1 because an insertion affects one row. The list of commands associated with
stmt will now be empty because the four commands added previously were sent to the database when
stmt called the method executeBatch. You can at any time explicitly empty this list of commands with the
method clearBatch.
The Connection.commit method makes the batch of updates to the "authors" table permanent. This
method needs to be called explicitly because the auto-commit mode for this connection was disabled
previously.
The following line enables auto-commit mode for the current Connection object.
connection.setAutoCommit(true);
Now each statement in the example will automatically be committed after it is executed, and it no
longer needs to invoke the method commit.
PreparedStatements
A PreparedStatement enables you to create compiled SQL statements that execute more efficiently than
Statements. PreparedStatements can also specify parameters, making them more flexible than
Statements—you can execute the same query repeatedly with different
parameter values.
The PreparedStatement is derived from the more general class, Statement. If you want to execute a
Statement object many times, it usually reduces execution time to use a PreparedStatement object
instead.
Performing Parameterized Batch Update using PreparedStatement
It is also possible to have a parameterized batch update, as shown in the following code fragment, where
con is a Connection object:
try {
connection = DriverManager.getConnection(
DATABASE_URL, "root", "" );
connection.setAutoCommit(false);
PreparedStatement pstmt = connection.prepareStatement(
"INSERT INTO authors VALUES(?, ?, ?)");
pstmt.setInt(1,19);
pstmt.setString(2, "Navin");
pstmt.setString(3,"Sharma");
pstmt.addBatch();
pstmt.setInt(1,20);
pstmt.setString(2, "Rajesh");
pstmt.setString(3,"Paudel");
pstmt.addBatch();
The three question marks (?) in the the preceding SQL statement’s last line are placeholders for values
that will be passed as part of the query to the database. Before executing a PreparedStatement, the
program must specify the parameter values by using the Prepared- Statement interface’s set methods.
For the preceding query, parameters are int and strings that can be set with Prepared- Statement method
setInt and setString.
Method setInt's and setString’s first argument represents the parameter number being set, and the
second argument is that parameter’s value. Parameter numbers are counted from 1, starting with the
first question mark (?).
Interface PreparedStatement provides set methods for each supported SQL type. It’s important to use
the set method that is appropriate for the parameter’s SQL type in the database—SQLExceptions occur
when a program attempts to convert a parameter value to an incorrect type.
Transaction Processing
Many database applications require guarantees that a series of database insertions, updates and deletions
executes properly before the application continues processing the next database operation. For example,
when you transfer money electronically between bank accounts, several factors determine if the
transaction is successful. You begin by specifying the source account and the amount you wish to transfer
from that account to a destination account. Next, you specify the destination account. The bank checks
the source account to determine whether its funds are sufficient to complete the transfer. If so, the bank
withdraws the specified amount and, if all goes well, deposits it into the destination account to complete
the transfer. What happens if the transfer fails after the bank withdraws the money from the source
account? In a proper banking system, the bank redeposits the money in the source account.The way to
be sure that either both actions occur or neither action occurs is to use a transaction. A transaction is a
set of one or more statements that is executed as a unit, so either all of the statements are executed,
or none of the statements is executed.
The way to allow two or more statements to be grouped into a transaction is to disable the auto-
commit mode.
Disabling Auto-Commit Mode
When a connection is created, it is in auto-commit mode. This means that each individual SQL statement
is treated as a transaction and is automatically committed right after it is executed.
The way to allow two or more statements to be grouped into a transaction is to disable the auto-
commit mode.
con.setAutoCommit(false);
Committing Transactions
After the auto-commit mode is disabled, no SQL statements are committed until you call the method
commit explicitly. All statements executed after the previous call to the method commit are included in
the current transaction and committed together as a unit.
con.commit();
Rollback
If you group update statements to a transaction, then the transaction either succeeds in its entirety and
it can be committed, or it fails somewhere in the middle. In that case, you can carry out a rollback and the
database automatically undoes the effect of all updates that occurred since the last committed
transaction.
Save Points
You can gain finer-grained control over the rollback process by using save points. Creating a save point
marks a point to which you can later return without having to return to the start of the transaction. For
example,
Here, we used an anonymous save point. You can also give the save point a name, such as
Savepoint svpt = conn.setSavepoint("stage1");
When you are done with a save point, you should release it:
stat.releaseSavepoint(svpt);
import java.sql.Connection;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.BatchUpdateException;
import java.sql.PreparedStatement;
try {
// establish connection to database
connection = DriverManager.getConnection(
DATABASE_URL, "root", "" );
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs= statement.executeQuery(
"SELECT * FROM authors");
while (uprs.next()) {
uprs.updateString( "LastName","Sharma");
uprs.updateRow();
}
}
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
try {
statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
uprs.moveToInsertRow();
uprs.updateInt("AuthorID",9);
uprs.updateString("FirstName","Subash");
uprs.updateString("LastName","Pakhrin");
uprs.insertRow();
uprs.beforeFirst();
}
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
try {
connection.setAutoCommit(false);
statement = connection.createStatement();
statement.addBatch(
"INSERT INTO authors " +
"VALUES('15','Hari','Shrestha')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('16','Ram','Acharya')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('17','Shyam','Gautam')");
statement.addBatch(
"INSERT INTO authors " +
"VALUES('18','Govinda','Paudel')");
} catch(BatchUpdateException b) {
b.printStackTrace();
} catch(SQLException ex) {
ex.printStackTrace();
}
try {
connection.setAutoCommit(false);
PreparedStatement pstmt = connection.prepareStatement(
"INSERT INTO authors VALUES(?, ?, ?)");
pstmt.setInt(1,19);
pstmt.setString(2, "Navin");
pstmt.setString(3,"Sharma");
pstmt.addBatch();
pstmt.setInt(1,20);
pstmt.setString(2, "Rajesh");
pstmt.setString(3,"Paudel");
pstmt.addBatch();
// query database
resultSet = statement.executeQuery(
"SELECT AuthorID, FirstName, LastName FROM authors" );
while ( resultSet.next() )
{
for ( int i = 1; i <= numberOfColumns; i++ )
System.out.printf( "%-8s\t", resultSet.getObject( i ) );
System.out.println();
} // end while
} // end try
catch ( SQLException sqlException )
{
sqlException.printStackTrace();
} // end catch
} // end try
catch ( Exception exception )
{
exception.printStackTrace();
} // end catch
} // end finally
} // end main
} // end class DisplayAuthors
RowSet Interface
A JDBC RowSet object holds tabular data in a way that makes it more flexible and easier to use than a
result set.The RowSet interface configures the database connection and prepares query statements
automatically.It provides several set methods that allow you to specify the properties needed to establish
a connection (such as the database URL, user name and password of the database) and create a
Statement (such as a query). RowSet also provides several get methods that return these properties.
Connected and Disconnected RowSets
There are two types of RowSet objects—connected and disconnected. A connected RowSet object
connects to the database once and remains connected while the object is in use. A disconnected RowSet
object connects to the database, executes a query to retrieve the data from the database and then closes
the connection. A program may change the data in a disconnected RowSet while it’s disconnected.
Modified data can be updated in the database
after a disconnected RowSet reestablishes the connection with the database.
JdbcRowSet
Navigating JdbcRowSet Objects
JdbcRowSet jdbcRs = new JdbcRowSetImpl();
jdbcRs.absolute(4);
jdbcRs.previous();
Inserting Rows
jdbcRs.moveToInsertRow();
jdbcRs.updateInt("Author_ID", 10);
jdbcRs.updateString("FirstName", "Navin");
jdbcRs.updateString("LastName", "Sharma");
jdbcRs.insertRow();
Deleting Rows
jdbcRs.last();
jdbcRs.deleteRow();
CachedRowSet
Creating CachedRowSet Objects:
achedRowSet crs = new CachedRowSetImpl();
Setting up command:
crs.setCommand("select * from Authors");