Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ganesh_JavaSE7_Programming_1z0-804_study_guide.pdf
Скачиваний:
94
Добавлен:
02.02.2015
Размер:
5.88 Mб
Скачать

Chapter 10 Building Database Applications with JDBC

Points to Remember

Here are a couple of points that could be helpful on your OCPJP exam:

The boolean absolute(int) method in ResultSet moves the cursor to the passed row number in that ResultSet object. If the row number is positive, it moves to that position from the beginning of the ResultSet object; if the row number is negative, it moves to that position from the end of the ResultSet object. Assume that there are 10 entries in the ResultSet object. Calling absolute(3) will move the cursor to the third row. Calling absolute(−3) will move the cursor to the 10–3, seventh row. If you give out of range values, the cursor will move to either beginning or end.

In a ResultSet object, calling absolute(1) is equivalent to calling first(), and calling absolute(−1) is equivalent to calling last().

Performing Transactions

A transaction is a set of SQL operations that needs to be either executed all successfully or not at all. Failure to perform even one operation leads to an inconsistent and erroneous database.

A database must satisfy the ACID properties (Atomicity, Consistency, Isolation, and Durability) to guarantee the success of a database transaction.

Atomicity: Each transaction should be carried out in its entirety; if one part of the transaction fails, then the whole transaction fails.

Consistency: The database should be in a valid state before and after the performed transaction.

Isolation: Each transaction should execute in complete isolation without knowing the existence of other transactions.

Durability: Once the transaction is complete, the changes made by the transaction are permanent (even in the occurrence of unusual events such as power loss).

A classic example of a transaction is fund transfer through a bank account. If one wants to transfer some money x to another account, the money x should be deducted from the first account and should be added to the other account. In essence, there are two operations to complete the fund transfer (which you can call a transaction). Failing either operation is not acceptable: if money is deducted from the first account and not added to the other account, the

first account holder unnecessarily loses x amount of money; if the second account gets x amount of money without deducting from the first account, the bank will definitely have a problem. Hence, either both the operations should be successful or both operations should fail.

 All operations of a transaction must be either successful or not happen at all.

In general, each statement is a transaction in a JDBC environment. What does this mean? When you call methods such as updateRow(), the JDBC immediately updates the underlying database. This behavior of JDBC can be controlled by the setAutoCommit() method; by default it is true, so each update statement changes the database

300

Chapter 10 Building Database Applications with JDBC

immediately. However, if you set this property to false, it is your responsibility to call the commit() method on the Connection object. The commit() method actually commits all the changes to the database.

Before seeing an example program for a transaction using the Connection interface, you’ll first see transaction related methods supported in this class (Table 10-3). (Note that all the methods given in this table may throw SQLException, so we don’t mention that explicitly in this table for each method.)

Table 10-3.  Transaction-Related Methods in the Connection Interface

 

 

Method

Description

void setAutoCommit(boolean autoCommit)

Sets the auto-commit mode to true or false. By default,

 

Connection objects have auto-commit set to true, and you

 

can set it to false by calling this method with false as the

 

argument value.

boolean getAutoCommit()

Returns the auto-commit mode value (a true value means

 

auto-commit mode, and a false value means manual

 

commit mode).

Savepoint setSavepoint()

Creates a Savepoint object in the current transaction and

 

returns that object.

Savepoint setSavepoint(String name)

Same as the previous method, except that the Savepoint

 

object has a name associated with it.

void releaseSavepoint(Savepoint savepoint)

Removes the given Savepoint object and the subsequent

 

Savepoint objects from the current transaction.

void rollback(Savepoint savepoint)

Rolls back to the given Savepoint state. In other words, all

 

the changes done after the Savepoint was created will be

 

lost or removed (an undo operation till that Savepoint).

 

Will throw a SQLException if rollback cannot be done

 

(for example, an invalid Savepoint object is passed).

void rollback()

Rolls back (undoes) all the changes made in the current

 

transaction. Will throw a SQLException if rollback fails

 

(e.g., rollback() was called when auto-commit mode is set).

void commit()

Makes (commits) all the changes done so far in the

 

transaction to the database.

 

 

