
- •Contents at a Glance
- •Contents
- •About the Authors
- •About the Technical Reviewer
- •Acknowledgments
- •Introduction
- •Oracle Java Certifications: Overview
- •FAQ 1. What are the different levels of Oracle Java certification exams?
- •FAQ 4. Is OCPJP 7 prerequisite for other Oracle certification exams?
- •FAQ 5. Should I take the OCPJP 7 or OCPJP 6 exam?
- •The OCPJP 7 Exam
- •FAQ 7. How many questions are there in the OCPJP 7 exam?
- •FAQ 8. What is the duration of the OCPJP 7 exam?
- •FAQ 9. What is the cost of the OCPJP 7 exam?
- •FAQ 10. What are the passing scores for the OCPJP 7 exam?
- •FAQ 11. What kinds of questions are asked in the OCPJP 7 exam?
- •FAQ 12. What does the OCPJP 7 exam test for?
- •FAQ 13. I’ve been a Java programmer for last five years. Do I have to prepare for the OCPJP 7 exam?
- •FAQ 14. How do I prepare for the OCPJP 7 exam?
- •FAQ 15. How do I know when I’m ready to take the OCPJP 7 exam?
- •Taking the OCPJP 7 Exam
- •FAQ 16. What are my options to register for the exam?
- •FAQ 17. How do I register for the exam, schedule a day and time for taking the exam, and appear for the exam?
- •The OCPJP 7 Exam: Pretest
- •Answers with Explanations
- •Post-Pretest Evaluation
- •Essentials of OOP
- •FunPaint Application: An Example
- •Foundations of OOP
- •Abstraction
- •Encapsulation
- •Inheritance
- •Polymorphism
- •Class Fundamentals
- •Object Creation
- •Constructors
- •Access Modifiers
- •Public Access Modifier
- •Private Access Modifier
- •Protected and Default Access Modifier
- •Overloading
- •Method Overloading
- •Constructor Overloading
- •Overload resolution
- •Points to Remember
- •Inheritance
- •Runtime Polymorphism
- •An Example
- •Overriding Issues
- •Overriding: Deeper Dive
- •Invoking Superclass Methods
- •Type Conversions
- •Upcasts and Downcasts
- •Casting Between Inconvertible Types
- •Using “instanceof” for Safe Downcasts
- •Java Packages
- •Working with Packages
- •Static Import
- •Summary
- •Abstract Classes
- •Points to Remember
- •Using the “final” Keyword
- •Final Classes
- •Final Methods and Variables
- •Points to Remember
- •Using the “static” Keyword
- •Static Block
- •Points to Remember
- •Flavors of Nested Classes
- •Static Nested Classes (or Interfaces)
- •Points to Remember
- •Inner Classes
- •Points to Remember
- •Local Inner Classes
- •Points to Remember
- •Anonymous Inner Classes
- •Points to Remember
- •Enum Data Types
- •Points to Remember
- •Summary
- •Interfaces
- •Declaring and Using Interfaces
- •Points to Remember
- •Abstract Classes vs. Interfaces
- •Choosing Between an Abstract Class and an Interface
- •Object Composition
- •Composition vs. Inheritance
- •Points to Remember
- •Design Patterns
- •The Singleton Design Pattern
- •Ensuring That Your Singleton Is Indeed a Singleton
- •The Factory Design Pattern
- •Differences Between Factory and Abstract Factory Design Patterns
- •The Data Access Object (DAO) Design Pattern
- •Points to Remember
- •Summary
- •Generics
- •Using Object Type and Type Safety
- •Using the Object Class vs. Generics
- •Container Implementation Using the Object Class
- •Container Implementation Using Generics
- •Creating Generic Classes
- •Diamond Syntax
- •Interoperability of Raw Types and Generic Types
- •Generic Methods
- •Generics and Subtyping
- •Wildcard Parameters
- •Limitations of Wildcards
- •Bounded Wildcards
- •Wildcards in the Collections Class
- •Points to Remember
- •The Collections Framework
- •Why Reusable Classes?
- •Basic Components of the Collections Framework
- •Abstract Classes and Interfaces
- •Concrete Classes
- •List Classes
- •ArrayList Class
- •The ListIterator Interface
- •The LinkedList Class
- •The Set Interface
- •The HashSet Class
- •The TreeSet Class
- •The Map Interface
- •The HashMap Class
- •Overriding the hashCode() Method
- •The NavigableMap Interface
- •The Queue Interface
- •The Deque Interface
- •Comparable and Comparator Interfaces
- •Algorithms (Collections Class)
- •The Arrays Class
- •Methods in the Arrays Class
- •Array as a List
- •Points to Remember
- •Summary
- •Generics
- •Collections Framework
- •Processing Strings
- •String Searching
- •The IndexOf() Method
- •The regionMatches() Method
- •String Parsing
- •String Conversions
- •The Split() Method
- •Regular Expressions
- •Understanding regex Symbols
- •Regex Support in Java
- •Searching and Parsing with regex
- •Replacing Strings with regex
- •String Formatting
- •Format Specifiers
- •Points to Remember
- •Summary
- •Reading and Writing from Console
- •Understanding the Console Class
- •Formatted I/O with the Console Class
- •Special Character Handling in the Console Class
- •Using Streams to Read and Write Files
- •Character Streams and Byte Streams
- •Character Streams
- •Reading Text Files
- •Reading and Writing Text Files
- •“Tokenizing” Text
- •Byte Streams
- •Reading a Byte Stream
- •Data Streams
- •Writing to and Reading from Object Streams: Serialization
- •Serialization: Some More Details
- •Points to Remember
- •Summary
- •A Quick History of I/O APIs
- •Using the Path Interface
- •Getting Path Information
- •Comparing Two Paths
- •Using the Files Class
- •Checking File Properties and Metadata
- •Copying a File
- •Moving a File
- •Deleting a File
- •Walking a File Tree
- •Revisiting File Copy
- •Finding a File
- •Watching a Directory for Changes
- •Points to Remember
- •Summary
- •Introduction to JDBC
- •The Architecture of JDBC
- •Two-Tier and Three-Tier JDBC Architecture
- •Types of JDBC Drivers
- •Setting Up the Database
- •Connecting to a Database Using a JDBC Driver
- •The Connection Interface
- •Connecting to the Database
- •Statement
- •ResultSet
- •Querying the Database
- •Updating the Database
- •Getting the Database Metadata
- •Points to Remember
- •Querying and Updating the Database
- •Performing Transactions
- •Rolling Back Database Operations
- •The RowSet Interface
- •Points to Remember
- •Summary
- •Define the Layout of the JDBC API
- •Connect to a Database by Using a JDBC driver
- •Update and Query a Database
- •Customize the Transaction Behavior of JDBC and Commit Transactions
- •Use the JDBC 4.1 RowSetProvider, RowSetFactory, and RowSet Interfaces
- •Introduction to Exception Handling
- •Throwing Exceptions
- •Unhandled Exceptions
- •Try and Catch Statements
- •Programmatically Accessing the Stack Trace
- •Multiple Catch Blocks
- •Multi-Catch Blocks
- •General Catch Handlers
- •Finally Blocks
- •Points to Remember
- •Try-with-Resources
- •Closing Multiple Resources
- •Points to Remember
- •Exception Types
- •The Exception Class
- •The RuntimeException Class
- •The Error Class
- •The Throws Clause
- •Method Overriding and the Throws Clause
- •Points to Remember
- •Custom Exceptions
- •Assertions
- •Assert Statement
- •How Not to Use Asserts
- •Summary
- •Introduction
- •Locales
- •The Locale Class
- •Getting Locale Details
- •Resource Bundles
- •Using PropertyResourceBundle
- •Using ListResourceBundle
- •Loading a Resource Bundle
- •Naming Convention for Resource Bundles
- •Formatting for Local Culture
- •The NumberFormat Class
- •The Currency Class
- •The DateFormat Class
- •The SimpleDateFormat Class
- •Points to Remember
- •Summary
- •Introduction to Concurrent Programming
- •Important Threading-Related Methods
- •Creating Threads
- •Extending the Thread Class
- •Implementing the Runnable Interface
- •The Start( ) and Run( ) Methods
- •Thread Name, Priority, and Group
- •Using the Thread.sleep() Method
- •Using Thread’s Join Method
- •Asynchronous Execution
- •The States of a Thread
- •Two States in “Runnable” State
- •Concurrent Access Problems
- •Data Races
- •Thread Synchronization
- •Synchronized Blocks
- •Synchronized Methods
- •Synchronized Blocks vs. Synchronized Methods
- •Deadlocks
- •Other Threading Problems
- •Livelocks
- •Lock Starvation
- •The Wait/Notify Mechanism
- •Let’s Solve a Problem
- •More Thread States
- •timed_waiting and blocked States
- •waiting State
- •Using Thread.State enum
- •Understanding IllegalThreadStateException
- •Summary
- •Using java.util.concurrent Collections
- •Semaphore
- •CountDownLatch
- •Exchanger
- •CyclicBarrier
- •Phaser
- •Concurrent Collections
- •Apply Atomic Variables and Locks
- •Atomic Variables
- •Locks
- •Conditions
- •Multiple Conditions on a Lock
- •Use Executors and ThreadPools
- •Executor
- •Callable, Executors, ExecutorService, ThreadPool, and Future
- •ThreadFactory
- •The ThreadLocalRandom Class
- •TimeUnit Enumeration
- •Use the Parallel Fork/Join Framework
- •Useful Classes of the Fork/Join Framework
- •Using the Fork/Join Framework
- •Points to Remember
- •Summary
- •Using java.util.concurrent Collections
- •Applying Atomic Variables and Locks
- •Using Executors and ThreadPools
- •Using the Parallel Fork/Join Framework
- •Chapter 3: Java Class Design
- •Chapter 4: Advanced Class Design
- •Chapter 5: Object-Oriented Design Principles
- •Chapter 6: Generics and Collections
- •Chapter 7: String Processing
- •Chapter 8: Java I/O Fundamentals
- •Chapter 9: Java File I/O (NIO.2)
- •Chapter 10: Building Database Applications with JDBC
- •Chapter 11: Exceptions and Assertions
- •Chapter 12: Localization
- •Chapter 13: Threads
- •Chapter 14: Concurrency
- •OCPJP7 Exam (1Z0-804 a.k.a. Java SE 7 Programmer II) Topics
- •OCPJP 7 Exam (1Z0-805, a.k.a. Upgrade to Java SE 7 Programmer) Topics
- •Answers and Explanations
- •Answer Sheet
- •Answers and Explanations
- •Index

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