
- •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
finally {
if(connection != null) connection.close(); if(resultSet != null) resultSet.close();
}
}
}
Run this program first.
Printing the contents of the table before inserting Starting to insert rows
Inserted row for Tom Inserted row for Dick Inserted row for Harry Table updation complete. . .
Rolling back to the state where Tom and Dick were inserted Printing the contents of the table after commit
1Tom
2Dick
Now let’s understand the program.
1.First you get the connection, create a statement, get a ResultSet, and print the contents of the table (which is empty).
2.You insert three rows, one after another. After inserting each row, you create a Savepoint object in that transaction. The first savepoint is an unnamed Savepoint after inserting “Tom” and the second and third are named savepoints occur after inserting “Dick” and “Harry.”
3.In the statement connection.rollback(secondSavepoint);, you instruct JDBC to roll back the transaction to the second savepoint. Remember that you’ve created the second savepoint to remember the state after inserting “Tom” and “Dick” but before inserting “Harry.” So the rollback is to the state where rows containing “Tom” and “Dick” are inserted.
4.The commit() method commits the current state of the transaction. Since the rollback is already called, the current state of the transaction is that there are two rows inserted containing the nicknames “Tom” and “Dick.” Printing the contents of the table confirms that it is indeed the case.
The RowSet Interface
The interface javax.sql.RowSet extends the ResultSet interface to provide support for the JavaBean component model. The RowSet interface defines getters and setters for different data types.
RowSet also supports methods to add and remove event listeners (since it is a JavaBean component). Other Java objects may use the event notification mechanism supported by RowSet. The RowSet interface implements the Observer design pattern (as a Subject). A Java object that wants to receive event notification from RowSet must implement the RowSetListner interface and must be registered with the RowSet object. RowSet notifies all the registered objects on the occurrence of one of the following events: change in cursor location, change in a row, and change in the entire RowSet object.
306

