Java and RDBMS. Married with issues. Database constraints



Similar documents
Chapter 9 Java and SQL. Wang Yang wyang@njnet.edu.cn

Evaluation. Copy. Evaluation Copy. Chapter 7: Using JDBC with Spring. 1) A Simpler Approach ) The JdbcTemplate. Class...

Object Relational Database Mapping. Alex Boughton Spring 2011

A Brief Introduction to MySQL

Customer Bank Account Management System Technical Specification Document

Spring Data JDBC Extensions Reference Documentation

Geodatabase Programming with SQL

Weaving Stored Procedures into Java at Zalando

SQL and Java. Database Systems Lecture 19 Natasha Alechina

CS346: Database Programming.

Supplement IV.D: Tutorial for MS Access. For Introduction to Java Programming By Y. Daniel Liang

Database Management System Choices. Introduction To Database Systems CSE 373 Spring 2013

CS/CE 2336 Computer Science II

Package sjdbc. R topics documented: February 20, 2015

Hibernate Validator. Olivier Devoisin Kevin Gallardo. Université Pierre et Marie Curie. 9 Decembre 2014

Java EE Web Development Course Program

Object Oriented Design with UML and Java. PART XVIII: Database Technology

OBJECTS AND DATABASES. CS121: Introduction to Relational Database Systems Fall 2015 Lecture 21

Services. Relational. Databases & JDBC. Today. Relational. Databases SQL JDBC. Next Time. Services. Relational. Databases & JDBC. Today.

SpagoBI exo Tomcat Installation Manual

Table of contents. Reverse-engineers a database to Grails domain classes.

Tutorial for Spring DAO with JDBC

What is a database? COSC 304 Introduction to Database Systems. Database Introduction. Example Problem. Databases in the Real-World

SQL DATA DEFINITION: KEY CONSTRAINTS. CS121: Introduction to Relational Database Systems Fall 2015 Lecture 7

History of SQL. Relational Database Languages. Tuple relational calculus ALPHA (Codd, 1970s) QUEL (based on ALPHA) Datalog (rule-based, like PROLOG)

The JAVA Way: JDBC and SQLJ

The release notes provide details of enhancements and features in Cloudera ODBC Driver for Impala , as well as the version history.

JSR-303 Bean Validation

Programming Database lectures for mathema

Specialized Programme on Web Application Development using Open Source Tools

An Eclipse Plug-In for Visualizing Java Code Dependencies on Relational Databases

D61830GC30. MySQL for Developers. Summary. Introduction. Prerequisites. At Course completion After completing this course, students will be able to:

Module Title: : Cloud Application Development

LSINF1124 Projet de programmation

Linas Virbalas Continuent, Inc.

Nick Ashley TOOLS. The following table lists some additional and possibly more unusual tools used in this paper.

A basic create statement for a simple student table would look like the following.

Data Hierarchy. Traditional File based Approach. Hierarchy of Data for a Computer-Based File

Chapter 13. Introduction to SQL Programming Techniques. Database Programming: Techniques and Issues. SQL Programming. Database applications

Easy-Cassandra User Guide

Java and Databases. COMP514 Distributed Information Systems. Java Database Connectivity. Standards and utilities. Java and Databases

Extracting META information from Interbase/Firebird SQL (INFORMATION_SCHEMA)

Database Design Patterns. Winter Lecture 24

Database Design and Programming

Supplement IV.C: Tutorial for Oracle. For Introduction to Java Programming By Y. Daniel Liang

Unified access to all your data points. with Apache MetaModel

How To Create A Table In Sql (Ahem)

EMBL-EBI. Database Replication - Distribution

f...-. I enterprise Amazon SimpIeDB Developer Guide Scale your application's database on the cloud using Amazon SimpIeDB Prabhakar Chaganti Rich Helms

MySQL for Beginners Ed 3

Comparing the Effectiveness of Penetration Testing and Static Code Analysis

Chapter 5 More SQL: Complex Queries, Triggers, Views, and Schema Modification

Specialized Programme on Web Application Development using Open Source Tools

Apache Sqoop. A Data Transfer Tool for Hadoop

Interfacing Fedora with Microsoft SQL Server

JDBC (Java / SQL Programming) CS 377: Database Systems

Q&A for Zend Framework Database Access

A SQL Injection : Internal Investigation of Injection, Detection and Prevention of SQL Injection Attacks

Web Development using PHP (WD_PHP) Duration 1.5 months

Template based relation database creator for mining industry

Getting Started with Telerik Data Access. Contents

Sharding with postgres_fdw

Oracle Database 10g Express

Security Test s i t ng Eileen Donlon CMSC 737 Spring 2008

Using Temporary Tables to Improve Performance for SQL Data Services

Physical Design. Meeting the needs of the users is the gold standard against which we measure our success in creating a database.

Database Access from a Programming Language: Database Access from a Programming Language

Database Access from a Programming Language:

Simba Apache Cassandra ODBC Driver

1. Introduction What is Slice? Background Why Slice? Purpose of this Document Intended Audience...

Enabling development teams to move fast. PostgreSQL at Zalando

Oracle to MySQL Migration

