• No results found

Java and RDBMS. Married with issues. Database constraints

N/A
N/A
Protected

Academic year: 2021

Share "Java and RDBMS. Married with issues. Database constraints"

Copied!
95
0
0

Loading.... (view fulltext now)

Full text

(1)

Java and RDBMS

Married with issues

(2)

Speaker

(3)

Situation

store

retrieve

Java


Application

Relational


Database

JDBC

(4)

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)

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

Name can only have


up to 3 characters

Name is required

Name can only occur once

Database

Maintain data

(8)

Constraint types

Not null

Type

Length

Primary key

Foreign key

Unique key

Check

(9)

Connection connection = …;


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


statement.executeUpdate(sql);


User

name : varchar(3)
 NOT-NULL,
 UNIQUE

What happens?

(10)

Connection connection = …;


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


statement.executeUpdate(sql);


User

name : varchar(3)
 NOT-NULL,
 UNIQUE

1 row updated

(11)

Connection connection = …;


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


statement.executeUpdate(sql);

What will happen?

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

(12)

Connection connection = …;


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


statement.executeUpdate(sql);

What will happen?

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

SQLIntegrityConstraint


ViolationException

(13)

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

(14)

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

(15)

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

(16)

Connection connection = …;


Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”;


statement.executeUpdate(sql);

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

What happens?

(17)

Connection connection = …;


Statement statement = connection.createStatement(); String sql = “INSERT INTO user (name) VALUES (NULL)”;


statement.executeUpdate(sql);

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

SQLIntegrityConstraint


ViolationException

(18)

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

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

(19)

Unique key violation

SQLIntegrityConstraint


ViolationException

(20)

Unique key violation

Not null violation

SQLIntegrityConstraint


ViolationException

(21)

SQLException

+ getSQLState() : int

+ getMessage() : String

SQLIntegrityConstraint


ViolationException

(22)

SQLException

+ getSQLState() : int

+ getMessage() : String

SQLIntegrityConstraint


ViolationException

(23)

State

Name

23000

Integrity constraint

23001

Restrict violation

23502

Not null violation

23503

Foreign key violation

23505

Unique violation

23514

Check violation

(24)

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

(25)

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

(26)

Multiple not-null values

User

name : varchar(3)
 NOT-NULL,
 UNIQUE email : varchar(30)
 NOT-NULL, 
 UNIQUE

(27)

uk_user_name

uk_user_email

Multiple not-null values

Multiple unique values

User

name : varchar(3)
 NOT-NULL,
 UNIQUE email : varchar(30)
 NOT-NULL, 
 UNIQUE

(28)

SQLException

+ getSQLState() : int

+ getMessage() : String

SQLIntegrityConstraint


ViolationException

(29)

Vendor messages

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.

Oracle

ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n

MySQL

Duplicate entry 'Jan' for key 'uk_user_name'

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

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.

Oracle

ORA-00001: unique constraint (GOTO.UK_USER_NAME) violated\n

MySQL

Duplicate entry 'Jan' for key 'uk_user_name'

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)

Message

Pattern matching

Vendor specific

Extract violation info

Just too difficult

(32)

JDBC needs a better exception API

( for integrity constraints )

Concrete exception classes

UniqueKeyViolationException NotNullViolationException

Access to constraint info

getColumnName() getConstraintName()

(33)
(34)
(35)

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;


}

Conveys

No SQL exception

(38)

Applicatio

n Database

throw new RuntimeException

(39)

User

@NotNull


private String name

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

Application

Database

Duplication

(40)

User

@NotNull


private String name

User

name : varchar(3)
 NOT-NULL,
 UNIQUE

Application

Database

Kept in sync

Unexpected SQL

exceptions

Duplication

(41)

Complicated

Depends on other rows

(42)

id

name

NULL

(43)

id

name

Jan

(44)

id

name

id

name

users

Piet

Henk

Jan

1

2

3

Jan

Requires data

(45)

No SQL exceptions

Extra query

Not atomic

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


}

(46)

Problem: Not atomic

Applicatio

n Database

INSERT (name) VALUES (‘Jan’) INSERTED 1

Thread 2

COUNT WHERE name = ‘Jan’ return 0