Chapter 10 ■ Building Database Applications with JDBC
Java provides five different flavors of the RowSet interface (see Figure 10-3). The interfaces of these flavors can be found in the javax.sql.rowset package. The five interfaces are JdbcRowSet, JoinRowSet, CachedRowSet, WebRowSet, and FilteredRowSet. Java also offers a default reference implementation of these interfaces that can be found in
the com.sun.rowset package. These implementations are JdbcRowSetImpl, JoinRowSetImpl, CachedRowSetImpl, WebRowSetImpl, and FilteredRowSetImpl.
|
ResultSet |
|
|
|
RowSet |
|
|
|
|
ResultSet capabilities + |
|
|
|
Java Bean capabilities + |
|
JdbcRowSet |
CachedRowSet |
disconnected ResultSet |
|
capabilities |
|||
|
|
||
ResultSet capabilities + |
|
Capabilities supported |
|
WebRowSet |
by CachedRowSet + XML |
||
Java Bean capabilities |
|||
|
capabilities |
||
|
|
||
|
JoinRowSet |
FilterRowSet |
|
Capabilities supported |
|
Capabilities supported |
|
by WebRowSet + SOL |
|
by WebRowSet + |
|
join capabilities |
|
filtering capabilities |
Figure 10-3. The RowSet hierarchy
JdbcRowSet is a connected RowSet, which means a JdbcRowSet implementation is always connected to the corresponding database. The other four interfaces are disconnected RowSets, which means an object of any one of these four RowSet implementations (except JdbcRowSet) connects to the database only when they want to read or write; all the other times they are disconnected from the database. This property of implementation of these four interfaces along with the capability of being serializable make them suitable for sending over the network.
Figure 10-3 shows the hierarchical relationship among various RowSet interfaces. As you already know, RowSet is a subinterface of the ResultSet interface. JdbcRowSet is a subinterface of RowSet; JdbcRowSet has all the features ResultSet supports plus Java Bean capabilities. CachedRowSet is also a subinterface of the RowSet interface; it has all the features JdbcRowSet supports plus it has the capabilities of a disconnected ResultSet. WebRowSet adds XML capabilities to the CachedRowSet features. Similarly, JoinRowSet adds SQL join capabilities to WebRowSet, and FilteredRowSet adds result filtering capabilities to WebRowSet.
Let’s now discuss the RowSetProvider class and the RowSetFactory interface, which were introduced in Java 7. RowSetProvider provides APIs to get a RowSetFactory implementation that can be used to instantiate a proper RowSet implementation. It provides the following two methods:
•RowSetFactory newFactory(): This API creates a new instance of a RowSetFactory implementation. So which factory implementation will this method instantiate? It is a good question; the answer is that this API infers the type of factory implementation to instantiate from the environment settings. It first looks in the system property javax.sql. rowset.RowSetFactory. If the API could not infer the factory implementation, then it uses ServiceLoader API to determine the type of the factory implementation to instantiate, and
finally it looks for the platform default implementation of the RowSetFactory instance. If the API could not infer the factory implementation type, it raises a SQLException.
307
Chapter 10 ■ Building dataBase appliCations with JdBC
•RowSetFactory newFactory(String factoryClassName, ClassLoader classloader): If it is unclear which driver will be loaded when you call the plain newFactory() method due to multiple drivers in the scope, you can use the overloaded method newFactory(), which takes the class name of the factory and the class loader and instantiates the appropriate factory.
RowSetFactory defines five methods; each method creates a type of RowSet implementation. So why are RowSetFactory and RowSetProvider required to create a RowSet implementation when you can create them using the traditional plain way? The answer is flexibility; you can create the RowSet object without specifying the details that you need to provide during a traditional RowSet object; you can then set other details once the object gets created. How about writing a program to see how to use RowSetFactory and RowSetProvider? See Listing 10-13.
Listing 10-13. DbQuery5.java
import javax.sql.rowset.*; import java.sql.*;
// To illustrate how to use RowSet, RowSetProvider, and RowSetFactory class DbQuery5 {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/addressBook"; String userName = "root";
String password = "mysql123"; try {
//first, create a factory object for rowset RowSetFactory rowSetFactory = RowSetProvider.newFactory();
//create a JDBC rowset from the factory
JdbcRowSet rowSet = rowSetFactory.createJdbcRowSet(); rowSet.setUrl(url);
rowSet.setUsername(userName);
rowSet.setPassword(password); rowSet.setCommand("SELECT * FROM contact"); rowSet.execute();
System.out.println("id \tfName \tlName \temail \t\tphoneNo"); while (rowSet.next()){
System.out.println(rowSet.getInt("id") + "\t"
+rowSet.getString("firstName") + "\t"
+rowSet.getString("lastName") + "\t"
+rowSet.getString("email") + "\t"
+rowSet.getString("phoneNo"));
}
} catch (SQLException sqle) { sqle.printStackTrace();
}
}
}
It prints the following:
Id |
fName |
lName |
phoneNo |
1Michael Taylor michael@abc.com +919976543210
2William Becker william@abc.com +449876543210
3 |
Samuel Uncle |
sam@abc.com |
+119955331100 |
308
Chapter 10 ■ Building Database Applications with JDBC
The output of the program is as expected. However, you made use of RowSetProvider and RowSetFactory. You first get the appropriate RowSetFactory and then create JdbcRowSet using the factory. The rest of the program is as you saw in Listing 10-3.
Points to Remember
Here are a few useful points that could be helpful in your OCPJP exam:
•You can use column name or column index with ResultSet methods. The index you use is the index of the ResultSet object, not the column number in the database table.
•A Statement object closes the current ResultSet object if a) the Statement object is closed, b) is re-executed, or c) is made to retrieve the next set of result. That means it is not necessary to call close() explicitly with ResultSet object; however, it is good practice to call close() once you are done with the object.
•You may use the column name of a ResultSet object without worrying about the case: getXXX() methods accept case insensitive column names to retrieve the associated value.
•Think of a case when you have two columns in a ResultSet object with the same name. How you can retrieve the associated values using the column name? If you use a column name to retrieve the value, it will always point to the first column that matches with the given name.
Hence, you have to use column index in this case to retrieve values associated with both columns.
•You might remember that the PreparedStatement interface inherits from Statement. However, PreparedStatement overrides all flavors of execute() methods. For instance, the behavior of executeUpdate() might be different from its base method.
•It is your responsibility to issue a correct SQL command; a JDBC Statement will not check for its correctness. For example, if there is a syntax error in the SQL command string, then you will not get a compiler error. Rather, you’ll get a MySQLSyntaxErrorException at runtime.
•You may call the appropriate get() method immediately after inserting a row using the insertRow() method. However, the values of the row are undefined.
•You may cancel any update you made using the method cancelRowUpdates(). However, you must call this method before calling the method updateRow(). In all other cases, it has no impact on the row.
•While connecting to the database, you need to specify the correct username and password. If the provided username or password is not correct, you will get a SQLException.
•JDBC 4.1 introduces the capability to use try-with-resources statement to close resources (Connection, ResultSet, and Statement) automatically.
309

