Devjournals - JDBC
Devjournals - JDBC
JDBC API is written in a way to allow loose coupling between our Java program and actual JDBC drivers
that makes our life easier in switching from one database to another database servers easily.
I think this is one of the best example of using Reflection in core java classes to make sure that our
application doesn’t work directly with Drivers API and that makes it very easy to move from one database
to another. Please read more at JDBC Example.
try{
Class.forName("com.mysql.jdbc.Driver");
con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/UserDB",
"pankaj",
"pankaj123");
}catch (SQLException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
Since the query is generated in the java program, if the user input is not properly validated it can lead to
SQL injection issue, more details can be found at SQL Injection Example.
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if we
want to work with multiple ResultSet objects, then each must have been generated by different Statement
objects. All execute() methods in the Statement interface implicitly close a statment’s current ResultSet
object if an open one exists.
Statement executeQuery(String query) is used to execute Select queries and returns the ResultSet.
ResultSet returned is never null even if there are no records matching the query. When executing select
queries we should use executeQuery method so that if someone tries to execute insert/update statement it
will throw java.sql.SQLException with message “executeQuery method can not be used for update”.
You should use execute() method only when you are not sure about the type of statement else use
executeQuery or executeUpdate method.
Since PreparedStatement is precompiled, it can then be used to efficiently execute this statement multiple
times. PreparedStatement is better choice that Statement because it automatically escapes the special
characters and avoid SQL injection attacks.
ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned
before the first row. The next() method moves the cursor to the next row. If there are no more rows, next()
method returns false and it can be used in a while loop to iterate through the result set.
A default ResultSet object is not updatable and has a cursor that moves forward only. Thus, you can iterate
through it only once and only from the first row to the last row. It is possible to produce ResultSet objects
that are scrollable and/or updatable using below syntax.
ResultSet.CONCUR_UPDATABLE);
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-
executed, or used to retrieve the next result from a sequence of multiple results.
We can use ResultSet getter method with column name or index number starting from 1 to retrieve the
column data.
9. ResultSet.TYPE_FORWARD_ONLY: This is the default type and cursor can only move
forward in the result set.
10. ResultSet.TYPE_SCROLL_INSENSITIVE: The cursor can move forward and backward, and
the result set is not sensitive to changes made by others to the database after the result set was
created.
11. ResultSet.TYPE_SCROLL_SENSITIVE: The cursor can move forward and backward, and the
result set is sensitive to changes made by others to the database after the result set was
created.
12. ResultSet.CONCUR_READ_ONLY: The result set is read only, this is the default concurrency
type.
13. ResultSet.CONCUR_UPDATABLE: We can use ResultSet update method to update the rows
data.
Understanding fetchSize can be tricky, for that you should know how Statement and ResultSet works.
When we execute a query in the database, the result is obtained and maintained in the database cache
and ResultSet is returned. ResultSet is the cursor that has the reference to the result in the database.
Let’s say we have a query that returns 100 rows and we have set fetchSize to 10, so in every database trip
JDBC driver will fetch only 10 rows and hence there will be 10 trips to fetch all the rows. Setting optimal
fetchSize is helpful when you need a lot of processing time for each row and number of rows in the result is
huge.
We can set fetchSize through Statement object but it can be overridden through ResultSet object
setFetchSize() method.
2. stmt.setInt(1, id);
3. stmt.setString(2, name);
4. stmt.setString(3, role);
5. stmt.setString(4, city);
6. stmt.setString(5, country);
7.
9. stmt.registerOutParameter(6, java.sql.Types.VARCHAR);
10.
11.stmt.executeUpdate();
We need to register the OUT parameters before executing the CallableStatement. More details about this
can be found at JDBC CallableStatement Example.
Batch Processing is faster than executing one statement at a time because the number of database calls
are less, read more at JDBC Batch Processing Example.
Sometimes we want a group of SQL queries to be part of a transaction so that we can commit them when
all the queries runs fine and if we get any exception, we have a choice of rollback all the queries executed
as part of the transaction.
JDBC API provide method setAutoCommit(boolean flag) through which we can disable the auto
commit feature of the connection. We should disable auto commit only when it’s required because the
transaction will not be committed unless we call the commit() method on connection. Database servers
uses table locks to achieve transaction management and it’s resource intensive process. So we should
commit the transaction as soon as we are done with it. Read more with example program at JDBC
Transaction Management Example.
6. Creating JDBC JNDI resource in the container configuration files, usually server.xml or
context.xml. For example
server.xml
<Resource name="jdbc/MyDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/UserDB"
username="pankaj"
password="pankaj123"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
context.xml
<ResourceLink name="jdbc/MyLocalDB"
global="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource" />
7. In web application, using InitialContext to look up the JNDI resource configured in the first step
and then get the connection.
8. Context ctx = new InitialContext();
DataSource ds = (DataSource)
ctx.lookup("java:/comp/env/jdbc/MyLocalDB");
Apache DBCP helps us in getting rid of these issues by providing DataSource implementation that works
as an abstraction layer between our program and different JDBC drivers. Apache DBCP library depends on
Commons Pool library, so make sure they both are in the build path.
JDBC transaction isolation level is used by DBMS to use the locking mechanism, we can get the isolation
level information through Connection getTransactionIsolation() method and set it with
setTransactionIsolation() method.
Not
TRANSACTION_NONE Not Supported Not Applicable Not Applicable
Applicable
Functions as Java Beans with properties and their getter-setter methods. RowSet uses
JavaBeans event model and they can send notifications to any registered component for events
such as cursor movement, update/insert/delete of a row and change to RowSet contents.
RowSet objects are scrollable and updatable by default, so if DBMS doesn’t support scrollable
or updatable ResultSet, we can use RowSet to get these features.
11. Connected RowSet Objects – These objects are connected to database and are most similar
to ResultSet object. JDBC API provides only one connected RowSet
object javax.sql.rowset.JdbcRowSet and it’s standard implementation class
is com.sun.rowset.JdbcRowSetImpl
12. Disconnected RowSet Objects – These RowSet objects are not required to connected to a
database, so they are more lightweight and serializable. They are suitable for sending data over
a network. There are four types of disconnected RowSet implementations.
CachedRowSet – They can get the connection and execute a query and read the
ResultSet data to populate the RowSet data. We can manipulate and update data while it
is disconnected and reconnect to database and write the changes.
WebRowSet derived from CachedRowSet – They can read and write XML document.
JoinRowSet derived from WebRowSet – They can form SQL JOIN without having to
connect to a data source.
FilteredRowSet derived from WebRowSet – We can apply filtering criteria so that only
selected data is visible.
Whether to use ResultSet or RowSet depends on your requirements but if you are planning to use
ResultSet for longer duration, then a disconnected RowSet is better choice to free database resources.
28.What are common JDBC Exceptions?
Some of the common JDBC Exceptions are:
Binary Large OBjects (BLOBs) are binary string made up of bytes with no associated code page. This data
type can store binary data larger than VARBINARY (32K limit). This data type is good for storing image,
voice, graphical, and other types of business or application-specific data.
13. Optimistic Locking – Locking the record only when update is taking place
14. Pessimistic Locking – Locking the record from the select to read, update and commit phase.
Apart from that some DBMS systems provide locking mechanism to lock single row, table or database.
at
org.apache.tomcat.dbcp.dbcp.BasicDataSource.createConnectionFactory(Basic
DataSource.java:1452)
at
org.apache.tomcat.dbcp.dbcp.BasicDataSource.createDataSource(BasicDataSou
rce.java:1371)
at
org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource
.java:1044)
at java.sql.DriverManager.getConnection(DriverManager.java:604)
at java.sql.DriverManager.getConnection(DriverManager.java:221)
at
com.journaldev.jdbc.DBConnection.getConnection(DBConnection.java:24)
at com.journaldev.jdbc.DBConnectionTest.main(DBConnectionTest.java:15)
at com.journaldev.jdbc.DBConnectionTest.main(DBConnectionTest.java:16)
While debugging this exception, just check the URL getting printed in the logs, as in above logs the URL
String is ‘jdbc:mysql://localhost:3306/UserDB whereas it should be jdbc:mysql://localhost:3306/UserDB.
Database resources are heavy, so make sure you close it as soon as you are done with it.
Connection, Statement, ResultSet and all other JDBC objects have close() method defined to
close them.
Always close the result set, statement and connection explicitly in the code, because if you are
working in connection pooling environment, the connection might be returned to the pool
leaving open result sets and statement objects resulting in resource leak.
Close the resources in the finally block to make sure they are closed even in case of exception
scenarios.
Use batch processing for bulk operations of similar kind.
Always use PreparedStatement over Statement to avoid SQL Injection and get pre-compilation
and caching benefits of PreparedStatement.
If you are retrieving bulk data into result set, setting an optimal value for fetchSize helps in
getting good performance.
The database server might not support all isolation levels, so check it before assuming.
More strict isolation levels result in slow performance, so make sure you have optimal isolation
level set for your database connections.
If you are creating database connections in a web application, try to use JDBC DataSource
resources using JNDI context for re-using the connections.
Try to use disconnected RowSet when you need to work with ResultSet for a long time.