Java(物件導向) 與 SQL 的概念衝突

Java(物件導向) 與 SQL 的概念衝突

The paradigm mismatch :

Java :

  1. public class User {
  2. String username;
  3. String address;
  4. Set billingDetails;
  5. // Accessor methods (getter/setter), business methods, etc.
  6. }
  7. public class BillingDetails {
  8. String account;
  9. String bankname;
  10. User user;
  11. // Accessor methods (getter/setter), business methods, etc.
  12. }

SQL :

  1. create table USERS (
  2. USERNAME varchar(15) not null primary key,
  3. ADDRESS varchar(255) not null
  4. );
  5. create table BILLINGDETAILS (
  6. ACCOUNT varchar(15) not null primary key,
  7. BANKNAME varchar(255) not null,
  8. USERNAME varchar(15) not null,
  9. foreign key (USERNAME) references USERS
  10. );


1. The problem of granularity (SQL 無法自訂 data type)

The most glaringly obvious problem with the current implementation is that you’ve designed an address as a simple String value. In most systems, it’s necessary to store street, city, state, country, and ZIP code information separately.

  • You have the choice of adding either several columns or a single column (of a new SQL data type).
  • This is clearly a problem of granularity. Broadly speaking, granularity refers to the relative size of the types you’re working with.
  • A new Address type (class) in Java and a new ADDRESS SQL data type should guarantee interoperability.
  • But you’ll find various problems if you check the support for userdefined data types (UDTs) in today’s SQL database management systems.

SQL :

  1. create table USERS (
  2. USERNAME varchar(15) not null primary key,
  3. ADDRESS address not null
  4. );

The pragmatic solution for this problem has several columns of built-in vendordefined SQL type.

  1. create table USERS (
  2. USERNAME varchar(15) not null primary key,
  3. ADDRESS_STREET varchar(255) not null,
  4. ADDRESS_ZIPCODE varchar(5) not null,
  5. ADDRESS_CITY varchar(255) not null
  6. );

Many simple persistence mechanisms fail to recognize this mismatch and so end up forcing the less flexible representation of SQL products on the object-oriented model, effectively flattening it.



2. The problem of subtypes (SQL 沒有繼承概念)

  • In Java, you implement type inheritance using superclasses and subclasses.
  • The result of this mismatch of subtypes is that the inheritance structure in a model must be persisted in an SQL database that doesn’t offer an inheritance mechanism.


3. The problem of identity (SQL 必需要 ID 當 PK,但 ID 卻無任何商業意義)

  • There are three ways to tackle this problem: two in the Java world and one in your SQL database.

  • Java defines two different notions of sameness:

    • Instance identity (roughly equivalent to memory location, checked with a == b)
    • Instance equality, as determined by the implementation of the equals() method (also called equality by value)
  • The identity of a database row is expressed as a comparison of primary key values.

  • A surrogate key column is a primary key column with no meaning to the application user.—in other words, a key that isn’t presented to the application user. Its only purpose is identifying data inside the application.

  1. create table USERS (
  2. ID bigint not null primary key,
  3. USERNAME varchar(15) not null unique,
  4. ...
  5. );
  6. create table BILLINGDETAILS (
  7. ID bigint not null primary key,
  8. ACCOUNT varchar(15) not null,
  9. BANKNAME varchar(255) not null,
  10. USER_ID bigint not null,
  11. foreign key (USER_ID) references USERS
  12. );


4. Problems relating to associations (SQL 利用 FK 來表示關聯)

  • Association mapping and the management of entity associations are central concepts in any object persistence solution.
  • Object-oriented languages represent associations using object references.
  • In the relational world (SQL), a foreign key–constrained column represents an association.

Java associations can have many-to-many multiplicity :

  1. public class User {
  2. Set billingDetails;
  3. }
  4. public class BillingDetails {
  5. Set users;
  6. }

But the foreign key declaration on the BILLINGDETAILS table is a many-to-one association: each bank account is linked to a particular user. Each user may have multiple linked bank accounts.

If you wish to represent a many-to-many association in an SQL database, you must introduce a new table, usually called a link table. In most cases, this table doesn’t appear anywhere in the domain model.

  1. create table USER_BILLINGDETAILS (
  2. USER_ID bigint,
  3. BILLINGDETAILS_ID bigint,
  4. primary key (USER_ID, BILLINGDETAILS_ID),
  5. foreign key (USER_ID) references USERS,
  6. foreign key (BILLINGDETAILS_ID) references BILLINGDETAILS
  7. );


5. The problem of data navigation (SQL 與 Java 從集合取資料方式不同)

  • There is a fundamental difference in how you access data in Java and in a relational database.
  • In Java (object-oriented), when you access a user’s billing information, you call someUser.getBillingDetails().iterator().next()
  • Unfortunately, this isn’t an efficient way to retrieve data from an SQL database.
  • The single most important thing you can do to improve the performance of data access code is to minimize the number of requests to the database.
  • The most obvious way to do this is to minimize the number of SQL queries. (select * from USERS u left outer join BILLINGDETAILS bd on bd.USER_ID = u.ID where u.ID = 123)

留言