Chapter 10 ■ Building Database Applications with JDBC
Question Time!
1.Consider the following code segment. Assume that the connection object is valid and statement.executeQuery() method successfully returns a ResultSet object with a few rows in it.
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM contact")){ System.out.println("ID \tfName \tlName \temail \t\tphoneNo");
//from resultSet metadata, find out how many columns are there and then read the column entries
int numOfColumns = resultSet.getMetaData().getColumnCount(); while (resultSet.next()) {
//traverse the columns by index values
for(int i = 0; i < numOfColumns; i++) {
// since we do not know the data type of the column, we use getObject() System.out.print(resultSet.getObject(i) + "\t");
}
System.out.println("");
}
Which of the following statements is true regarding this code segment?
A.The code segment will successfully print the contents of the rows in the ResultSet object.
B.The looping header is wrong. To traverse all the columns, it should be for(int i = 0; i <= numOfColumns; i++) {
C.The looping header is wrong. To traverse all the columns, it should be for(int i = 1; i <= numOfColumns; i++) {
D.The looping header is wrong. To traverse all the columns, it should be for(int i = 1; i < numOfColumns; i++) {
Answer: C. The looping header is wrong. To traverse all the columns, it should be
for(int i = 1; i <= numOfColumns; i++) {
(Given N columns in a table, the valid column indexes are from 1 to N and not 0 to N - 1.)
2.Assume that you’ve freshly created this table with the following command in MySQL:
create table familyGroup (id int not null auto_increment, nickName varchar(30) Not null, primary key (id));
You’ve written this program that makes use of this table:
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;
310
Chapter 10 ■ Building Database Applications with JDBC
class DbTransactionTest {
public static void main(String[] args) throws SQLException { try (Connection connection = DbConnector.connectToDb();
Statement statement = connection.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet =
statement.executeQuery("SELECT * FROM familyGroup")) { resultSet.moveToInsertRow(); resultSet.updateString("nickName", "Sam");
resultSet.insertRow(); |
// INSERT |
ROW |
System.out.println("Table updated |
with a row. . ."); |
|
connection.commit(); |
// COMMIT |
STMT |
}
}
}
What will be the result of executing this program assuming that establishing the connection succeeds?
A.The program will successfully insert a row with id = 1 and nickName = “Sam”.
B.A SQLException will be thrown in the line where the INSERT ROW comment is provided because you cannot insert a row on a read-only ResultSet object.
C.A SQLException will be thrown in the line where the COMMIT STMT statement is provided because auto-commit is enabled; hence the commit will fail.
D.The program will not insert anything into the familyGroup table.
Answer: C. A SQLException will be thrown in the line where the COMMIT STMT statement is provided because auto-commit is enabled; hence the commit will fail.
(Any attempt to use methods such as commit, rollback, setSavepoint, etc. will result in throwing a SQLException if auto-commit is not disabled.)
3.Consider the following sequence of operations in a transaction:
//assume that all operations execute in this program successfully without
//throwing any exceptions; also assume that the connection is established
//successfully
connection.setAutoCommit(false);
//insert a row into the table here
//create a savepoint in this transaction here
//insert another row into the table here
//create a named savepoint in this transaction here
//insert the third row into the table here
connection.rollback();
connection.commit();
311
Chapter 10 ■ Building Database Applications with JDBC
What will be the effect of this sequence of actions after executing the statement connection.commit()?
A.Three rows will be inserted into the table.
B.No rows will be inserted into the table.
C.One row will be inserted into the table.
D.Two rows will be inserted into the table.
E.All three rows will be inserted into the table. Answer: B. No rows will be inserted into the table.
(Since connection.rollback(); is called before connection.commit(), all operations will be undone and no rows will be inserted into the table.)
4.Which one of the following statements would be needed in JDBC 3.0?
A.Connection connection = DriverManager.getConnection("jdbc:mysql:// localhost:3306/addressBook", "root", "password"))
B.Connection connection = DriverManager.createConnection("jdbc:mysql:// localhost:3306/addressBook", "root", "password"))
C.Class.forName("com.mysql.jdbc.Driver").newInstance();
D.Class.forName("com.mysql.jdbc.Driver").getInstance();
Answer: C. Class.forName("com.mysql.jdbc.Driver").newInstance();
(You need to explicitly load the JDBC driver using the Class.forName() statement in JDBC 3.0. From 4.0 onwards, this statement is not needed and you can directly get the connection. Note that option A) shows how to get the connection for MySQL, and this URl will depend on the specific database used.)
5.Consider this program and choose the best option describing its behavior (assume that the connection is valid):
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM contact")){ System.out.println(resultSet.getInt("id") + "\t"
+resultSet.getString("firstName") + "\t"
+resultSet.getString("lastName") + "\t"
+resultSet.getString("email") + "\t"
+resultSet.getString("phoneNo"));
}
catch (SQLException sqle) { System.out.println("SQLException");
}
A.This program will print the following: SQLException.
B.This program will print the first row from contact.
C.This program will print all the rows from contact.
D.This program will report compiler errors.
Answer: A. This program will print the following: SQLException.
312