java and rdbms
play

Java and RDBMS Married with issues Database constraints Speaker - PowerPoint PPT Presentation

Java and RDBMS Married with issues Database constraints Speaker Jeroen van Schagen Situation store Java Relational Application Database retrieve JDBC JDBC J ava D ata b ase C onnectivity Data Access API ( java.sql ,


  1. Java and RDBMS Married with issues Database constraints

  2. Speaker Jeroen van Schagen

  3. Situation store Java 
 Relational 
 Application Database retrieve JDBC

  4. JDBC • J ava D ata b ase C onnectivity • Data Access API ( java.sql , javax.sql ) • JDK 1.1 (1997) • Relational Database • Many implementations

  5. Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql);

  6. Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql);

  7. Database User Maintain data name : varchar(3) 
 NOT-NULL, 
 UNIQUE Name can only have 
 up to 3 characters Name is required Name can only occur once

  8. Constraint types Check Not null Unique key Length Type Foreign key Primary key

  9. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql); 
 What happens? Assuming the user table is empty

  10. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql); 
 1 row updated

  11. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql); 
 statement.executeUpdate(sql); What will happen? What happens?

  12. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql); 
 statement.executeUpdate(sql); SQLIntegrityConstraint 
 What will happen? ViolationException

  13. executeUpdate(sql) INSERT return 1 Inserted 1 Applicatio JDBC Database n executeUpdate(sql) INSERT throw Unique violation SQLIntegrityConstraint 
 ViolationException

  14. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 statement.executeUpdate(sql); 
 statement.executeUpdate(sql);

  15. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (‘Jan’)”; 
 try { 
 statement.executeUpdate(sql); 
 statement.executeUpdate(sql); 
 } catch (SQLIntegrityConstraintViolationException e) { 
 throw new RuntimeException(“Name already exists”); 
 }

  16. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”; 
 statement.executeUpdate(sql); What happens?

  17. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”; 
 statement.executeUpdate(sql); SQLIntegrityConstraint 
 ViolationException

  18. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”; 
 try { 
 statement.executeUpdate(sql); 
 } catch (SQLIntegrityConstraintViolationException e) { 
 throw new RuntimeException(“Name is required”); 
 throw new RuntimeException(“Name already exists”); 
 }

  19. Unique key violation SQLIntegrityConstraint 
 ViolationException Not null violation

  20. Unique key violation SQLIntegrityConstraint 
 ViolationException Not null violation Which was violated?

  21. SQLException + getSQLState() : int + getMessage() : String SQLIntegrityConstraint 
 ViolationException

  22. SQLException + getSQLState() : int + getMessage() : String SQLIntegrityConstraint 
 ViolationException

  23. State Name 23 000 Integrity constraint 23 001 Restrict violation 23 502 Not null violation 23 503 Foreign key violation 23 505 Unique violation 23 514 Check violation

  24. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”; 
 try { 
 statement.executeUpdate(sql); 
 } catch (SQLIntegrityConstraintViolationException e) { 
 if (e.getSQLState() == 23502) { 
 throw new RuntimeException(“Name is required”); 
 } else if (e.getSQLState() == 23505) { 
 throw new RuntimeException(“Name already exists”); 
 } 
 }

  25. User name : varchar(3) 
 NOT-NULL, 
 UNIQUE Connection connection = …; 
 Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”; 
 try { 
 statement.executeUpdate(sql); 
 } catch (SQLIntegrityConstraintViolationException e) { 
 if (e.getSQLState() == 23502) { 
 throw new RuntimeException(“Name is required”); 
 } else if (e.getSQLState() == 23505) { 
 throw new RuntimeException(“Name already exists”); 
 } 
 } Complicated Boilerplate Assumptions

  26. Multiple not-null values User name : varchar(3) 
 NOT-NULL, 
 UNIQUE email : varchar(30) 
 NOT-NULL, 
 UNIQUE

  27. Multiple not-null values Multiple unique values Which was violated? User name : varchar(3) 
 NOT-NULL, 
 uk_user_name UNIQUE email : varchar(30) 
 NOT-NULL, 
 uk_user_email UNIQUE

  28. SQLException + getSQLState() : int + getMessage() : String SQLIntegrityConstraint 
 ViolationException

  29. Vendor messages They are all di fg erent Oracle ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n MySQL Duplicate entry 'Jan' for key 'uk_user_name' HSQL integrity constraint violation: unique constraint or index violation; 
 UK_USER_NAME table: USER PostgreSQL ERROR: duplicate key value violates unique constraint \"uk_user_name\" 
 Detail: Key (name)=(Jan) already exists. H2 Unique index or primary key violation: "UK_USER_NAME_INDEX_1 ON GOTO.USER(NAME)"; 
 SQL statement:\ninsert into user (name) values (?) [23505-171]

  30. Vendor messages The info is there Oracle ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n MySQL Duplicate entry 'Jan' for key 'uk_user_name' HSQL integrity constraint violation: unique constraint or index violation; 
 UK_USER_NAME table: USER PostgreSQL ERROR: duplicate key value violates unique constraint \"uk_user_name\" 
 Detail: Key (name)=(Jan) already exists. H2 Unique index or primary key violation: "UK_USER_NAME_INDEX_1 ON GOTO.USER(NAME)"; 
 SQL statement:\ninsert into user (name) values (?) [23505-171]

  31. Extract violation info • Message Just too di ffj cult • Pattern matching Focus on application logic • Vendor specific

  32. Concrete exception classes UniqueKeyViolationException NotNullViolationException JDBC needs a better exception API 
 ( for integrity constraints ) Access to constraint info getColumnName() getConstraintName()

  33. Workaround

  34. Prevent violations

  35. Prevent violations • Data integrity checks in application layer.

  36. Prevent not-null if (user.getName() == null) { 
 throw new RuntimeException(“Name is required”); 
 }

  37. Javax validation public class User { 
 @NotNull 
 private String name; 
 } No SQL exception Conveys Less database interaction

  38. Less interaction throw new RuntimeException Applicatio Database n

  39. Duplication Application Database User User @NotNull 
 name : varchar(3) 
 private String name NOT-NULL, 
 UNIQUE

  40. Duplication Application Database User User @NotNull 
 name : varchar(3) 
 private String name NOT-NULL, 
 UNIQUE Kept in sync Unexpected SQL exceptions

  41. Prevent unique violation • Complicated • Depends on other rows

  42. id name NULL Testable in isolation

  43. id name Jan

  44. id name Jan Requires data users id name Piet 1 2 Jan 3 Henk

  45. No SQL exceptions if (countUsersWithName(user.getName()) > 0) { 
 throw new RuntimeException(“Name already exists”); 
 } private int countUsersWithName(String name) { 
 return jdbcTemplate.queryForObject( 
 “SELECT COUNT(1) FROM user where name = ?”, 
 name, Long.class); 
 } Extra query Not atomic

  46. Problem: Not atomic Thread 1 COUNT WHERE name = ‘Jan’ return 0 Thread 2 INSERT (name) VALUES (‘Jan’) Applicatio Database n INSERTED 1 Uncaught Thread 1 Unexpected INSERT (name) VALUES (‘Jan’) Decision on 
 Unique key violation old data

  47. Recap Lack proper solution Not null No SQL exceptions Duplication Error prone Unique key No SQL exceptions Extra query Error prone

  48. Solution Ja va R epository B ridge - JaRB

  49. 
 Databases are good at 
 maintaining integrity; 
 let them!

Recommend


More recommend