Let’s understand transactions with the help of an example. As you recall, you have a MySQL database named addressBook in which you have a table named contact. Now, you want to have different groups of contacts; for instance, one such group is familyGroup; you are maintaining another table called familyGroup for family members. Let’s imagine now that you want to add a new record in the familyGroup table (you are storing only nicknames of the family members) along with full contact details in the table contact. Imagine a situation where you add the nickname of a family member in familyGroup but could not add the full contact details of your contact! The situation would lead to an inconsistent database. This is an example of a transaction since you want to execute both operations successfully (or don’t want to make changes at all, so that you can make an attempt again). Listing 10-11 contains a small program to achieve it.

301

Chapter 10 Building Database Applications with JDBC

Listing 10-11.  DbTransaction.java

import java.sql.*;

// To illustrate how to do commit or rollback class DbTransaction {

public static void main(String[] args) throws SQLException { Connection connection = DbConnector.connectToDb(); ResultSet resultSet1 = null, resultSet2 = null;

//we're using explicit finally blocks

//instead of try-with-resources statement in this code try {

//for commit/rollback we first need to set auto-commit to false connection.setAutoCommit(false);

Statement statement = connection.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

resultSet1 = statement.executeQuery("SELECT * FROM familyGroup"); resultSet1.moveToInsertRow(); resultSet1.updateString("nickName", "Sam Uncle");

//updating here. . . but this change will be lost if a rollback happens

resultSet1.insertRow(); System.out.println("First table updated. . .");

resultSet2 = statement.executeQuery("SELECT * FROM contact"); resultSet2.moveToInsertRow(); resultSet2.updateString("firstName", "Samuel");

// resultSet2.updateString("firstName",

"The great Samuel the billionaire from Washington DC"); resultSet2.updateString("lastName", "Uncle"); resultSet2.updateString("email", "sam@abc.com"); resultSet2.updateString("phoneNo", "+119955331100");

//updating here. . . but this change will be lost of a rollback happens resultSet2.insertRow();

System.out.println("Both tables updated, committing now.");

//we're committing the changes for both the tables only now connection.commit();

}catch (SQLException e) {

System.out.println(

"Something gone wrong, couldn't add a contact in family group");

// roll back all the changes in the transaction since something has gone wrong connection.rollback();

e.printStackTrace();

}

finally {

if(connection != null) connection.close(); if(resultSet1 != null) resultSet1.close(); if(resultSet2 != null) resultSet2.close();

}

}

}

302

Chapter 10 Building Database Applications with JDBC

Let’s understand the program first. There are basically two operations in the transaction. The first is to add a new row in the table called familyGroup for the contact “Sam Uncle.” The second is to add the full contact details of “Sam Uncle” in the table called contact. Now, look at the key differences: you call the setAutoCommit() method with argument false; hence, auto commit will not happen. Another difference is that you are calling the method commit() with a connection object. Hence, when both the operations are successful, you will update the database (with scheduled updates) by calling the commit() method.

Now, let’s execute this program and see what it prints.

Something gone wrong, couldn't add a contact in family group com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'addressbook.familygroup' doesn't exist

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [. . . this part of the stack trace elided to save space . . .]

at DbTransaction.main(DbTransaction.java:18)

What happened? You haven’t created a familyGroup table yet. Do it in the MySQL command line.

mysql> create table familyGroup (id int not null auto_increment, nickName varchar(30) Not null, primary key (id));

Query OK, 0 rows affected (0.11 sec)

Now try running the program again.

First table updated. . .

Something gone wrong, couldn't add a contact in family group

com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'firstName' at row 1 at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4072)

[. . . this part of stack trace elided to save space . . .] at DbTransaction.main(DbTransaction.java:43)

Well, you got a SQLException since the string provided for Uncle Sam’s name is too long. You can observe that the first table got updated and the exception occurred while executing the second operation. However, you have set the auto commit mode to false; hence, the first table is not changed in the database. Both the tables will actually be changed when you execute the commit() method. In other words, if the commit() method does not execute in manual commit mode, then there will be no change in the database. In the above example, neither table got changed since the exception occurred before the commit() method could execute.

Let’s change the name of the Sam uncle in the updateString() method (in the above program) and rerun the example. Replace the earlier statement with this new statement:

resultSet2.updateString("firstName", "Samuel");

Let’s see the output of the program this time.

First table updated. . .

Both tables updated, committing now.

Perfect! Both operations worked this time, so the transaction is complete.

303

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]