Thread 1

INSERT (name) VALUES (‘Jan’)

Unique key violation

Thread 1

Decision on


old data

Unexpected

(47)

Recap

No SQL exceptions

Duplication

Error prone

Not null

Extra query

Unique key

No SQL exceptions

Error prone

(48)

Solution

(49)

Databases are good at


maintaining integrity;

(50)

Catch exception

Prevent exception

Testable in isolation

Not null

Type

Length

Check

Unique key

Foreign key

Primary key

(51)

Prevent exception

Validation

(52)

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

No duplication

Retrieve

constraints


Database as

only truth

(53)

validate(new User(‘Henk’));

varchar(3)


not null

name = ‘Henk’

email = null

1. Loop over properties

3. Check name ‘Henk’


on metadata

Database Application

2. Get metadata


user.name

Determine column name

(Hibernate)

(54)

Database Application

name = ‘Henk’

email = null

varchar(

3

)


not null

1. Loop over properties

3. Check name ‘Henk’


on metadata

“ Name cannot be longer


than 3 characters “

2. Get metadata


user.name

(55)

validate(new User(‘Henk’));

name = null

email = null

1. Loop over properties

3. Check

null name


on metadata

validate(new User(null));

varchar(3)


not null

Database Application

2. Get metadata


user.name

(56)

validate(new User(‘Henk’));

Application

name = null

email = null

varchar(3)


not null

1. Loop over properties

3. Check

null name


on metadata

validate(new User(null));

“ Name cannot be null “

Database

2. Get metadata


(57)

validate(new User(‘Henk’));

name = ‘Jan’

email = null

1. Loop over properties

3. Check name ‘Jan’


on metadata

validate(new User(null));

validate(new User(‘Jan’));

Database Application

varchar(3)


not null

2. Get metadata


user.name

(58)

validate(new User(‘Henk’));

Database Application

name = ‘Jan’

email = null

varchar(

3

)


not null

1. Loop over properties

3. Check name ‘Jan’


on metadata

2. Get metadata


user.name

validate(new User(null));

(59)

validate(new User(‘Henk’));

name = ‘Jan’


email = null

varchar(100)

1. Loop over properties

3. Check

null email


on metadata

Database Application

2. Get metadata


user.email

validate(new User(null));

validate(new User(‘Jan’));

(60)

validate(new User(‘Henk’));

Database Application

name = ‘Jan’


email = null

varchar(

100

)

1. Loop over properties

3. Check

null email


on metadata

2. Get metadata


user.email

validate(new User(null));

(61)

validate(new User(‘Henk’));

Database Application

name = ‘Jan’


email = null

varchar(

100

)

1. Loop over properties

3. Check

null email


on metadata

2. Get metadata


user.email

validate(new User(null));

(62)

Super class

@MappedSuperclass


@DatabaseConstrained

public abstract class BaseEntity {


}

@Entity


public class User extends BaseEntity {


private String name;


private String email;


}

(63)

JDBC

@DatabaseConstrained

public class User {


private String name;


private String email;


}

(64)

Catch exception

Exception translation

Check

Unique key

Foreign key

Primary key

(65)

Translate the JDBC exception into

a proper

constraint

exception

(66)
(67)

Object Relation Mapping

Extracts constraint name from message

(68)

Hibernate

ConstraintViolationException getConstraintName()

Access to constraint name

Hardcoded names

Heavy for plain JDBC

(69)

Hardcoded names

try {


// Insert user


} catch (ConstraintViolationException e) {


if (

e.getConstraintName() == “uk_user_name”

) {


// Handle error


}


}

Too technical

Focus on domain

(70)

Dependency Injection

Templates

JDBC

DAO

(71)

JdbcTemplate

SQLExceptionTranslator

Error codes

Register own classes

No constraint name

(72)

Spring

DataAccessException

DataIntegrityViolationException

Consistent hierarchy

(73)

ORM (e.g. Hibernate)

PersistenceExceptionTranslator

Proxy

(74)


 
 Spring$Proxy PersistenceExceptionTranslator ConstraintViolation
 Exception JPASystemException UserRepository

(75)

No constraint name

