Create connections, create and execute basic, prepared and callable statements, process query results and control transactions using JDBC API.
ResultSet
Java Database Connectivity (JDBC) is an API for accessing databases from Java. In simple terms, JDBC is like a universal adapter that allows your Java programs to plug into and interact with virtually any relational database. If Java is the common language that lets you write a program once and run it anywhere there’s a Java Virtual Machine, JDBC is the common language that lets that program talk to any database.
Here’s a diagram that shows the overall JDBC architecture:
┌─────────────────────────────────────────────────────────┐
│ JDBC Architecture │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Java │ │ JDBC │ │ Database │ │
│ │ Application │◄──►│ API │◄──►│ Driver │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Database │ │
│ │ │ │
│ └─────────────┘ │
│ │
│ Key Components: │
│ 1. Java Application: Uses JDBC API │
│ 2. JDBC API: Provides standard database access method │
│ 3. JDBC Driver: Implements the JDBC API for a specific │
│ database │
│ 4. Database: The actual database system │
│ │
└─────────────────────────────────────────────────────────┘
The JDBC API defines a set of Java interfaces to support this architecture:
java.sql.Driver
: This interface handles the communication with the database server. You’ll need a different driver for each database vendor (Oracle, MySQL, etc.).java.sql.Connection
: Represents a connection with a specific database. SQL statements are executed and results are returned within the context of a connection.java.sql.PreparedStatement
: Represents a precompiled SQL statement. Useful when you plan to execute the same SQL statement many times with high efficiency.java.sql.CallableStatement
: Used to execute stored procedures, which may have input and output parameters.java.sql.ResultSet
: Represents data returned from the database after you execute an SQL statement, kind of like a fancy 2D array.Almost all the methods of these core JDBC interfaces declare that they may throw an SQLException
. This is a checked exception that provides information on a database access error or other errors.
An SQLException
provides the following useful methods:
String getMessage()
: Returns a description of the error.String getSQLState()
: Returns a SQL:2003 standard code identifying the error.int getErrorCode()
: Returns a database vendor-specific error code.The following diagram shows the workflow of JDBC:
┌─────────────────────────────────────────────────────────┐
│ JDBC Workflow │
│ │
│ ┌─────────────┐ │
│ │ Load JDBC │ │
│ │ Driver │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Establish │ │ Create │ │ Execute │ │
│ │ Connection │───►│ Statement │───►│ Query │ │
│ └──────┬──────┘ └─────────────┘ └──────┬──────┘ │
│ │ │ │
│ │ ┌──────▼──────┐ │
│ │ │ Process │ │
│ │ │ ResultSet │ │
│ │ └──────┬──────┘ │
│ │ │ │
│ │ ┌─────────────┐ ┌──────▼──────┐ │
│ └───────────┤ Close │◄───┤ Close │ │
│ │ Connection │ │ ResultSet │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ │
└─────────────────────────────────────────────────────────┘
A JDBC driver is a software component that enables Java applications to interact with a database. It converts JDBC calls into the specific database protocol required to connect and interact with the database.
To load a JDBC driver, you need to include the driver class (JAR) in your application’s classpath. For JDBC 4.0 and later (Java 6 and above), the driver is automatically loaded if the JAR file of the driver is present in the classpath, you don’t need to explicitly load the driver class in your code.
So let’s start with the JDBC URL and the Connection
object.
The JDBC URL contains all the necessary information to locate and access the database, neatly packaged into a single string.
The format is straightforward:
jdbc:{driver-name}://{server-name}:{port}/{database-name}
For example, to connect to an Oracle database named users
on localhost
, the JDBC URL might look like:
jdbc:oracle:thin:@localhost:1521:users
With the JDBC URL and the database credentials, we can obtain a Connection
object, either through the java.sql.DriverManager
utility class or a javax.sql.DataSource
object.
DriverManager
is the simpler, more direct path. You load the database driver class, pass the JDBC URL and credentials to DriverManager.getConnection()
, and you get a Connection
object:
String url = "jdbc:mydb://localhost:1234/users";
Connection conn = DriverManager.getConnection(url, "username", "password");
DataSource
is a slightly more involved path, designed for use in application servers. You configure a DataSource
object with the database information and let the application server manage the connections:
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/myDB");
Connection conn = ds.getConnection();
In any case, once you have a Connection
object, you’re ready to start executing SQL statements and retrieving results.
In JDBC, the interaction with the database centers around three types of statements:
Statement
: For simple SQL statements without parameters.PreparedStatement
: For precompiled SQL statements, possibly with parameters. Ideal for repeated execution of the same statement with different parameter values.CallableStatement
: For invoking stored procedures in the database.For one-off, straightforward SQL queries, a simple Statement
object will suffice. You can create a Statement
from your Connection
object with:
Statement stmt = conn.createStatement();
And then execute your SQL using one of three methods:
ResultSet executeQuery(String sql)
: For SELECT
statements. Returns a ResultSet
.int executeUpdate(String sql)
: For INSERT
, UPDATE
, DELETE
, or DDL
statements. Returns the row count.boolean execute(String sql)
: For any kind of SQL statement. Returns true
if a ResultSet
is available, false otherwise.Here’s a quick example:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
But simple Statements
have their limitations. They’re not very efficient for repeated queries, and they don’t allow for parameterization. Here’s where PreparedStatement
comes in.
Think of a PreparedStatement
as a template for an SQL query. You define the basic structure of the query, with placeholders for parameters, and the database precompiles it. Then you can efficiently execute that query multiple times with different parameter values.
Obtaining a PreparedStatement
is similar to getting a regular Statement
, but with your SQL template as a parameter:
String sql = "UPDATE users SET status = ? WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
Those ?
symbols are the placeholders for parameters.
It’s generally better to use bind variables (the ?
placeholders) instead of concatenating values into your SQL string. This has several benefits:
It helps prevent SQL injection attacks. If you concatenate user input directly into your SQL, a malicious user could inject their own SQL commands. Bind variables avoid this risk.
It improves performance. When you use bind variables, the database can reuse the parsed and optimized SQL statement, even if the parameter values change. If you concatenate values into the SQL, the database has to parse and optimize the statement every time.
Now, executing a PreparedStatement
is a little different. Instead of passing the SQL to the execute method, you first set the parameter values using setter methods like setString()
, setInt()
, etc. The parameters are numbered starting from 1
.
pstmt.setString(1, "active");
pstmt.setInt(2, 1234);
Then you call one of the execution methods (executeQuery()
, executeUpdate()
, or execute()
) just like with a simple Statement
.
int rowCount = pstmt.executeUpdate();
But what happens if we use the wrong execution method for our SQL statement? For example, what if we use executeQuery()
for an UPDATE statement?
You’ll receive an SQLException
. As a rule of thumb:
executeQuery()
for SELECT
statementsexecuteUpdate()
for INSERT
, UPDATE
, DELETE
, or DDL
statementsexecute()
if you’re not sure what type of result your statement will returnOne of the key benefits of PreparedStatements
is the ability to batch multiple statements together for execution. This can dramatically improve performance when you need to execute many similar statements.
Suppose you need to insert a thousand rows into the users
table. With simple Statements
, you’d have to execute a thousand individual INSERT
statements. But with PreparedStatements
and batching, you can do it much more elegantly:
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)");
for (int i = 0; i < 1000; i++) {
pstmt.setString(1, "user" + i);
pstmt.setString(2, "password" + i);
pstmt.addBatch();
}
int[] rowCounts = pstmt.executeBatch();
The addBatch()
method adds the current set of parameters to the batch, and executeBatch()
executes all the accumulated statements in one fell swoop.
For even more power and flexibility, JDBC allows you to call stored procedures in your database using CallableStatements
. Stored procedures can have IN
, OUT
, and INOUT
parameters, and CallableStatements
handle them all.
To call a procedure with no parameters, the process is straightforward:
CallableStatement cstmt = conn.prepareCall("{CALL procedureName}");
cstmt.execute();
For procedures with parameters, use the setter and getter methods corresponding to the parameter types. Let’s look at examples for IN
, OUT
, and INOUT
parameters.
Passing an IN
parameter:
CallableStatement cstmt = conn.prepareCall("{CALL procedureName(?)}");
cstmt.setString(1, "value");
cstmt.execute();
Getting an OUT
parameter:
CallableStatement cstmt = conn.prepareCall("{CALL procedureName(?)}");
cstmt.registerOutParameter(1, java.sql.Types.VARCHAR);
cstmt.execute();
String result = cstmt.getString(1);
And for an INOUT
parameter, you use both a setter and a getter:
CallableStatement cstmt = conn.prepareCall("{CALL procedureName(?)}");
cstmt.setString(1, "inValue");
cstmt.registerOutParameter(1, java.sql.Types.VARCHAR);
cstmt.execute();
String result = cstmt.getString(1);
ResultSet
While Statements
and PreparedStatements
are about sending data and commands to the database, ResultSets
are all about retrieving data from the database. They represent the rows and columns returned by a SQL query.
Reading a ResultSet
is like iterating over a 2D array, you have a cursor that moves from row to row, and, for each row, you can access the columns by index or by name. The cursor starts before the first row, so you need to call next()
to move to the first row.
Here’s a basic example:
ResultSet rs = stmt.executeQuery("SELECT id, name FROM users");
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
// do something with the data
}
The ResultSet
provides getter methods for all the common data types: getInt()
, getString()
, getDouble()
, getDate()
, etc. You can retrieve a column value by its index (starting from 1
) or by its name.
By default, ResultSets
are forward-only and read-only. This means you can only move forward through the rows using next()
, and you can’t update the data in the ResultSet
. However, JDBC allows you to create ResultSets
with different capabilities by passing type and concurrency options to the createStatement()
or prepareStatement()
methods.
The type options are:
ResultSet.TYPE_FORWARD_ONLY
: This is the default. You can only move forward through the ResultSet
using next()
.ResultSet.TYPE_SCROLL_INSENSITIVE
: You can move forward and backward through the ResultSet
using methods like next()
, previous()
, first()
, last()
, etc. The ResultSet
does not reflect changes made to the underlying database after it was created.ResultSet.TYPE_SCROLL_SENSITIVE
: Like TYPE_SCROLL_INSENSITIVE
, but the ResultSet
reflect changes made to the underlying database.The concurrency options are:
ResultSet.CONCUR_READ_ONLY
: This is the default. You cannot update the data in the ResultSet
.ResultSet.CONCUR_UPDATABLE
: You can update the data in the ResultSet
using methods like updateString()
, updateInt()
, etc., and then call updateRow()
to update the underlying database.Here’s an example of creating a scrollable, updatable ResultSet
:
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
// Move to the last row
rs.last();
// Update the name in the current row
rs.updateString("name", "New Name");
rs.updateRow();
These options give you a lot of flexibility in how you work with the data retrieved from your database.
Imagine you’re transferring money from one bank account to another. This involves two steps: debiting the amount from the source account, and crediting it to the destination account. Now, what if something goes wrong after the debit but before the credit? You’d have an inconsistency in your data and money would be lost!
This is where transactions come in. A transaction is a sequence of database operations that are treated as a single unit of work. Either all of the operations are completed (committed), or none of them are (rolled back). This ensures that the database is always left in a consistent state.
Here’s a diagram that shows the typical workflow of a transaction in JDBC:
┌─────────────────────────────────────────────────────────┐
│ JDBC Transaction │
│ │
│ ┌─────────────┐ │
│ │ Begin │ │
│ │ Transaction │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ SQL │ │ SQL │ │ SQL │ │
│ │ Statement 1 │───►│ Statement 2 │───►│ Statement 3 │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ ┌───────▼───────┐ │ │
│ │ │ Savepoint │ │ │
│ │ └───────┬───────┘ │ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Commit/ │ │
│ │ Rollback │ │
│ └─────────────┘ │
│ │
│ Key Concepts: │
│ 1. Transactions group multiple operations │
│ 2. Savepoints allow partial rollback │
│ 3. Commit makes changes permanent │
│ 4. Rollback undoes all changes in the transaction │
│ │
└─────────────────────────────────────────────────────────┘
In JDBC, every Connection
has an associated transaction. By default, each SQL statement is automatically committed as soon as it finishes. This is known as auto-commit mode. However, you can disable auto-commit and manage the transaction manually.
To start a transaction, you disable auto-commit on the Connection
:
conn.setAutoCommit(false);
From this point on, no SQL statements will be committed until you explicitly call the commit()
method:
conn.commit();
If at any point you decide to abort the transaction, you can call the rollback()
method, which will undo all the changes made since the start of the transaction:
conn.rollback();
It’s important to always either commit or roll back a transaction. If you disable auto-commit, start a transaction, and then close the Connection
without committing or rolling back, the behavior will be undefined. The changes might be committed, or they might be rolled back, or they might be left in limbo, depending on the database and the JDBC driver. To avoid this uncertainty always explicitly commit or roll back before closing the Connection
.
Here’s a typical pattern for using transactions:
try {
conn.setAutoCommit(false);
// execute some SQL statements
conn.commit();
} catch (SQLException e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
}
The finally
block ensures that auto-commit is re-enabled, even if an exception occurs.
Sometimes, you might want to partially roll back a transaction. For example, suppose a transaction consists of three SQL statements. After executing the first two statements, you encounter an error. You want to roll back the second statement, but keep the changes made by the first statement.
This is where savepoints come in. A savepoint is a named bookmark within a transaction. You can roll back to a savepoint without aborting the entire transaction.
Here’s how it works:
Savepoint sp1 = conn.setSavepoint();
// execute first statement
Savepoint sp2 = conn.setSavepoint();
// execute second statement
if (error) {
conn.rollback(sp2);
}
// execute third statement
conn.commit();
In this example, if an error occurs after the second statement, we roll back to the sp2
savepoint, which discards the changes made by the second statement but keeps the changes made by the first statement. We then proceed with the third statement and commit the transaction.
Transactions are a powerful tool for ensuring data integrity, but they also come with some overhead. Opening a transaction, committing it, and rolling it back all involve communication with the database server, which can be slow. Therefore, it’s generally best to keep transactions as short as possible, and only use them when necessary for maintaining data consistency.
When you’re done with your database work, it’s essential to properly close all the resources you’ve opened: Connections
, Statements
, PreparedStatements
, CallableStatements
, and ResultSets
. Failing to close these resources can lead to resource leaks, which can severely impact the performance and scalability of your application.
Think of it like borrowing books from a library. If you keep borrowing books without ever returning them, eventually the library will run out of books for other people to borrow. Similarly, if you keep opening database resources without closing them, eventually the database will run out of resources to allocate to other connections.
However, always keep in mind that the order matters. It’s not enough to just close the resources, you need to close them in the right order. The rule of thumb is to close the resources in the reverse order of their creation.
Here’s the typical order:
ResultSet
(if there is one)Statement
, PreparedStatement
, or CallableStatement
Connection
This order is important because of the way these resources are related:
Connection
can have multiple Statements
, PreparedStatements
, and CallableStatements
.Statement
, PreparedStatement
, or CallableStatement
can have at most one associated ResultSet
.Therefore:
Connection
automatically closes all the Statements
, PreparedStatements
, and CallableStatements
created from it.Statement
, PreparedStatement
, or CallableStatement
automatically closes its associated ResultSet
(if there is one).Here’s an example that demonstrates the proper closing order:
ResultSet rs = null;
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
// process the results
} catch (SQLException e) {
// handle the exception
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// log the exception
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
// log the exception
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// log the exception
}
}
}
Notice that we close the resources in the finally block. This ensures that they get closed even if an exception occurs. Note that each close()
call is wrapped in its own try-catch
block. This is because the close()
method can also throw a SQLException
, and we don’t want that to prevent the other resources from being closed. Also, the code checks if the resources are null
first, to avoid a NullPointerException
if the resources were never initialized.
However, you can use the try-with-resources
statement to automatically close resources:
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
// process the results
} catch (SQLException e) {
// handle the exception
}
The try-with-resources
statement automatically closes the resources in the reverse order of their declaration, even if an exception occurs. This is the preferred way to handle JDBC resources because it greatly simplifies your code and make it more readable.
JDBC (Java Database Connectivity) is an API for accessing relational databases from Java programs.
The core JDBC interfaces are Driver
, Connection
, Statement
, PreparedStatement
, CallableStatement
, and ResultSet
.
An SQLException
is thrown to provide information on database access errors. Its methods getMessage()
, getSQLState()
, and getErrorCode()
provide details about the error.
A JDBC URL contains the information needed to locate and access the database, in the format jdbc:{driver-name}://{server-name}:{port}/{database-name}
.
A Connection
object can be obtained from a JDBC URL using DriverManager.getConnection()
or from a DataSource
object.
A Statement
is used for simple SQL queries without parameters. A PreparedStatement
is used for precompiled SQL statements with or without parameters. A CallableStatement
is used to execute stored procedures.
A ResultSet
represents the rows and columns returned from a SQL query. Data can be retrieved from a ResultSet
using getter methods like getInt()
, getString()
, etc.
By default, a ResultSet
is forward-only (ResultSet.TYPE_FORWARD_ONLY
) and read-only (ResultSet.CONCUR_READ_ONLY
), but it can be made scrollable and updatable.
Transactions ensure data consistency by treating a sequence of database operations as a single unit of work. They are controlled by setAutoCommit()
, commit()
, and rollback()
.
Savepoints allow for partial rollbacks within a transaction.
Always close ResultSets
, Statements
, and Connections
in the reverse order of their creation to prevent resource leaks, either manually in a finally
block or by using a try-with-resources
block.
1. Which of the following statements correctly creates a database connection using JDBC?
A) Connection connection = DriverManager.connect("jdbc:mysql://localhost:3306/mydatabase");
B) Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "user");
C) Connection connection = DriverManager.connect("jdbc:mysql://localhost:3306/mydatabase", "user", "password");
D) Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "user", "password");
2. Which of the following statements correctly executes a SQL query using a Statement
object in JDBC?
A) ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
B) int result = statement.executeQuery("SELECT * FROM users");
C) ResultSet result = statement.execute("SELECT * FROM users");
D) int resultSet = statement.executeUpdate("SELECT * FROM users");
3. Which of the following statements correctly prepares and executes a parameterized SQL query using a PreparedStatement
object in JDBC?
A)
PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE id = ?");
ResultSet rs = pstmt.executeQuery(1);
B)
PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, 1);
ResultSet rs = pstmt.executeQuery();
C)
PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE id = 1");
ResultSet rs = pstmt.execute();
D)
PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, 1);
boolean rs = pstmt.execute();
4. Given a users
table with the columns id (INT)
and name (VARCHAR)
, which of the following statements correctly retrieves all the data from a ResultSet
object in JDBC?
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class RetrieveData {
public static void main(String[] args) {
try {
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"user", "password"
);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT id, name FROM users"
);
// Retrieving data
} catch (SQLException e) {
e.printStackTrace();
}
}
}
A)
while (resultSet.next()) {
String id = resultSet.getString("id");
int name = resultSet.getInt("name");
}
B)
if (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
}
C)
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
D)
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
}
5. Which of the following statements correctly demonstrates how to manage transactions using JDBC?
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TransactionExample {
public static void main(String[] args) {
try {
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"user", "password"
);
Statement statement = connection.createStatement();
// Managing transaction
} catch (SQLException e) {
e.printStackTrace();
}
}
}
A)
connection.setAutoCommit(true);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.commit();
B)
connection.setAutoCommit(false);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.commit();
C)
connection.setAutoCommit(false);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.rollback();
D)
connection.setTransaction(true);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.commit();
6. Which of the following statements correctly demonstrates the use of savepoints in JDBC transactions?
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
public class SavepointExample {
public static void main(String[] args) {
try {
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"user", "password"
);
Statement statement = connection.createStatement();
connection.setAutoCommit(false);
// Using savepoints
} catch (SQLException e) {
e.printStackTrace();
}
}
}
A)
Savepoint savepoint1 = connection.setSavepoint();
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.rollback(savepoint1);
connection.commit();
B)
Savepoint savepoint1 = connection.setSavepoint();
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.rollback();
statement.executeUpdate("INSERT INTO users (id, name) VALUES (3, 'Jane')");
connection.commit();
C)
Savepoint savepoint1 = connection.setSavepoint("Savepoint1");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.rollback(savepoint1);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (3, 'Jane')");
connection.commit();
D)
Savepoint savepoint1 = connection.savepoint("Savepoint1");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (1, 'John')");
statement.executeUpdate("INSERT INTO users (id, name) VALUES (2, 'Doe')");
connection.rollbackToSavepoint(savepoint1);
statement.executeUpdate("INSERT INTO users (id, name) VALUES (3, 'Jane')");
connection.commit();
7. Which of the following statements correctly demonstrates how to close JDBC resources properly in a finally
block?
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class CloseResourcesExample {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"user", "password"
);
statement = connection.createStatement();
statement.executeUpdate(
"INSERT INTO users (id, name) VALUES (1, 'John')"
);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// Closing resources
}
}
}
A)
finally {
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
B)
finally {
try {
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
C)
finally {
try {
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
D)
finally {
statement.close();
connection.close();
}
Do you like what you read? Would you consider?
Do you have a problem or something to say?