Write access, coding!
JDBC™ applications require a per project driver configuration:
...
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
<scope>runtime</scope>
</dependency> ...
No. 1
Why <scope>
runtime
</scope>
?
Q: |
Why is the JDBC™ driver dependency not being required at compile time? |
A: |
According to Figure 849, “JDBC™ architecture ”
a JDBC™ based application requires just
interfaces rather than classes at compile time. The actual
instances of |
So how does it actually work with respect to coding? We first prepare a database table:
-
Java™ application executing:
INSERT INTO Person VALUES('Jim', 'jim@foo.org')
-
No database read required (No
java.sql.ResultSet
). -
Success / failure related database return parameter.
// Step 1: Open connection to database server
final Connection conn = DriverManager.getConnection (
"jdbc:postgresql://localhost/hdm", // Connection parameter URL
"hdmuser", // Username
"XYZ"); // Password
// Step 2: Create a Statement instance
final Statement stmt = conn.createStatement();
// Step 3: Execute the desired INSERT
final int updateCount = stmt.executeUpdate(
"INSERT INTO Person VALUES('Jim', 'jim@foo.org')");
// Step 4: Give feedback to the end user
System.out.println("Successfully inserted " + updateCount + " dataset(s)");
-
Execution yields:
Successfully inserted 1 dataset(s)
-
Note: The database server returns the number of inserted / modified / deleted datasets.
No. 2
Exception on inserting objects
Q: |
Set up Figure 865, “JDBC™ backed data insert ” as a Maven project yourself. Create a corresponding table prior to executing your application. Execute your application twice. What happens? Give an explanation. |
A: |
We require a database table
Building the executable jar and running de.hdm_stuttgart.sda1.insert.SimpleInsert yields: goik@goiki Minimum> mvn package
[INFO] Scanning for projects...
...
[INFO] Replacing .../Jdbc/Insert/Minimum/target/insert_user-0.1.jar
with .../Jdbc/Insert/Minimum/target/insert_user-0.1-shaded.jar
goik@goiki Minimum> java -jar /.../Jdbc/Insert/Minimum/target/insert_user-0.1.jar
Successfully inserted 1 dataset(s) We may check our database: MariaDB [hdm]> SELECT * FROM Person; +------+-------------+ | name | email | +------+-------------+ | Jim | jim@foo.org | +------+-------------+ 1 row in set (0.00 sec) A second invocation results in a runtime error: The exception relates to a constraint violation with
respect to the |
- Missing exception handling:
public static void main(String[] args) throws SQLException { ...
- Hard coded connection parameters:
... = DriverManager.getConnection ( "jdbc:postgresql://localhost/hdm", //JDBC URL "hdmuser", // Username "XYZ") // Password
-
Connection parameter changes require recompilation!
-
Parameters should be configurable.
Possible solution: Java™ properties.
- Properties key / value file
resources/jdbc.properties
jdbcurl=jdbc:postgresql://localhost/hdm username=hdmuser password=XYZ
- ResourceBundle reading properties
// resources/jdbc.properties ResourceBundle jdbcProperties = ResourceBundle.getBundle("jdbc");
- Using ResourceBundle
... Connection conn = DriverManager.getConnection( jdbcProperties.getString("jdbcurl"), jdbcProperties.getString("username"), jdbcProperties.getString("password"));
-
Set up: Test preparation.
-
Open database connection
-
Create a required schema.
-
Optional: Insert initial data.
-
-
Test: Execute JDBC™ CRUD / SELECT operations.
-
Tear down:
-
Drop schema
-
Close database connection.
-
public class InsertTest { static private Connection conn; static private Statement stmt; @BeforeClass ❶ static public void initDatabase() throws SQLException { conn = DriverManager.getConnection( SimpleInsert.jdbcProperties.getString("jdbcurl"), SimpleInsert.jdbcProperties.getString("username"),...); ScriptUtils.executeSqlScript(conn, new ClassPathResource("schema.sql")); stmt = conn.createStatement();} @Test ❷ public void test_010_insertJill() throws SQLException { Assert.assertEquals(1, SimpleInsert.insertPerson( stmt, "Jill", "jill@programmer.org")); } @AfterClass ❸ static public void releaseDatabase() throws SQLException {conn.close();}
Getting ScriptUtils.executeSqlScript(...) to work:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
final Connection conn = DriverManager.getConnection(...);
... // CRUD operations
conn.close(); // Important! Wanna use a connection pool instead?
AutoCloseable
Using try-with-resources statement.
try (final Connection conn = DriverManager.getConnection(...) {
... // CRUD operations
} catch (SQLException e) {...}
No. 3
Interactive inserts, connection properties, error handling and unit tests
Q: |
Extend the previous example by adding support for
interactive insert of person data. Ask the end user to enter name and email addresses of persons until being satisfied. In case of constraint violations issue a warning rather then terminating the application as in: Moreover Exception on inserting objects does not yet contain any tests: SQL schema or application modifications may lead to inconsistencies. Provide the following tests:
Tip
|
A: |
Our last exercise's database schema
|
No. 4
Interfaces and classes in JDBC™
Q: |
The JDBC™
standard mostly defines interfaces like You may want to supply code examples backing your argumentation. |
A: |
Figure Figure 849, “JDBC™ architecture ”
depicts JDBC™
being a vendor independent architecture. Oracle for example
may implement a class
Using JDBC™ interfaces rather than vendor specific classes allows for decoupling an application from a specific database platform. It requires a database vendor's implementation not to be exposed to our own Java™ code but to be encapsulated by a set of interfaces. Regarding the special role of
The problem with this approach is its explicit constructor call: Whenever we want to use another database we have two possibilities:
|
No. 5
Closing JDBC™ connections
Q: |
Why is it important to call the close()
method for |
A: |
A JDBC™ connection ties network resources (socket connections). These may get used up if e.g. new connections are being established within a loop. The situation is similar to memory leaks in programming languages lacking a garbage collector. |
No. 6
Driver dispatch mechanism
Q: |
In exercise Interfaces and classes in JDBC™
we saw a hypothetic way to resolve the interface/class
resolution problem by using a switch clause. How is this
Hint: Read the documentation of
|
||||||||
A: |
Prior to opening a Connection a JDBC™
driver registers itself at the
So whenever the method getConnection()
is being called the
|