ConstraintViolationException getConstraintName() JPASystemException DataAccessException cause

Hierarchy

Weaker API

(76)

Weaker API

try {


userRepository.save(user);


} catch (JPASystemException e) {


ConstraintViolationException ce = 


(ConstraintViolationException) e.getCause()

;


if (ce.getConstraintName() == “uk_user_name”) {


// Handle error


}


}

Unsafe cast

(77)

Recap

Constraint name

Hierarchy

Extensible

Hibernate

Spring

JaRB

Best of both worlds

(78)

JaRB

Concrete and domain specific exceptions.

(79)

try {


userRepository.save(new User(“Jan”));


} catch (

UserNameAlreadyExistsException

e) {


error(“User name already exists.”);


(80)

try {


userRepository.save(new User(“Jan”));


} catch (

UserNameAlreadyExistsException

e) {


error(“User name already exists.”);


} catch (

UserEmailAlreadyExistsException

e) {


error(“User email already exists.”);


(81)

Translator

SQLIntegrity


ConstraintException

UserNameAlready
 ExistsException

(82)

Resolver

ERROR: duplicate key value violates
 unique constraint \"uk_user_name\"


Detail: Key (name)=(Jan) already exists.

Extract all information from exception

SQLIntegrity


(83)

Resolver

ERROR: duplicate key value violates
 unique constraint \"uk_user_name\"


Detail: Key (name)=(Jan) already exists.

Vendor specific

Pattern matching

Extract all information from exception

Column name

Value

Constraint name

Version specific

SQLIntegrity


(84)

Resolvers

Pattern matching (default)

PostgreSQL

Oracle

MySQL

HSQL

H2

(85)

Factory

(86)

Default factory

UniqueKeyViolationException NotNullViolationException LengthExceededViolationExceptio n PrimaryKeyViolationException CheckFailedException InvalidTypeException ForeignKeyViolationException

(87)

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

(88)

Custom exceptions

@NamedConstraint(“uk_user_name”)

public class UserNameAlreadyExistsException


extends UniqueKeyViolationException {


}

Scanned from class path

Registered on constraint

(89)

Custom exceptions

uk_user_name

UserNameAlreadyExistsException

(90)

Injectable arguments

@NamedConstraint(“uk_user_name”)

public class UserNameAlreadyExistsException


extends UniqueKeyViolationException {


UserNameAlreadyExistsException(…) { }


}

DatabaseConstraintViolation

Throwable (cause)

ExceptionFactory

(91)

Less concrete

try {


userRepository.save(new User(“Jan”));


} catch (

UniqueKeyViolationException

e) {


error(“User name already exists.”);


(92)
(93)

Enable in Spring

@EnableDatabaseConstraints(basePackage = “org.myproject”)

Enable exception translation

Enable database validation

Resolve database vendor

Register custom exceptions

(94)

Get source

<dependency>

<groupId>org.jarbframework</groupId>

<artifactId>jarb-constraints</artifactId>

<version>2.1.0</version>

</dependency>

Maven central

http://www.jarbframework.org

Github

(95)

References

Related documents

Qoc kha jbujh s!stc wjs suddcreb&#34; drk j screcs kd arjwijg/s, Webgc wokhc kd toc s!stc wjs tk ic jebtjebca weto ojbas toc prkgcss kd /ccpeb&#34; jebtjebeb&#34;

The international teachers (both NES and NNES) and some of the national teachers had learning and professional experiences that derived not just from their own countries, as

[r]

The options on this tab depend on a table type selected in the Steel summary tables - style manager dialog. The example above displays the options available after selecting the

In particular, the corpus analysis has revealed that ‘alibrāliyah’ is mainly associated with the discourse of religion and human rights, in which the salient construction

Using each of these three treatment effect metrics (ORs, HRs, and median differ- ences), separate der Simonian and Laird random-effects uni- variate meta-analyses were used to

Any creature coming into physical contact with a blightburn crystal takes 2d6 points of fire damage per round, and creatures within 60 feet of blightburn crystals are exposed

These are my solutions to problems given in Theodore Frankel’s book “The Ge- ometry of Physics” (second edition).. As I could not find any other sources, I do not know whether they