Performance Evaluation of Java Object Relational Mapping Tools

Introduction to Triggers using SQL

Object Relational Mapping for Database Integration

How to Improve Database Connectivity With the Data Tools Platform. John Graham (Sybase Data Tooling) Brian Payton (IBM Information Management)

1 File Processing Systems

CSCE 156H/RAIK 184H Assignment 4 - Project Phase III Database Design

Normal Form vs. Non-First Normal Form

Self-test Database application programming with JDBC

CSCI110 Exercise 4: Database - MySQL

Database 10g Edition: All possible 10g features, either bundled or available at additional cost.

EDI Process Specification

How To Let A Lecturer Know If Someone Is At A Lecture Or If They Are At A Guesthouse

Using Database Metadata and its Semantics to Generate Automatic and Dynamic Web Entry Forms

Database programming made easier Master thesis of Roland Balk

UltraQuest Cloud Server. White Paper Version 1.0

Developing SQL and PL/SQL with JDeveloper

- Eliminating redundant data - Ensuring data dependencies makes sense. ie:- data is stored logically

CSE 530A Database Management Systems. Introduction. Washington University Fall 2013

database abstraction layer database abstraction layers in PHP Lukas Smith BackendMedia

Talend for Data Integration guide

Basic Unix/Linux 1. Software Testing Interview Prep

Developing Web Applications for Microsoft SQL Server Databases - What you need to know

Lecture 6. SQL, Logical DB Design

Physical Database Design Process. Physical Database Design Process. Major Inputs to Physical Database. Components of Physical Database Design

New Features... 1 Installation... 3 Upgrade Changes... 3 Fixed Limitations... 4 Known Limitations... 5 Informatica Global Customer Support...

Chapter 30 Exporting Inventory Management System Data

Transcription:

Java and RDBMS Married with issues Database constraints

Speaker Jeroen van Schagen

Situation Java Application store retrieve JDBC Relational Database

JDBC Java Database Connectivity Data Access API ( java.sql, javax.sql ) JDK 1.1 (1997) Relational Database Many implementations

Connection connection = ; Statement statement = connection.createstatement(); String sql = INSERT INTO user (name) VALUES ( Jan ) ; statement.executeupdate(sql);

Connection connection = ; Statement statement = connection.createstatement(); String sql = INSERT INTO user (name) VALUES ( Jan ) ; statement.executeupdate(sql);

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

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

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

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

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 happens? happen?

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

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

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);

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 ); }

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?

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

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 ); }

Unique key violation SQLIntegrityConstraint ViolationException Not null violation

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

SQLException + getsqlstate() : int + getmessage() : String SQLIntegrityConstraint ViolationException

SQLException + getsqlstate() : int + getmessage() : String SQLIntegrityConstraint ViolationException

State Name 23000 Integrity constraint 23001 Restrict violation 23502 Not null violation 23503 Foreign key violation 23505 Unique violation 23514 Check violation

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 ); } }

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

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

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

SQLException + getsqlstate() : int + getmessage() : String SQLIntegrityConstraint ViolationException

Vendor messages Oracle ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n They are all different 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]

Vendor messages Oracle ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n The info is there 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]

Extract violation info Message Just too difficult Pattern matching Vendor specific Focus on application logic

Concrete exception classes UniqueKeyViolationException NotNullViolationException JDBC needs a better exception API ( for integrity constraints ) Access to constraint info getcolumnname() getconstraintname()

Workaround

Prevent violations

Prevent violations Data integrity checks in application layer.

Prevent not-null if (user.getname() == null) { throw new RuntimeException( Name is required ); }

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

Less interaction throw new RuntimeException Applicatio n Database

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

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

Prevent unique violation Complicated Depends on other rows

id name NULL Testable in isolation

id name Jan

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

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

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

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

Solution Java Repository Bridge - JaRB

Databases are good at maintaining integrity; let them!

Prevent exception Testable in isolation Catch exception Not null Type Length Unique key Foreign key Primary key Check

Prevent exception Validation Not null Type Length

@Entity @DatabaseConstrained public class User { @NotNull @Length(max=3) private String name; private String email; } User name : varchar(3) NOT-NULL, UNIQUE email : varchar(100) Retrieve constraints Database as only truth No duplication

validate(new User( Henk )); 1. Loop over properties 3. Check name Henk on metadata name = Henk email = null Application 2. Get metadata user.name varchar(3) not null Determine column name (Hibernate) Database

Name cannot be longer than 3 characters validate(new User( Henk )); 1. Loop over properties 3. Check name Henk on metadata name = Henk email = null Application 2. Get metadata user.name varchar(3) not null Database

validate(new User( Henk )); validate(new User(null)); 1. Loop over properties name = null email = null 3. Check null name on metadata Application 2. Get metadata user.name varchar(3) not null Database

Name cannot be null validate(new User( Henk )); validate(new User(null)); 1. Loop over properties name = null email = null 3. Check null name on metadata Application 2. Get metadata user.name varchar(3) not null Database

validate(new User( Henk )); validate(new User(null)); validate(new User( Jan )); 1. Loop over properties 3. Check name Jan on metadata name = Jan email = null Application 2. Get metadata user.name varchar(3) not null Database

validate(new User( Henk )); validate(new User(null)); validate(new User( Jan )); 1. Loop over properties 3. Check name Jan on metadata name = Jan email = null Application 2. Get metadata user.name varchar(3) not null Database

validate(new User( Henk )); validate(new User(null)); validate(new User( Jan )); 1. Loop over properties name = Jan email = null 3. Check null email on metadata Application 2. Get metadata user.email varchar(100) Database

validate(new User( Henk )); validate(new User(null)); validate(new User( Jan )); 1. Loop over properties name = Jan email = null 3. Check null email on metadata Application 2. Get metadata user.email varchar(100) Database

validate(new User( Henk )); validate(new User(null)); validate(new User( Jan )); 1. Loop over properties name = Jan email = null 3. Check null email on metadata Application 2. Get metadata user.email varchar(100) Database

Super class @MappedSuperclass @DatabaseConstrained public abstract class BaseEntity { } @Entity public class User extends BaseEntity { private String name; private String email; }

JDBC Custom schema mapper @DatabaseConstrained public class User { private String name; private String email; }

Catch exception Exception translation Unique key Foreign key Primary key Check

Translate the JDBC exception into a proper constraint exception

Existing translators

Hibernate Object Relation Mapping Extracts constraint name from message

Hibernate Access to constraint name ConstraintViolationException getconstraintname() Heavy for plain JDBC Hardcoded names

Hardcoded names try { // Insert user } catch (ConstraintViolationException e) { if (e.getconstraintname() == uk_user_name ) { // Handle error } } Too technical Focus on domain

Spring Dependency Injection Templates JDBC DAO

Spring JDBC JdbcTemplate SQLExceptionTranslator Error codes Register own classes No constraint name

Spring Consistent hierarchy Extensible DataAccessException DataIntegrityViolationException

Spring DAO ORM (e.g. Hibernate) PersistenceExceptionTranslator Proxy

UserRepository Spring$Proxy ConstraintViolation Exception JPASystemException PersistenceExceptionTranslator

Hierarchy DataAccessException JPASystemException cause ConstraintViolationException getconstraintname() No constraint name Weaker API

Weaker API Unsafe cast try { userrepository.save(user); } catch (JPASystemException e) { ConstraintViolationException ce = (ConstraintViolationException) e.getcause(); if (ce.getconstraintname() == uk_user_name ) { // Handle error } } Why isn t this easier?

Recap Best of both worlds Hibernate Spring JaRB Constraint name Hierarchy Extensible

JaRB Concrete and domain specific exceptions. Map each constraint to a custom exception.

try { userrepository.save(new User( Jan )); } catch (UserNameAlreadyExistsException e) { error( User name already exists. ); }

try { userrepository.save(new User( Jan )); } catch (UserNameAlreadyExistsException e) { error( User name already exists. ); } catch (UserEmailAlreadyExistsException e) { error( User email already exists. ); }

Translator SQLIntegrity ConstraintException UserNameAlready ExistsException

Resolver Extract all information from exception SQLIntegrity ConstraintException ERROR: duplicate key value violates unique constraint \"uk_user_name\" Detail: Key (name)=(jan) already exists.

Resolver Extract all information from exception SQLIntegrity ConstraintException ERROR: duplicate key value violates unique constraint \"uk_user_name\" Detail: Key (name)=(jan) already exists. Constraint name Pattern matching Column name Value Vendor specific Version specific

Resolvers Pattern matching (default) PostgreSQL Oracle MySQL HSQL H2 Hibernate: constraint name only

Factory Create a concrete exception

Default factory InvalidTypeException LengthExceededViolationExceptio n CheckFailedException NotNullViolationException PrimaryKeyViolationException ForeignKeyViolationException UniqueKeyViolationException

DatabaseConstraintViolationException Constraint info InvalidTypeException LengthExceededViolationExceptio n CheckFailedException NotNullViolationException PrimaryKeyViolationException ForeignKeyViolationException UniqueKeyViolationException UserNameAlreadyExistsException

Custom exceptions @NamedConstraint( uk_user_name ) public class UserNameAlreadyExistsException extends UniqueKeyViolationException { } Scanned from class path Registered on constraint

Custom exceptions uk_user_name UserNameAlreadyExistsException uk_user_email UniqueKeyViolationException

Injectable arguments @NamedConstraint( uk_user_name ) public class UserNameAlreadyExistsException extends UniqueKeyViolationException { UserNameAlreadyExistsException( ) { } } Throwable (cause) DatabaseConstraintViolation ExceptionFactory

Less concrete try { userrepository.save(new User( Jan )); } catch (UniqueKeyViolationException e) { error( User name already exists. ); }

How?

Enable in Spring @EnableDatabaseConstraints(basePackage = org.myproject ) <jarb:enable-constraints base-package= org.myproject /> Enable exception translation Resolve database vendor Register custom exceptions Enable database validation

Get source Maven central <dependency> <groupid>org.jarbframework</groupid> <artifactid>jarb-constraints</artifactid> <version>2.1.0</version> </dependency> Github http://www.jarbframework.org

Questions?