o'reilly : java database best practices - doc.lagout.org database best... · focus on a single...

614

Upload: dinhtuyen

Post on 20-Mar-2018

258 views

Category:

Documents


11 download

TRANSCRIPT

Page 1: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 2: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Main Page Table of content Copyright Dedication Preface Audience Organization of This Book Conventions Used in This Book Comments and Questions About the Philosophers Acknowledgments Part I: Data Architecture Chapter 1. Elements of DatabaseApplications 1.1 Database Application Architectures 1.2 Component Models 1.3 Persistence Models Chapter 2. Relational Data Architecture 2.1 Relational Concepts 2.2 Modeling 2.3 Normalization

Page 3: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.4 Denormalization 2.5 Object-Relational Mapping Chapter 3. Transaction Management 3.1 Transactions 3.2 Concurrency 3.3 JDBC Transaction Management 3.4 Transaction Management Paradigms Part II: Persistence Models Chapter 4. Persistence Fundamentals 4.1 Patterns of Persistence 4.2 A Guest Book Application Chapter 5. EJB CMP 5.1 Which CMP Model to Use? 5.2 The EJB 1.0 CMP Model 5.3 The EJB 2.0 CMP Model 5.4 Beyond CMP Chapter 6. EJB BMP 6.1 EJBs Revisited 6.2 BMP Patterns 6.3 State Management 6.4 Exception Handling Chapter 7. JDO Persistence

Page 4: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

7.1 JDO or EJB? 7.2 Basic JDO Persistence 7.3 EJB BMP with JDO Chapter 8. Alternative PersistenceFrameworks 8.1 Why Alternative Frameworks? 8.2 Persistence Approach 8.3 Persistence Operations 8.4 Searches 8.5 Beyond the Basics Part III: Tutorials Chapter 9. J2EE Basics 9.1 The Platform 9.2 Java Naming and Directory Interface 9.3 JavaServer Pages 9.4 Remote Method Invocation 9.5 Enterprise JavaBeans Chapter 10. SQL 10.1 Background 10.2 Database Creation 10.3 Table Management 10.4 Data Management

Page 5: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 11. JDBC 11.1 Architecture 11.2 Simple Database Access 11.3 Advanced JDBC Chapter 12. JDO 12.1 Architecture 12.2 Enhancement 12.3 Queries 12.4 Changes 12.5 Transactions 12.6 Inheritance Colophon Index Index SYMBOL Index A Index B Index C Index D Index E Index F Index G Index H

Page 6: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Index I Index J Index K Index L Index M Index N Index O Index P Index Q Index R Index S Index T Index U Index V Index W Index X

Page 7: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

• Table of Contents• Index• Reviews• Examples• Reader Reviews• Errata• Academic

Java Database Best PracticesBy George Reese

Publisher : O'ReillyPub Date : May 2003

ISBN : 0-596-00522-9Pages : 286

Unlike other books on this topic, which

Page 8: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

focus on a single way to do things,Java Database Best Practices takesyou through a wide variety of differentways to store and access data,enabling you to learn which"persistence model" is mostappropriate for each type ofapplication. This unique book coversEnterprise JavaBeans, Java DataObjects, the Java DatabaseConnectivity API (JDBC) and other,lesser-known options.

Page 9: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

• Table of Contents• Index• Reviews• Examples• Reader Reviews• Errata• Academic

Java Database Best PracticesBy George Reese

Publisher : O'ReillyPub Date : May 2003

ISBN : 0-596-00522-9Pages : 286

Copyright

Dedication

Preface

Audience

Organization of This Book

Conventions Used in This Book

Comments and Questions

About the Philosophers

Acknowledgments

Part I: Data Architecture

Chapter 1. Elements of Database Applications

Section 1.1. Database Application Architectures

Page 10: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Section 1.2. Component Models

Section 1.3. Persistence Models

Chapter 2. Relational Data Architecture

Section 2.1. Relational Concepts

Section 2.2. Modeling

Section 2.3. Normalization

Section 2.4. Denormalization

Section 2.5. Object-Relational Mapping

Chapter 3. Transaction Management

Section 3.1. Transactions

Section 3.2. Concurrency

Section 3.3. JDBC Transaction Management

Section 3.4. Transaction Management Paradigms

Part II: Persistence Models

Chapter 4. Persistence Fundamentals

Section 4.1. Patterns of Persistence

Section 4.2. A Guest Book Application

Chapter 5. EJB CMP

Section 5.1. Which CMP Model to Use?

Section 5.2. The EJB 1.0 CMP Model

Section 5.3. The EJB 2.0 CMP Model

Section 5.4. Beyond CMP

Chapter 6. EJB BMP

Section 6.1. EJBs Revisited

Section 6.2. BMP Patterns

Section 6.3. State Management

Section 6.4. Exception Handling

Chapter 7. JDO Persistence

Section 7.1. JDO or EJB?

Section 7.2. Basic JDO Persistence

Section 7.3. EJB BMP w ith JDO

Chapter 8. Alternative Persistence Frameworks

Section 8.1. Why Alternative Frameworks?

Section 8.2. Persistence Approach

Section 8.3. Persistence Operations

Section 8.4. Searches

Section 8.5. Beyond the Basics

Page 11: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Part III: Tutorials

Chapter 9. J2EE Basics

Section 9.1. The Platform

Section 9.2. Java Naming and Directory Interface

Section 9.3. JavaServer Pages

Section 9.4. Remote Method Invocation

Section 9.5. Enterprise JavaBeans

Chapter 10. SQL

Section 10.1. Background

Section 10.2. Database Creation

Section 10.3. Table Management

Section 10.4. Data Management

Chapter 11. JDBC

Section 11.1. Architecture

Section 11.2. Simple Database Access

Section 11.3. Advanced JDBC

Chapter 12. JDO

Section 12.1. Architecture

Section 12.2. Enhancement

Section 12.3. Queries

Section 12.4. Changes

Section 12.5. Transactions

Section 12.6. Inheritance

Colophon

Index

Page 12: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Copyright

Copyright © 2003 O'Reilly & Associates, Inc.

Printed in the United States of America.

Published by O'Reilly & Associates, Inc., 1005Gravenstein Highway North, Sebastopol, CA95472.

O'Reilly & Associates books may be purchasedfor educational, business, or sales promotionaluse. Online editions are also available for mosttitles (http://safari.oreilly.com). For moreinformation, contact our corporate/institutionalsales department: (800) 998-9938 [email protected].

Nutshell Handbook, the Nutshell Handbook logo,and the O'Reilly logo are registered trademarksof O'Reilly & Associates, Inc. Java and all Java-based trademarks and logos are trademarks orregistered trademarks of Sun Microsystems, Inc.,in the United States and other countries. O'Reilly& Associates, Inc. is independent of SunMicrosystems. The licenses for all the opensource tools presented in this book are includedwith the online examples. Many of the

Page 13: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

designations used by manufacturers and sellersto distinguish their products are claimed astrademarks. Where those designations appear inthis book, and O'Reilly & Associates, Inc. wasaware of a trademark claim, the designationshave been printed in caps or initial caps. Theassociation between the image of a taguan andthe topic of Java database best practices is atrademark of O'Reilly & Associates, Inc.

While every precaution has been taken in thepreparation of this book, the publisher andauthors assume no responsibility for errors oromissions, or for damages resulting from the useof the information contained herein.

Page 14: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Dedication

To my beautiful w ife, Monique, and thechild she carries.

Page 15: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 16: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

PrefaceI t is never too late to become reasonableand wise; but if the insight comes late,there is always more difficulty in startingthe change.

Immanuel Kant, Prolegomena to Any FutureMetaphysics

Java database programming has grown muchmore complex than it was in 1996 when I wrotethe first edition of my book DatabaseProgramming with JDBC and Java (O'Reilly &Associates). The J2EE platform did not exist.Distributed programming was RMI, JDBC wassimple, and transaction management andpersistence did not exist in the Java vocabulary.Database programming in 1996 was quite simplyJDBC programming.

To place database programming in a real-worldcontext, I spent much of that book introducingways to build robust persistence models andmanage transactions using only the JDBC API. Asyou can imagine, you had to do a lot of thingsfor yourself that developers now take for grantedin the Java platform.

Page 17: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The Java world has certainly changed since then.Not only does Java provide you with apersistence model, it provides you with threedifferent persistence models built right into thecore J2EE platform. Outside the J2EE platform isthe popular JDO persistence model. In addition,many tools exist to enable you to effectively usethird-party and custom persistence models. All ofthese choices present a problem for databaseprogrammers that simply did not exist in 1996:what are the best approaches to databaseprogramming with the Java language?

This book seeks to aid the Java developer inappreciating the different approaches Javaprovides for database programming. It helps youassess what approaches fit which problems, andwhat the best practices are under each model.

Page 18: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Audience

This book is not an introductory text. It is alsonot a tutorial on any particular API. It is,instead, a description of the best practices forusing a database to drive a variety of Javaapplication architectures. It assumes you haveat least a passing familiarity with one or more ofthe Java enterprise APIs, as well as SQL. You donot, however, need to be an expert in all ofthem. To help you with any holes in yourknowledge of these tools, I provide a fewtutorial chapters at the end of the book.

Page 19: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Organization of This Book

This book is divided into three distinct sections.The first two sections are the meat of this book:best practices for Java database architecture anddevelopment. The first section focuses on thearchitecture aspect and the second section onthe development aspect.

Part I

Chapter 1 is an overview of the art of databaseprogramming. It examines the various tools andskills needed for database programming andcovers common database applicationarchitectures. The chapter is mostly reviewmaterial for experienced database programmers.

Chapter 2 tackles one of the more difficultaspects of database programming, especially forthe object-oriented programmer: dataarchitecture. This chapter begins with relationaltheory and covers critical topics such asnormalization and object-relational modeling. Itis a very important chapter for databaseprogrammers of all levels of experience.

Page 20: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Though relational architecture is one of the moredifficult aspects of database programming,transaction management is where databaseprogrammers make most of their mistakes.Chapter 3 covers transactions and transactionmanagement.

Part II

The second section begins with an overview ofpersistence concepts. In short, persistence isthe practice of saving application state to a datastore. Chapter 4 introduces this practice with aneye on using relational databases as your datastore for Java applications.

Chapter 5 through Chapter 8 go into the bestpractices for different Java persistence models.Chapter 5 begins with container-managedpersistence under the Enterprise JavaBeanscomponent model for Versions 1 and 2. Chapter 6tackles the other EJB persistence model, bean-managed persistence. Chapter 7 dives into anevolving, popular persistence model, Java DataObjects. Finally, Chapter 8 looks at alternativesto the standard Java persistence models.

Page 21: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Part III

The third section of the book contains tutorialson the core technologies covered in this book.No reader should need to read all of the tutorialchapters. Instead, I expect that most readerswill be familiar with the subject in several, butnot all, of the tutorial chapters. The tutorialchapters provide the basic knowledge necessaryto understand key concepts used in the first twosections. Don't look to any of the tutorialchapters to make you an expert in its subjectmatter. I have provided tutorials on the J2EEplatform (Chapter 9), SQL (Chapter 10), JDBC(Chapter 11), and JDO (Chapter 12).

I recommend reading the first two sections inorder, breaking that order only to refer to atutorial chapter for a subject on which you lackfamiliarity.

Page 22: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Conventions Used in This Book

The following typographical conventions are usedin this book:

I talic

Used for filenames and directory names,programs, compilers, tools, utilities, URLs,emphasis, and first use of a technical term.

Constant width

Used in code examples and to show thecontents of files. Also used for tags,attributes, and environment variable namesappearing in the text.

Constant width italic

Used as a placeholder to indicate an itemthat should be replaced with an actual valuein your program.

Page 23: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Constant width bold

Used to highlight a particular section orchange in code, such as a custom tag or achange in a transaction.

Page 24: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Comments and Questions

Please address comments and questionsconcerning this book to the publisher:

O'Reilly & Associates, Inc.1005 Gravenstein Highway NorthSebastopol, CA 95472(800) 998-9938 (in the United States orCanada)(707) 829-0515 (international/local)(707) 829-0104 (fax)

There is a web page for this book, which listserrata, examples, or any additional information.You can access this page at:

http://www.oreilly.com/catalog/javadtabp

To comment or ask technical questions aboutthis book, send email to:

[email protected]

For more information about books, conferences,Resource Centers, and the O'Reilly Network, seethe O'Reilly web site at:

Page 25: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

http://www.oreilly.com

Page 26: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

About the Philosophers

Daniel Dennett (Chapter 1)

Dennett, who teaches at Tufts University, isprobably my favorite philosopher. His booksare actually well written, which is a rarequality among philosophy texts. His worksrun the spectrum of philosophy, but hisgreatest influence lies in the philosophiesof mind and science. If you want a funphilosophy book to read that does notrequire you to be a philosopher, pick up hisbook Elbow Room. If you are looking forsomething more weighty, but equallyaccessible, read Darwin's Dangerous Idea.

René Descartes (Chapter 2)

Though he lived from 1596 until 1650,Descartes's writings mark the beginning ofmodern philosophy. He was a Frenchphilosopher who emphasized a solipsisticapproach to epistemology. He is the author

Page 27: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

of the famous quote "Cogito, ergo sum," or"I think, therefore I am."

Donald Davidson (Chapter 3)

Donald Davidson is among the mostimportant philosophers of the late 20thcentury. He is particularly influential in thephilosophy of language and action theory.He is currently a professor at the Universityof California, Berkeley. My senior thesis atBates College was based on his writings.

Ludwig W ittgenstein (Chapter 4)

Ludwig W ittgenstein was a Germanphilosopher who lived from 1889 until 1951.His primary contributions to philosophy werein the philosophy of language. He oncewrote that "philosophy is a battle againstthe bewitchment of our intelligence bymeans of language."

Friedrich Nietzsche (Chapter 5)

Page 28: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Nietzsche, who lived in Germany from 1844until 1900, is likely the most controversial"serious" philosopher. His writings haveinfluenced nearly every kind of philosophybut have had their greatest impact bothpositive and negative in the area of ethics.

Martin Heidegger (Chapter 6)

Heidegger, another 20th-century Germanphilosopher, made popular the movementstarted by Edmund Husserl known asphenomenology. Phenomenology attemptsto understand things as they presentthemselves rather than to appeal to somesort of essential nature hidden from us.This movement eventually led to the mostpopularly known philosophical movement,existentialism.

David Kolb (Chapter 7)

David Kolb was my major adviser at BatesCollege in Lewiston, Maine, where he is aCharles A. Dana Professor of Philosophy. He

Page 29: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

has written extensively on Hegelianphilosophy and nonlinear writing inphilosophy.

Immanuel Kant (Preface, Chapter 8)

Immanuel Kant may be the most influentialphilosopher of the second millennium. Hewas a German philosopher who lived from1724 until 1804. He emphasized a rationalapproach to all philosophical pursuits. Thisrationalism has had its greatest impact inthe area of ethics, where moral principlesare, according to Kant, derived entirely fromreason.

David Hume (Chapter 9)

David Hume was an 18th-century Scottishphilosopher who wrote on a range ofphilosophical subjects. He is largelyresponsible for the school of philosophyknown as empiricism.

Page 30: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Ruth Garrett Millikan (Chapter 10)

Ruth Garrett Millikan is a professor ofphilosophy at the University of Connecticut.She is an influential modern philosopher inthe philosophy of language andepistemology.

Noam Chomsky (Chapter 11)

Born in 1928, Noam Chomsky is perhaps themost famous living philosopher. While oftenknown for his political activism especiallyduring the Vietnam era his greatestcontributions to philosophy lie in thephilosophy of language.

Jean-Paul Sartre (Chapter 12)

Sartre was a novelist, a philosopher, and amember of the French Resistance duringWorld War II. As a philosopher, he is bestknown as the force behind theexistentialism movement. Existentialismgoes beyond phenomenology in its claimsabout the essential nature of things. While

Page 31: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

phenomenology claims that we should notappeal to an essential nature of a thing inorder to understand it, existentialism saysthat no such essential nature exists. Athing is exactly as it presents itself.

Page 32: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Acknowledgments

So much work other than that of the author goesinto putting together a solid book. First of all,Brett McLaughlin's editing skills and general Javaknowledge have been critical to keeping me inline. Also critical to the book was thecontribution of Chapter 8 on alternativepersistence frameworks by Justen Stepka. I amnot much of a fan of leaving the core platform,so this book would have been incompletewithout his contribution.

Several people contributed to reviewing thisbook: Nick Kokotovich, Justen Stepka, and HenriYandell. In addition, Monique Girgis, Andy Oram,and John Viega have all at times provided acritical eye on this content.

Page 33: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 34: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Part I: Data ArchitectureDatabase programming begins with thedatabase. To build effective databaseapplications, you need to fully appreciatethe work the database does for thoseapplications. This first section addressesthe best practices in data architecture--thedesign of relational database elements thatsupport database applications.

Page 35: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 36: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 1. Elements ofDatabase Applications

I f Life is a Tree, it could have arisen froman inexorable, automatic rebuilding processin which designs would accumulate overtime.

Daniel C. Dennett, Darwin's Dangerous Idea

Once upon a time, database programming on theJava platform was an exercise in nativeprogramming; nothing existed within the Javaplatform to support database programmingefforts. The first tool in the databaseprogramming arsenal arrived in March 1996 inthe form of Java's first proposed enterprise API,JDBC. JDBC enabled application developers touse a single API to access any database fromany vendor.

JDBC, however, is the start not the end ofdatabase programming. JDBC simply enables youto access a database; it does not address allelements of database programming. It does not:

Ensure your database meets the need of

Page 37: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

your application

Automate the mapping of Java classes intorelational entities

Provide a model for structuring your Javacomponents

Manage application transactions

This book is about database programming; it isnot about JDBC. However, because JDBC playssuch a critical role in database programming, itwill play a critical role in this book. If you needto brush up on your JDBC skills, take a look atthe tutorial in Chapter 11 or my earlier book,Database Programming with JDBC and Java(O'Reilly). This book addresses all of theelements of database programming and theirrespective roles in supporting real worlddatabase applications.

Page 38: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.1 Database Application Architectures

Database applications require an entire networkof software in order to function. Even the mostbasic of database applications the command-lineSQL tool is a complex system involving thedatabase engine and a separate client utility.Architecture is the space in which all of theelements of an application operate. Before welook at each of those elements, we should firsttake a look at the space itself.

Architecture identifies the hardware and softwarenecessary to support an application and specifieshow those tools communicate within a network.When referring to architecture, different peopletend to have different things in mind. In somecases, architecture refers to the way hardware isplaced on a physical network. This kind ofarchitecture is called network architecture. Othertimes, however, architecture refers to thesystem architecture the way different logical andphysical components work together to create acomplex network application. The last kind ofarchitecture is software architecture, whenarchitecture refers to the design of one of thepieces of software that make up the system

Page 39: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

architecture.

1.1.1 The Network Architecture

The network architecture focuses on hardwareissues and how they connect to one another. Thequality of your network architecture affectssecurity and bandwidth and limits the ability ofyour applications to talk with different parts ofthe system. Figure 1-1 is a simple networkarchitecture diagram.

Figure 1-1. A database server in anetwork architecture diagram

It shows how the network separates the Internetfrom the network in which the web server runswith a firewall. Similarly, this network diagramplaces the database server in a separatenetwork segment, again separated by a firewall.In spite of the fact that very little about network

Page 40: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

architecture is specific to database applications,it can make a significant impact on theperformance of those applications. It is thereforehelpful to understand those aspects mostrelevant to database systems.

1.1.1.1 Network segmentation

Segmentation is the way in which the network isdivided for performance and security. Routers,bridges, and firewalls are all tools of networksegmentation.

The first rule of segmentation is to divide yournetwork into regions of equal hostility andsensitivity. Hostility describes the attitude ofpeople with access to a given network segment.The Internet, for example, is considered anextremely hostile network. Your homenetwork assuming you have no children isconversely minimally hostile.

Sensitivity represents the risk profile of the datawithin a network segment. A high-risk profilemeans that public exposure or destruction of thedata can cause significant harm. A sensitivenetwork segment is therefore one that houses

Page 41: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

data that must be kept private at all costs. IRSdatabase servers have a very high degree ofsensitivity, whereas a Quake server ranks on thelow end.

BEST PRACTICE: Place your databaseservers on a high-sensitivity, low-hostilitynetwork segment. In other words, you shouldnever place a database server directly on theInternet or a network segment that is evenroutable to the Internet.

If two software components have very differentlevels of sensitivity, they should be on differentnetwork segments separated by firewalls thatlimit the interaction between their networks.Because databases serve as primary datastorage points, they tend to have highersensitivity profiles than other softwarecomponents. As a good general rule of thumb,database servers should be protected in a high-security network segment. In Figure 1-1, forexample, a firewall separates the web serverfrom the database server.

BEST PRACTICE: Segment your network intoregions of equal hostility and sensitivity.

Page 42: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.1.1.2 Bandwidth

Databases are the fountain from which datastreams to all kinds of applications on thenetwork. It is therefore critical especially forhigh-volume database servers to allocate thenecessary bandwidth to database servers. It isnot uncommon for database servers to beconnected to the network through multiple fiber-based gigabit Ethernet ports.

Proper bandwidth also means paying attention toissues other than the raw size of your pipe. Agood network architect also structures thetopology of the network to minimize packetcollisions and bring the database network asclose as possible to the other networks that relyon the databases.

BEST PRACTICE: Place your databaseservers on gigabit or 100-megabit networksegments. Never use anything less than 10megabits.

Page 43: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.1.1.3 Hardware

Database engines are among the most resource-intensive applications commonly found inbusiness environments. Solid performance fordatabase applications demands the properhardware for all parts of the application. If youwere to choose only one thing to spend moneyon, you should spend it on RAM. Running a veryclose second to RAM in importance, however, isdisk access speed.

BEST PRACTICE: When selecting hardwarefor database servers, spend your money onRAM and high-speed disk access.

Ultimately, a database will run faster if it cancache a lot of data in RAM. Ideally, you havemore memory for your database engine than youhave data. In reality, however, that muchmemory is rarely possible. Good databaseperformance therefore needs a solid array ofdisks. Though SCSI disks are the ideal, a RAID ofIDE disks can support a web site's database justfine. The disks should then be divided into atleast three sets of responsibilities:

Page 44: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

System data

Database log files

Database tables and indexes

It is even better if your database engine enablesyou to split up tables and indexes on differentdisks. You want the database tables and indexeson the fastest drives you have available.

BEST PRACTICE: Split your tables andindexes across different physical drives tomaximize database performance.

1.1.2 Various System Architectures

The role of the system architect is to look at theoverall technology objectives of an organizationand establish a system architecture thatmaximizes the reuse of critical components. Asimple web application can work well in anynumber of different system architectures; itworks best, however, when it fits nicely with theother applications in that architecture. For

Page 45: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

example, you can build an excellent webapplication using Perl and MySQL. If theorganization you are building it for, however, hasan established J2EE (Java 2 Enterprise Edition)infrastructure with an Oracle backend, you areintroducing new components requiringmaintenance that cannot be easily integratedinto that organization's existing environment.

The starting point for determining an appropriatesystem architecture is to understand the basicenterprise platform for the organization. BecauseI am covering database programming in a J2EEenvironment, I will assume your basic enterpriseplatform is J2EE. Alternatives include .NET andgeneral web services. These platforms all comewith basic approaches to different kinds ofarchitectural requirements. In this section, I willbriefly discuss the different system architecturesthat fit inside the J2EE platform.

Page 46: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 47: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Making Architectural DecisionsA lot of time, technical people want to believe there isone true architecture. Unfortunately, there is no suchthing. There is only the right architecture for the rightorganization. I have developed tools I call architecturalprinciples that I use to help me make technologydecisions. They help w ith questions like:

What should the organization's enterpriseplatform be?

What is the appropriate system architecturew ithin that platform?

What application server/content managementserver/database engine should we use?

In other words, architectural principles form the basis ofevery technology decision.

Architectural principles are maxims that no technologydecision can violate w ithout rigorous justification for theviolation. They complete the phrase, "W ithout strongjustification to the contrary, all of our technologiesw ill..." Examples of architectural principles include:

Be based on open standards.

Leverage open source technologies.

Be fully internationalized and localized.

BEST PRACTICE: Develop architecturalprinciples and use them as the basis for alltechnology decisions for your application.

Page 48: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.1.2.1 The client/serverarchitecture

The client/server architecture is one of theoldest distributed computing architectures in useon the J2EE platform. You will sometimes hearpeople refer to the client/server architecture as atwo-tier architecture. The term two-tierdescribes the way in which applicationprocessing can be divided in a client/serverapplication. A two-tier application ideallyprovides multiple workstations with a uniformpresentation layer that communicates with acentralized database. The presentation layer isgenerally the client, and the database layer isthe server.

Figure 1-2 shows how two-tier systems provideclients with access to centralized data. A clientlike a Java Swing application talks directly to adatabase and displays the data in the userinterface.

Figure 1-2. The client/serverarchitecture

Page 49: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

A client/server architecture is definitelyappropriate for some applications. Specifically,any application that must deal directly with thedatabase needs to be a client/server application.For example, the command-line tools that enableyou to enter arbitrary SQL statements areclient/server applications that fit this profile. Infact, just about any database administration toolis a good candidate for a client/serverarchitecture.

A client/server architecture falls apart, however,when application logic needs to operate on thedata from the database or when application logicneeds to be shared among multiple clients. Theclient/server architecture suffers specifically fromthe following problems:

The fat client

Perhaps you have seen a client/serverapplication evolve over time to include more

Page 50: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and more application logic operating ondata from the database. Ideally, theclient/server architecture is supposed to leteach machine do only the processingrelevant to its specialization graphicalpresentation of data on the client and thestorage and retrieval of data on the server.This breakdown, however, does not clearlyprovide a place for application logic alsoknown as business logic. As more and morebusiness logic ends up in the client, youend up with a problem known as the fatclient. Fat client systems are notorious fortheir inability to adapt to changingenvironments and scale with growing userand data volume.

Object reuse

Object reuse[1] is a very vague, yet centralconcept to object-oriented softwareengineering. You can reuse code throughcutting and pasting or through linking eitherstatically or dynamically to an API, or youcan reuse shared object instances. Theideal form of reuse is to reuse shared objectinstances among applications. Of course,that requires a single point of focus forapplications. Only the database is sharedunder the two-tier model. In order to reuseobject instances, you need to embed themin the serverand create a fat serveror move

Page 51: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

to a different architecture.

[1] I am talking specifically about reuse in thedevelopment workflows of a project. The mosteffective reuse occurs in the analysis and designworkflows.

As I mentioned before, in spite of itsshortcomings, a two-tier architecture does havea place in application development. In additionto applications tied directly to the database,simple applications with immediate deadlinesand no maintenance or reuse requirements areprime candidates. The following checklistprovides important questions to ask beforecommitting yourself to a two-tier design. If youcan answer "yes" to each of the questions in thechecklist, then a two-tier architecture is likelyyour best solution. Otherwise, you shouldconsider one of the other architectures supportedby the J2EE platform.

Does your application emphasize time-to-market over architecture?

Does your application use a singledatabase?

Is your database engine located on a singlehost?

Is your database likely to stayapproximately the same size over time?

Page 52: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Is your user base likely to stayapproximately the same size over time?

Is there no web interface to yourapplication?

Are your requirements fixed with little or nopossibility of change?

Do you expect minimal maintenance afteryou deliver the application?

1.1.2.2 The simple web sitearchitecture

Perhaps the simplest and mostfamiliararchitecture to Internet developers isthat of the simple web site. Figure 1-3 showsthe simple web site architecture with a pagegeneration technology like JSPs (JavaServerPages) or servlets talking directly to a databaseengine. In short, this is the web equivalent tothe client/server architecture. Its criticaldifference is that an intermediate tier isstructuring the data for display and providing itto the client.

Figure 1-3. The simple web sitearchitecture

Page 53: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In general, all of the faults of the client/serverarchitecture apply to this architecture. It does,however, provide some flexibility on the displayside. You can use the web server as the locationfor your shared object access. Unfortunately, youcannot access the objects directly; you mustaccess them through the display informationprovided by the web server. The advantage thisarchitecture has over the pure client/serverarchitecture is that you can now provide multipleviews of the same object instances.Unfortunately, these views must be browser-based and have roughly the same content.

1.1.2.3 Peer-to-peer

Peer-to-peer (P2P) is a new name for an oldarchitecture. Every other architecture presentedin this book seeks to break processing down intospecialized tiers that handle one kind ofapplication processing. The peer-to-peerarchitecture still has physical divisions amongdifferent kinds of logic, but it hides thosedivisions behind an egalitarian logical façade.Under the P2P architecture, all logical players

Page 54: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

can perform all tasks.

Figure 1-4 shows how the P2P architecturedivides the network into equal nodes. Each nodeis capable of making direct contact with anyother node and requesting services from thatnode. Similarly, each node is capable ofproviding services to any other node.

Figure 1-4. The logical view of theP2P architecture

Within a P2P node, the system can beperforming any number of tasks. One of thebeauties of the P2P architecture is that the

Page 55: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

details of how a given node is providing itsservices are completely hidden from the othernodes. You could, for example, implement a P2Pauction network in which one node consisted of adatabase server and a GUI and another nodeconsisted of flat files and a command-line utility.

Another advantage of a P2P architecture is thatthere's no single point of failure. Assuming theproblem domain is appropriate to P2P, the failureof any one node or even a large group ofnodes doesn't affect the functionality of thesystem built on top of the architecture. Theremaining nodes simply seek services from oneanother.

In reality, the development of a scalable P2Psystem is quite a challenge. No one has trulygotten this right yet. Pure P2P networks likeGnutella suffer from serious scalability issuesand an inability of many nodes to actuallyrequest services from other nodes. Other P2Psystems like the infamous Napster compromiseon the P2P architecture and thus compromise onits advantages. Napster created a single point offailure for the network and thus ceased to existin a meaningful sense when that point of failurewas shut down.

You should consider a P2P architecture under thefollowing conditions:

You need massive failover capabilities.

Page 56: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Replication of services to all nodes ispractical.

The source of services is not important i.e.,no security or trust issues exist.

1.1.2.4 Distributed architectures

Logic in distributed architectures is dividedamong any number of specialized tiers forhandling that data. The number of tiers runs wellbeyond the extra tier demanded by client/serverfor business logic. Distributed architecturesinclude tiers for business logic, content services,and everything else you can imagine.

Like the P2P architecture, distributedarchitectures are logical in that they provide fora high-level division of labor among thefollowing tiers:

User interface layer

The user interface (UI) layer is responsiblefor all direct user interaction. A physicalimplementation of the UI layer could consistof a web browser or be a combination ofbrowser, command-line, and Swingapplications.

Page 57: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Content generation layer

The content generation layer is responsiblefor structuring content for display to the UIlayer and subsequently routing user input.It is generally a web server or cluster ofweb servers using static and dynamiccontent generation tools to pull contentfrom a content management layer.

Content management layer

The content management layer storescontent from structuring and transmissionto a UI. It includes content managementsystems and digital asset managementsystems.

Web services layer

Whereas the content generation layerserves content to human users, the webservices layer serves it to otherapplications. It is the integration point formodern applications across a LAN (LocalArea Network). It exchanges messages withweb services clients using open standardslike XML (Extensible Markup Language).

Page 58: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Business logic layer

Business objects in the business logic layerexecute business logic on behalf of webservices and users. It serves as a sharedpoint for all business logic within anorganization.

Integration services layer

The integration services layer ties modernapplications to their legacy counterpartsthrough tools like enterprise messagingservices and proprietary APIs.

Data storage

This layer is where the database sits. In areal enterprise, the data storage layerconsists of many different databasesserving up various kinds of data.

Figure 1-5 shows an architecture for distributedapplications.

Figure 1-5. An architecture fordistributed Internet applications

Page 59: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

When you are writing EJB (Enterprise JavaBeans)applications, you're using a distributedarchitecture. How many of the layers you usedepends on the needs of your application.Regardless of how many layers you use, thisarchitecture is definitely the most complexarchitecture covered in this book. Unlike the P2Parchitecture, no level of generality hides thephysical services behind each layer. Thebusiness logic layer seeking data storageservices knows what kind of data storageservices it seeks.

Though a distributed architecture provides manyadvantages over other architectures, it is notwithout its drawbacks. I have already mentionedthe complexity it adds to a system. It is alsohard to find system architects proficient in alllayers of a distributed application architecture.

Page 60: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Though the J2EE platform attempts to mitigatethese issues, it does not mitigate themcompletely.

1.1.3 Software Architecture

Software architecture describes the internaldesign of a software component. It identifies theclasses that make up the piece of software andwhat processes those classes support. Standardsoftware development methodologies provide fortwo common views of a software architecture: astatic view and a behavioral view. Figure 1-6 is aUML (Unified Modeling Language)[2] classdiagram that serves as the static view, andFigure 1-7 is a UML sequence diagram providingthe behavioral view.

[2] UML is the standard language in which architectscommunicate software design decisions.

Figure 1-6. A UML class diagram

Page 61: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 1-7. A UML sequencediagram

Page 62: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In designing an application, you need to pick outdesign patterns that will provide a level ofreliability to its underlying logic. The first step toidentifying the design patterns is identifyingproblems in generic terms. In databaseprogramming, you need design patterns tosupport persistence and encapsulation ofbusiness logic.

Over the course of this book, we will encounter

Page 63: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

many different design patterns. In this section,my goal is simply to provide an overview ofthese patterns. If you do not fully understandthem after this section, you should not beconcerned. I will be talking in more detail abouteach of them later.

BEST PRACTICE: Leverage design patternswhen your problem matches an establishedpattern.

1.1.3.1 User interface patterns

The UI provides a view of the system specific tothe role of the user in question. Good UIpatterns help keep the user interface decoupledfrom the server. Though to some degree UIpatterns depend on the UI technology, there arealso some generic patterns like the model-view-controller pattern that serve any form of UI.

1.1.3.1.1 The model-view-controller pattern.

Java Swing is based entirely on a very importantUI pattern called the model-view-controllerpattern (MVC). In fact, this key design pattern iswhat makes Java so perfect for distributed

Page 64: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

enterprise development. The MVC patternseparates a GUI component's visual display (theview) from the thing it is a view of (the model)and the way in which the user interacts with thecomponent (the controller).

In a client/server application that displays therows from a database table in a Swing display,for example, the database serves as the model.In this application, the columns and rows of theSwing table match the columns and rows of thedatabase table. The Swing table is the view. Thecontroller is a less obvious object that handlesuser mouse clicks and key presses anddetermines what the model or view should do inresponse to those user actions.

Swing actually uses a variant of this patterncalled the model-delegate pattern. The model-delegate pattern combines the view and thecontroller into a single object that delegates toits model.

BEST PRACTICE: Use the MVC paradigm or avariation on the MVC paradigm in allapplications w ith user interface needs.

The MVC pattern is not limited to Swingapplications. It is also the preferred way ofbuilding the HTML (Hypertext Markup Language)pages for web applications. Figure 1-8 illustratesthe MVC pattern in a JSP-based web application.

Page 65: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In this case, the JSP page is the view, theservlet the controller, and the EJB or JavaBeanthe model.

Figure 1-8. The MVC pattern in aJSP application

1.1.3.1.2 The listener pattern.

For the Swing example of MVC, it would be niceif the view could be told about any changes tothe model. The listener pattern provides amechanism by which interested parties arenotified of events in other objects. You haveprobably seen this pattern in Swing developmentas well.

The listener pattern enables one object to listento specific events that occur to another object. A

Page 66: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

common listener in the JavaBeans componentmodel is something called aPropertyChangeListener. One object can declareitself a PropertyChangeListener by implementing thejava.beans.PropertyChangeListener interface. It thentells other objects that it is interested inproperty changes by calling theaddPropertyChangeListener( ) method in anyJavaBean it cares about. The important part ofthis pattern is that the object being listened toneeds to know nothing about its listeners exceptthat those objects want to know when a propertyhas changed. Consequently, you can designobjects that live well beyond the uses originallyintended for them.

1.1.3.2 Business patterns

As a general rule, the midtier business logic islikely to use just about every design pattern incommon use. The two most common generalpatterns I have encountered are the compositeand factory patterns. More important to thebusiness logic, however, is the componentmodel.

The component model defines the standards yourely on for encapsulating your application logic.Java has two major component models:JavaBeans and Enterprise JavaBeans. JavaBeansdefines a contract between applications andtheir components that tells applications how to

Page 67: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

find out what attributes are supported by acomponent and how to trigger that component'sbehavior. Enterprise JavaBeans takes the basiccontract of JavaBeans into the realm ofdistributed computing. EJB provides forcommunication among components across anetwork, the ability to search for components,and the ability to include components intransactions.

1.1.3.2.1 The composite pattern.

The composite pattern appears everywhere inthe real world. It represents a hierarchy in whichsome type of object may both be contained bysimilar objects and contain similar objects.Figure 1-9 shows a UML diagram describing thecomposite pattern.

Figure 1-9. A class diagram of thecomposite pattern

Page 68: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Look carefully for thecomposite pattern in the problems you aremodeling. It appears everywhere in problemdomains.

To put a more concrete face on the compositepattern, think of a virtual reality game thatattempts to model your movements through amaze. In your game, you might have a Roomclass that can contain Item objects. Some ofthose Item objects (like a bag) can contain otherItem objects. Your room is a container, and bagsare containers. On the other hand, things likemoney and stones cannot contain anything. Tocomplicate matters further, the room cannot becontained by anything greater than it. The resultis the class diagram in Figure 1-10.

Figure 1-10. The compositepattern in practice

Page 69: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.1.3.2.2 The factory pattern.

Another common pattern found in the core Javalibraries is the factory pattern. The patternencapsulates the creation of objects behind asingle interface. Java internationalizationsupport is peppered with implementations of thefactory design pattern. The java.util.ResourceBundleclass, for example, contains logic that enablesyou to find a bundle of resources for a specificlocale without having to know which subclass ofResourceBundle is the right one to instantiate. AResourceBundle is an object that might containtranslations of error messages, menu itemlabels, and text labels for your application. Byusing a ResourceBundle, you can create anapplication that will appear in French to French

Page 70: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

users, in German to German users, and inEnglish to English and American users.

Because of the factory pattern, using aResourceBundle is quite easy. To create a Savebutton, for example, you might have thefollowing code:

ResourceBundle bundle = ResourceBundle.getBundle("labels", Locale.getDefault( ));Button button = new Button(bundle.getString("SAVE");

This code actually shows two factory methods:Locale.getDefault( ) and ResourceBundle.getBundle( ).Locale.getDefault( ) constructs a Locale instancerepresenting the locale in which the applicationis running.

The goal of this pattern is to capture thecreation logic of certain objects in a singlemethod. The benefit of providing a singlelocation for that logic is that the logic can varywithout impacting applications that rely on thoseclasses. Sun Microsystems, for example, couldchange the getBundle( ) method to look for XML-based property bundles as well as traditionalJava property bundles without any impact to themasses of legacy Java systems.

1.1.3.3 Persistence patterns

One key to smooth development in a distributed

Page 71: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

architecture is providing a clear division betweendata storage code and business logic code. Atsome point, a business object needs to saveitself to a data store. You will chose apersistence model that supports the persistenceof your business components. The goal is tomake sure that the business object knowsnothing about how it is stored in the database infact, it should not even know that its persistenceform is a database.

The form of your persistence model willdetermine the underlying pattern you use. Laterin the book, we will get into a custompersistence model based on the data accessobject pattern.

1.1.3.3.1 The data access objectpattern.

The data access object pattern also referred to asthe persistence delegate pattern relies on adelegate to make a component persistent. Eachbusiness component sees generic methods in itsdelegate for persistence operations like loading,creating, saving, and deleting the component.Behind those methods are implementations for aspecific data storage technology and schema. Inour case, the data storage technology is arelational database.

Page 72: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Use the data access objectpattern in your database applications. It is akey aspect of most of the chapters in thisbook. I describe it in greater detail in Chapter4.

1.1.3.3.2 The memento pattern.

In the persistence delegate pattern, how doesthe persistence delegate know about the stateof the object it is persisting? You could pass theobject to the persistence methods, but thataction requires your delegate to know a lot moreabout the objects it supports that you probablywant. Another design pattern the mementopattern comes to the rescue here.

A memento is a tool for capturing an object'sstate and safely passing it around. Theadvantage of the memento pattern is that itenables you to modify the components and thedelegates independently. A change to thecomponent has no effect on the delegate and achange to the delegate has no effect on thecomponent. The persistence handler knows onlyhow to get the data it needs to support theunderlying data storage schema from thememento. I provide a concrete implementationof the memento pattern later in the book.

Page 73: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.2 Component Models

We have already touched a bit on componentmodels. A component model defines the variousaspects of encapsulating business logic insoftware. The Java platform provides two majorcomponent models:

The JavaBeans component model

The Enterprise JavaBeans component model

Enterprise JavaBeans work well only indistributed architectures and the P2Parchitecture. JavaBeans, on the other hand, workin any architecture. If you use JavaBeans in adistributed architecture, however, you will haveto write your own logic to support interprocesscommunication, security, transactionmanagement, and other functionality that comesfree with EJBs.

1.2.1 JavaBeans

The JavaBeans specification defines the way in

Page 74: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

which you should write your components so theycan be used by other components andapplication elements. When you writeJavaBeans, applications that know nothing aboutthose beans can still use them. One example ofJavaBeans in action is the development of JSPtag libraries. Your tag handlers are JavaBeanscomponents. A JSP container can access theproperties in your tag library because the way inwhich you write those properties uses standardgetter and setter methods defined by theJavaBeans specification.

The beauty of the JavaBeans specification is itssimplicity. To conform to it, you need only writeyour getters and setters using standard getXXX( )and setXXX( ) method calls. You can optionallyimplement listener support to enableapplications to listen for changes in properties.There is really nothing much more to thecomponent model.

Just as simplicity is JavaBeans advantage, it isalso its disadvantage. The JavaBeansspecification does not provide for many of thefollowing pieces necessary in distributedarchitectures:

Page 75: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Transaction support

Transaction support enables yourcomponents to put in database transactionswithout requiring a programmer to worryabout when to start and end thetransaction. If you want transaction supportwith JavaBeans, you need to write your owntransaction logic.

Distributed access

Distributed access provides direct access toyour component through some distributedcomponent model RMI, CORBA, EJB, DCOM,etc. Because JavaBeans is not a distributedcomponent model, you have to manuallycombine your JavaBeans with anothercomponent model generally, RMI forexporting components.

Security

If you make your components available overa network, you need a mechanism for

Page 76: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

securing them against unauthorized access.If you are using JavaBeans, you will have towrite your own code to authenticate clientsand authorize their component access.

Persistence management

Persistence management automaticallymaps your components to a data store. Inother words, with a component model thatprovides persistence management, younever have to write any JDBC code.JavaBeans, however, requires you tobecome quite familiar with JDBC in order tosave the state of the beans to a relationaldatabase.

Searching

Searching enables applications to search forthe components they need. Again, if you areusing JavaBeans, you will have to write yourown search methods and leverage JDBCqueries to support component searching.

Page 77: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.2.2 Enterprise JavaBeans

The Enterprise JavaBeans component model isbasically a component model for distributedarchitectures. It provides many of the featureslacking in JavaBeans at the cost of JavaBeanssimplicity. Because the EJB component modelhandles all of these aspects of distributedcomponent management, you can literally pickand choose the best-designed businesscomponents from different vendors and makethem work and play well with one another in thesame environment. EJB is now the standardcomponent model for capturing distributedcomponents on the Java platform. It hides fromyou the details you would have had to worryabout with JavaBeans.

One of the benefits of the EJB approach is that itseparates different application developmentroles into distinct parts so that the outputs ofone role are usable in different environments bythe players of the other roles. You can use yourEJB container, for example, to house componentswritten by third-party vendors or custom writtenby your team. Similarly, a JDBC service providercan deploy their JDBC drivers in any EJBcontainer without impacting transaction

Page 78: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

management.

Figure 1-11 illustrates what it takes to code asingle component under the EJB componentmodel. You have the actual bean, the homeinterface, and a remote interface. When youdeploy a bean in a container, the containercreates implementations of your home andremote interfaces. Contrast all of this work withthe simplicity of the JavaBeans componentmodel. Not only do you write just one class, butwhat you see is what you get nothing fancyhappens out of your view.

Figure 1-11. The EJB componentmodel

Page 79: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1.3 Persistence Models

A persistence model dictates how yourcomponents persist themselves to a data store.The EJB component model, for example, comeswith a built-in persistence model in the form ofcontainer-managed persistence. When you usethe container-managed persistence model withEnterprise JavaBeans, you do not have to write aline of database access code. Instead, youspecify a database mapping when you deploy theapplication through deployment configurationfiles. The EJB container manages the rest.

Other persistence models may perform all or partof the work necessary to implement componentpersistence. Over the course of this book, wewill examine the most popular persistencemodels for both the JavaBeans and EJBcomponent models.

1.3.1 EJB Persistence

Until recently, container-managed persistence inEJB has proven to be insufficient for mostapplication development. Most EJB developers

Page 80: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

write their own persistence logic for their beans apractice called bean-managed persistence. Bean-managed EJB programmers use some otherpersistence model when constructing theircomponents. The full gamut of EJB-specificpersistence models include:

EJB 1.x CMP

This model is container-managedpersistence (CMP) under the EJB 1.xspecification. As I noted earlier, few peopleactually use this persistence model. It hasdifficulties with such basic persistenceoperations as searching and primary keymanagement. It also does not provide asolid mapping of many-to-manyrelationships.

BMP

Bean-managed persistence (BMP) is notitself a persistence model. It instead meansthat you are using some non-EJBpersistence model for storage of your EJBcomponents.

Page 81: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

EJB 2.x CMP

Because of the massive shortcomings of EJB1.x CMP, EJB 2.0 introduced a newcontainer-managed persistence model.Though it is not yet widely supported, itdoes promise to address the shortcomingsof EJB 1.x CMP. To meet this challenge,however, it introduces a new querylanguage. Because many alternativepersistence models have evolved, it isunclear if EJB 2.x CMP will be accepted.

1.3.2 Other Persistence Models

Many persistence models have evolved both toaddress shortcomings in EJB persistence modelsand to support the persistence of non-EJBsystems. If you have read my book DatabaseProgramming with JDBC and Java, then you haveseen one such alternative persistence model.Among today's most popular alternatives is JavaData Objects (JDO). We will examine JDO andmy custom persistence model as well as severalothers over the course of this book.

Page 82: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

others over the course of this book.

Page 83: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 84: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 2. Relational DataArchitecture

Good sense is the most evenly shared thingin the world, for each of us thinks that he isso well endowed with it that even thosewho are the hardest to please in all otherrespects are not in the habit of wantingmore than they have. I t is unlikely thateveryone is mistaken in this. I t indicatesrather that the capacity to judge correctlyand to distinguish true from false, which isproperly what one calls common sense orreason, is naturally equal in all men, andconsequently the diversity in our opinionsdoes not spring from some of us being moreable to reason than others, but only fromour conducting our thoughts along differentlines and not examining the same things.

René Descartes Discourse on the Method

Database programming begins with thedatabase. A well-performing, scalable databaseapplication depends heavily on proper databasedesign. Just about every time I haveencountered a problematic database application,

Page 85: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

a large part of the problem sat in the underlyingdata model. Before you worry too much aboutwriting Java code, it is important to lay theproper foundation for that Java code in thedatabase.

Relational data architecture is the discipline ofstructuring databases to serve application needswhile remaining scalable to future demands andusage patterns. It is a complex discipline wellbeyond the scope of any single chapter. We willfocus instead on the core data architectureneeds of Java applications from basic datanormalization to object-relational mapping.

Though knowledge of SQL (Structured QueryLanguage) is not a requirement for this chapter,I use it to illustrate some concepts. I provide aSQL tutorial in the tutorial section of the bookshould you want to dive into SQL now. You willdefinitely need it as we get further intodatabase programming.

Page 86: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.1 Relational Concepts

Before we approach the details of relational dataarchitecture, it helps to establish a baseunderstanding of relational concepts. If you arean experienced database programmer, you willprobably want to move on to the next section onnormalization. In this section, we will review thekey concepts behind relational databases criticalto an in-depth understanding of relational dataarchitecture.

Page 87: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 88: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Databases and Database EnginesDevelopers new to database programming often runinto problems understanding just what a database is. Insome contexts, it represents a collection of data like themusic library. In other contexts, however, it may refer tothe software that supports that collection, a processinstance of the software, or even the server machine onwhich the process is running.

Technically speaking, a database is really the collectionof related data and the relationships supporting thedata. The database software a.k.a the databasemanagement system (DBMS)is the software, such asOracle, Sybase, MySQL, and DB2, that is used to storethat data. A database engine, in turn, is a processinstance of the software accessing your database.Finally, the database server is the computer on whichthe database engine is running.

In the industry, this distinction is often understood fromcontext. I w ill therefore continue to use the term"database" interchangeably to refer to any of thesedefinitions. It is important, however, to databaseprogramming to understand this breakdown.

2.1.1 The Relational Model

A database is any collection of related data. Thefiles on your hard drive and the piles of paper onyour desk all count as databases. Whatdistinguishes a relational database from other

Page 89: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

kinds of databases is the mechanism by whichthe database is organized the way the data ismodeled. A relational database is a collection ofdata organized in accordance with the relationalmodel to suit a specific purpose.

Relational principles are based on themathematical concepts developed by Dr. E. F.Codd that dictate how data can be structured todefine data relationships in an efficient manner.The focus of the relational model is thus thedata relationships. In short, by organizing yourdata according to the relational model asopposed to the hierarchical principles of yourfilesystem or the random mess of your desktop,you can find your data at a later date mucheasier than you would have had you stored itsome other way.

A relationship in relational parlance is a tablewith columns and rows.[1] A row in the databaserepresents an instance of the relation.Conceptually, you can picture a table as aspreadsheet. Rows in the spreadsheet areanalogous to rows in a table, and thespreadsheet columns are analogous to tableattributes. The job of the relational dataarchitect is to fit the data for a specific problemdomain into this relational model.

Page 90: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[1] You w ill sometimes see a row referred to as atuple especially in more theoretical discussions of relationaltheory. Columns are often referred to as attributes orfields.

Page 91: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 92: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Other Data ModelsThe relational model is not the only data model. Prior tothe w idespread acceptance of the relational model, twoother models ruled data storage:

The hierarchical model

The network model

Though systems still exist based on these models, theyare not nearly as common as they once were. Adirectory service like ActiveDirectory or OpenLDAP iswhere you are most likely to engage in new hierarchicaldevelopment.

Another modelthe object modelis slow ly coming intofavor for limited problem domains. As its name implies, itis a data model based on object-oriented concepts.Because Java is an object-oriented programminglanguage, it actually maps best to the object model.However, it is not as w idespread as the relational modeland is definitely not proven to support systems on thescale of the relational model.

2.1.2 Entities

The relational model is one of many ways ofmodeling data from the real world. The modelingprocess starts with the identification of thethings in the real world that you are modeling.These real world things are called entities. If youwere creating a database to catalog your musiclibrary, the entities would be things like compactdisc, song, band, record label, and so on.Entities do not need to be tangible things; theycan also be conceptual things like a genre or aconcert.

Page 93: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Capture the "things" inyour problem domain as relational entities.

An entity is described by its attributes. Back tothe example of a music library, a compact dischas attributes like its title and the year in whichit was made. The individual values behind eachattribute are what the database engine stores.Each row describes a distinct instance of theentity. A given instance can have only a singlevalue for each attribute.

Table 2-1 describes the attributes for a CD entityand lists instances of that entity.

Table 2-1. A list of compact discs in a musiclibrary

Artist Title Category Year

The Cure Pornography Alternative 1983

Garbage Garbage Grunge 1995

Hole Live Through This Grunge 1994

The MightyLemon Drops World Without End Alternative 1988

Nine Inch Nails The Downward Spiral Industrial 1994

Public ImageLimited Compact Disc Alternative 1986

Ramones Mania Punk 1988

Page 94: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The Sex Pistols Never Mind the Bollocks, Here'sthe Sex Pistols Punk 1977

Skinny Puppy Last Rights Industrial 1992

Wire A Bell Is a Cup Until It IsStruck Alternative 1989

You could, of course, store this entire list in aspreadsheet. If you wanted to find data basedon complex criteria, however, the spreadsheetwould present problems. If, for example, youwere having a "Johnny Rotten Night" partyfeaturing music from the punk rocker, how wouldyou create this list? You would probably gothrough each row in the spreadsheet andhighlight the compact discs from Johnny Rotten'sbands.

Using the data in Table 2-1, you would have tohope that you had in mind an accuraterecollection of which bands he belonged to. Toavoid taxing your memory, you could createanother spreadsheet listing bands and theirmembers. Of course, you would then have tometiculously check each band in the CDspreadsheet against its member information inthe spreadsheet of musicians.

2.1.3 Constraints

What constitutes identity for a compact disc? Inother words, when you look at a list of compactdiscs, how do you know that two items in the

Page 95: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

discs, how do you know that two items in thelist are actually the same compact disc? On theface of it, the disc title seems as if it might be agood candidate. Unfortunately, different bandscan have albums with the same title. In fact,you probably use a combination of the artistname and disc title to distinguish amongdifferent discs.

The artist and title in our CD entity areconsidered identifying attributes because theyidentify individual CD instances. In creating thetable to support the CD entity, you tell thedatabase about the identifying attributes byplacing a constraint on the database in the formof a unique index or primary key. Constraints arelimitations you place on your data that areenforced by the DBMS. In the case of uniqueindexes (primary keys are a special kind ofunique index), the DBMS will prevent theinsertion of two rows with the same values forthe entity's identifying attributes. The DBMSwould prevent, for example, the insertion ofanother row with values of 'Ramones' and 'Mania'for the artist and title values in a CD table havingartist and title as a unique index. It won't matterif the values for all of the other columns differ.

BEST PRACTICE: Use constraints to helpenforce the data integrity of your system.

Constraints like unique indexes help the DBMShelp you maintain the overall data integrity ofyour database. Another kind of constraint isformally known as an attribute domain. Youprobably know the domain as its data type.

Page 96: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Choosing data types and indexes along with theprocess of normalization are the most criticaldesign decisions in relational data architecture.

2.1.3.1 Indexes

An index is a constraint that tells the DBMSabout how you wish to search for instances of anentity. The relational model provides for threemain kinds of indexes:

Index

An index in the generic sense is a simpletool that tells the DBMS what kind ofsearches you intend to perform. W ith thisinformation, the DBMS can organizeinformation to make the searches goquickly. A very crude way to think of anindex is as a Java HashMap in which the keyis your index attribute and the values arearrays of matching rows.

Unique index

A unique index is an index whose values areguaranteed to be unique. In other words,instead of an array of matching rows, thisindex is like a HashMap that returns a singlevalue for its key. The index created earlierfor the artist and title columns in the CD table

Page 97: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

is an example of a unique index.

Primary key

A primary key is a special unique index thatacts as the main identifier for the row. Atable can have any number of uniqueindexes, but it can have only one primarykey.

We can examine the impact of indexes bycreating the CD entity as a table in a MySQLdatabase and using a special SQL commandcalled the EXPLAIN command. The SQL to createthe CD table looks like this:

CREATE TABLE CD ( artist VARCHAR(50) NOT NULL, title VARCHAR(100) NOT NULL, category VARCHAR(20), year INT);

The EXPLAIN command tells you what thedatabase will do when trying to run a query. Inthis case, we want to look at what happenswhen we are looking for a specific compact disc:

mysql> EXPLAIN SELECT * FROM CD -> WHERE artist = 'The Cure' AND title = 'Pornography';+-------+------+---------------+------+---------+------+------+------------+| table | type | possible_keys | key | key_len | ref | rows | Extra |+-------+------+---------------+------+---------+------+------+------------+| CD | ALL | NULL | NULL | NULL | NULL | 10 | where used |+-------+------+---------------+------+---------+------+------+------------+

Page 98: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1 row in set (0.00 sec)

The important information in this output for nowis to look at the number of rows. Given the datain Table 2-1, we have 10 rows in the table. Theresults of this command tell us that MySQL willhave to examine all 10 rows in the table tocomplete this query. If we add a unique index,however, things look much better:

mysql> ALTER TABLE CD ADD UNIQUE INDEX ( artist, title );Query OK, 10 rows affected (0.20 sec)Records: 10 Duplicates: 0 Warnings: 0mysql> EXPLAIN SELECT * FROM CD -> WHERE artist = 'The Cure' AND title = 'Pornography';+-------+-------+---------------+--------+---------+-------------+------+| table | type | possible_keys | key | key_len | ref | rows |+-------+-------+---------------+--------+---------+-------------+------+| CD | const | artist | artist | 150 | const,const | 1 |+-------+-------+---------------+--------+---------+-------------+------+1 row in set (0.00 sec)mysql>

The same query can now be executed simply byexamining a single row.

BEST PRACTICE: Make indexes for attributesyou intend to search against.

Unfortunately, the artist and title probably makea poor unique index. First of all, there is noguarantee that a band will actually choosedistinct names for its albums. Worse, in somecircumstances, bands have chosen to have thesame album carry different names. Public Image

Page 99: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Limited's Compact Disc is an example of such analbum. The cassette version of the album iscalled Cassette.

Even if artist and title were solid identifyingattributes, they still make for a poor primarykey. A primary key must meet the followingrequirements:

It can never be NULL.

It must be unique across all entityinstances.

The primary key value must be known whenthe instance is created.

In addition to these requirements, good primarykeys have the following characteristics:

The primary key should never change value.

The primary key attributes should have nomeaning except to uniquely identify theentity instance.

It is very common for people to find attributesinherent in an entity and chose one or more ofthose identifying attributes as a primary key.Perhaps the best example of this practice is theuse of an email address as a primary key. Emailaddresses, however, can and do change. Achange to a primary key attribute can cause aninstance to become inaccessible to anyone withold information about the instance. In plain

Page 100: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

English, it can break your application.

Another example of a common primary key withmeaning is a U.S. Social Security number. It issupposed to be unique. It is never supposed tochange. You, however, have no control over itsuniqueness or whether it changes. As it turnsout, sometimes the uniqueness of Social Securitynumbers is violated. In addition, they dosometimes change. Furthermore, in many cases,the law restricts your ability to share thisinformation. It is therefore best to choose aprimary key with no external meaning; you willcontrol exactly how it is used and have the fullpower to enforce its uniqueness andimmutability.

BEST PRACTICE: Never use meaningfulattributes or attributes whose values canchange as primary keys.

The solution is to create a new attribute to serveas the primary identifier for instances of anentity. For the CD table, we will call this newattribute the cdID. The SQL to create the tablethen looks like this:

CREATE TABLE CD ( cdID INT NOT NULL, artist VARCHAR(50) NOT NULL, title VARCHAR(100) NOT NULL, category VARCHAR(20), year INT, PRIMARY KEY ( cdID ), INDEX ( artist, title ),

Page 101: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

INDEX ( category ), INDEX ( year ));

You may have noted that my naming styledoes not redundantly name columns like titlecdTitle. Yet I chose to name the primary keyfor the CD table cdID instead of id. This choicebasically makes the use of data modelingtools a lot simpler. In short, data modelingtools look for natural joins joins between twotables when the common columns share thesame name, data type, and value. I discussnatural joins in more detail in Chapter 10.

BEST PRACTICE: Include the table name inthe primary key name to assist data modelingtools.

Ideally, you always search on unique indexes. Inthe real world, however, you will select onattributes like the year or genre that are notunique. You can still help the database organizethe underlying data storage by creating plainindexes. In general, you want any attribute youcommonly search on to be indexed. An indexdoes, however, come with some downsides:

Indexes are stored apart from the tabledata. Every index thus adds to the diskspace requirements of the database.

Every change to the table requires every

Page 102: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

index to be updated to reflect the changes.

In other words, if you have a table on which youperform a significant number of write operations,you want to minimize your indexes to thoseattributes that appear frequently in queries.

Finally, as you have already seen, you can haveindexes including primary keys that are formed outof any number of identifying columns so long asthose columns together sufficiently identify asingle entity instance. It is always a good idea,however, to build primary keys out of theminimal number of columns possible.

BEST PRACTICE: Use the smallest number ofcolumns possible in your primary keys.

2.1.3.2 Domains

The proper choice of data type is another criticalaspect of relational data architecture. Itconstrains the kind of data that can be stored fora given attribute. By creating an email attributeas a text value, you prevent people from storingnumbers in the field. A time-oriented domain likea SQL DATE enables you to perform timearithmetic on date values.

The domains that exist in a relational databasedepend on the DBMS of choice. Those thatsupport the SQL specification generally support acore set of data types. Just about every

Page 103: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database engine comes with its own, proprietarydata types. When modeling a system, youshould use SQL-standard data types.

Primary keys deserve special consideration whenyou are putting domain constraints on an entity.Because they are the primary mechanism forgetting access to an entity instance, it isimportant that the database is able to do quickmatches against primary key values. In general,numeric types form the best primary keys. Irecommend the use of 64-bit, sequentiallygenerated integers for primary key columns. Theonly exception is for lookup tables.

A lookup table is a small table with a known,finite set of data like a table containing a list ofstates or, with respect to the music libraryexample, a set of genres. In the case of lookuptables, they more often than not have codesagainst which you will do most lookups. Forexample, you will almost always retrieve thestate of Maine from a State table by itsabbreviation ME. It therefore makes more senseto use fixed character data types like SQL's CHARfor primary keys in lookup tables. The length ofthese fixed character values should be no morethan a few characters.

BEST PRACTICE: Use fixed character datatypes like CHAR for primary keys in lookuptables.

The data types for other kinds of attributes varywith the diversity in the kinds of data you will

Page 104: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

want to store in your databases. These days,many databases even support the creation ofuser-defined data types. These pseudo-objectdata types prove particularly useful in thedevelopment of Java database applications.

2.1.4 Relationships

The creation of relationships among the entitiesin the database lies at its heart. Theserelationships enable you to easily answer thequestion, "On what compact discs in my librarydid Johnny Rotten play?" Unlike other models,the relational model does not create hard linksbetween two entities. In the hierarchical model,a hard relationship exists between a parententity and its child entities. The relationalmodel, on the other hand, creates relationshipsby matching a primary key attribute in one entityto a foreign key attribute in another entity.

The relational model supports three kinds ofentity relationships:

One-to-one

One-to-many

Many-to-many

W ith any of these relationships, one side of therelationship may be optional. An optionalrelationship allows the foreign key to containNULL values to indicate the relationship does not

Page 105: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

exist for that row.

2.1.4.1 One-to-one relationships

The one-to-one relationship is the most rarerelationship in the relational model. A one-to-one relationship says that for every instance ofentity A, there is a corresponding instance ofentity B. It is so rare that its appearance in adata model should be met with skepticism as itgenerally indicates a design flaw. You indicate aone-to-one relationship in the same way youindicate a one-to-many relationship.

BEST PRACTICE: Recheck your designwhenever you encounter one-to-onerelationships, as they are often indicators ofproblematic design choices.

2.1.4.2 One-to-many relationships

A one-to-many relationship means that for everyinstance of entity A, there can be multipleinstances of entity B. As Figure 2-1 shows, the"many" side of the relationship houses theforeign key that points to the primary key of the"one" side of the relationship.

Figure 2-1. A One-to-ManyRelationship

Page 106: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Table 2-2 lists data from a Song table whoserows are dependent on rows in the CD table.

Table 2-2. The Song entity with a foreign keyfrom the CD entity

Attribute Domain Notes NULL?

songID INT PRIMARY KEY No

cdID INT FOREIGN KEY No

t it le VARCHAR(100) No

length INT No

Under this design, one compact disc isassociated with many songs. The placement ofcdID into the Song table as a foreign keyindicates the dependency on a row of the CDtable. In databases that manage foreign keyconstraints, this dependency will prevent theinsertion of songs into the Song table that do notalready have a corresponding CD. Similarly, thedeletion of a disc will cause the deletion of itsassociated songs. You should note, however,that not all database engines support foreignkey constraints. Of those that do support them,

Page 107: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

you often have the option of turning them on oroff.

Why would you want foreign key constraintsoff? Many application environments particularlymultitier distributed object systems prefer tomanage dependencies in the object layerinstead of the database. It is generally atrade-off between a combination of speedwith object purity and guaranteed dataintegrity. When foreign key constraints arenot checked in the database, updates occurmore quickly. Furthermore, you do not end upwith a situation in which objects exist in themiddle tier that have been automaticallydeleted by the database. On the other hand,if your middle-tier logic is not sound, yourapplication can damage the data integrityw ithout proper foreign key constraints.

You now have a proper relationship betweencompact discs and their songs. To ask whichsongs are on a particular compact disc, you needto ask the Song table which songs have thedisc's cdID. Assuming you are looking for allsongs from the disc Garbage (cdID 2), the SQL tofind the songs looks like this:

SELECT songID, title FROM Song WHERE cdID = 2;

More powerfully, however, you can ask for allsongs from a compact disc by the disc title:

SELECT Song.songID, Song.titleFROM Song, CDWHERE CD.title = 'Last Rights'AND CD.cdID = Song.cdID;

Page 108: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The last part of the query where the cdID wascompared in both tables is called a join. A join iswhere the implicit relationship between twotables becomes explicit.

2.1.4.3 Many-to-manyrelationships

A many-to-many relationship allows an instanceof entity A to be associated with multipleinstances of entity B and an instance of entity Bto be associated with multiple instances ofentity A. These relationships require the creationof a special table to manage the relationship.You may hear these tables referred to by anynumber of names: composite entities, jointables, cross-reference tables, and so forth. Thisextra table creates the relationship by havingthe primary keys of each table in the relationshipas foreign keys. It then uses the combination offoreign keys as its own compound primary key.If, for example, we had an Artist table in ourmusic library, we indicate a many-to-manyrelationship between an Artist and a CD throughan ArtistCD join table. Table 2-3 shows thisspecial table.

Table 2-3. The ArtistCD table creates a many-to-many relationship between Artist and CD

Attribute Domain Notes NULL?

cdID INT FOREIGN KEY , PRIMARY KEY No

Page 109: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

art istID INT FOREIGN KEY , PRIMARY KEY No

You can now ask for all of the compact discs byGarbage:

SELECT CD.cdID, CD.titleFROM CD, ArtistCD, ArtistWHERE ArtistCD.cdID = CD.cdIDAND ArtistCD.artistID = Artist.artistIDAND Artist.name = 'Garbage';

BEST PRACTICE: Use join tables to modelmany-to-many relationships.

Another useful aspect of join tables is that youcan use them to contain information about arelationship. If, for example, you wanted to trackguest artists on albums, where would you storethat information? It really is not an attribute ofan artist or a compact disc. It is instead anattribute of the relationship between the twoentities. To capture this information, you wouldtherefore add a column to ArtistCD called guest.Finding which compact discs on which Stingappeared as a guest artist would then be assimple as:

SELECT CD.cdID, CD.titleFROM CD, ArtistCD, ArtistWHERE ArtistCD.cdID = CD.cdIDAND ArtistCD.artistID = Artist.artistIDAND Artist.name = 'Sting'AND ArtistCD.guest = 'Y';

Page 110: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.1.5 NULL

NULL is a special value in relational databasesthat indicates the absence of a value. If youhave a pet store site that gathers information onyour users, for example, you may track thenumber of pets your users have. W ithout theconcept of NULL, you have no proper way toindicate that you do not know how many pets auser has. Applications commonly resort tononsense values (like -1) or unlikely values (like9999) as a substitute for NULL.

BEST PRACTICE: Use NULL to representunknown or missing values.

Though the basic concept of NULL is prettystraightforward, beginning databaseprogrammers often have trouble figuring out howNULL works in database operations. A basicexample would come about by adding a newcolumn to our Song table that is a rating. It canbe NULL since it is unlikely anyone wants to rateevery single song in their library. The followingSQL may not do what you think:

SELECT songID, title FROM Song WHERE rating = NULL;

No matter what data is in your database, thisquery will always return zero rows. Relationallogic is not Boolean; it is three-value logic: true,false, and unknown. Most NULL comparisonstherefore result in NULL since a NULL comparisonis indeterminate under three-value logic. SQL

Page 111: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

provides special mechanisms to test for NULL inthe form of IS NULL and IS NOT NULL so that it ispossible to ask for the unrated songs:

SELECT songID, title FROM Song WHERE rating IS NULL;

Page 112: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.2 Modeling

Throughout this book, I will be using industry-standard diagrams to illustrate designs. A criticalpart of relational data architecture isunderstanding a special kind of diagram calledan entity relationship diagram, or ERD. An ERDgraphically captures the entities in your problemdomain and illustrates the relationships amongthem. Figure 2-2 is the ERD of the music librarydatabase.

Figure 2-2. The ERD for the musiclibrary

There are in fact several forms of ERDs. In the

Page 113: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

style I use in this book, each entity is indicatedby a box with the name of the entity at the top.A line separates the name of the entity from itsattributes inside the box. Primary key attributeshave "PK" after them, and foreign key attributeshave "FK" after them.

The lines between entities indicate arelationship. At each end of the relationship aresymbols that indicate what type of relationshipit is and whether it is optional or mandatory.Table 2-4 describes these symbols.

Table 2-4. Symbols for an ERD

Symbol Description

The many side of a mandatory one-to-many ormany-to-many relationship

The one side of a mandatory one-to-one or one-to-many relationship

The many side of an optional one-to-many or many-to-many relationship

The one side of an optional one-to-one or one-to-many relationship

Our ERD therefore says the following things:

Page 114: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

One compact disc contains one or moresongs.

One song appears on exactly one compactdisc.

One compact disc features one or moreartists.

One artist is featured on one or morecompact discs.

An artist can optionally be part of one ormore artists (bands).

This ERD is a logical representation of the musiclibrary. The entities in a logical model are nottables. First of all, you probably noticed there isno composite entity handling the relationshipbetween an artist and a compact disc I havedrawn the relation directly as a many-to-manyrelationship. Furthermore, all of the entitynames and attributes are in plain English.Finally, no foreign keys are shown.

BEST PRACTICE: Develop an ERD to modelyour problem before you create thedatabase.

Page 115: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The physical data model transforms the logicaldata model into the tables that will be createdin the working database. A data architect workswith the logical data model while DBAs(database administrators) and developers workwith the physical data model. You translate thelogical data model into a physical one by addingjoin tables, turning domains into database-specific data types, and using table and columnnames appropriate to your DBMS. Figure 2-3shows the physical data model for the musiclibrary as it would be created in MySQL.

Figure 2-3. The physical datamodel for the music library

Page 116: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 117: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.3 Normalization

When beginning the development of a dataarchitecture for a project, you first want tocapture all the entities in your problem domainand the attributes associated with thoseentities. Depending on your software engineeringprocesses, these entities may be driven by yourobject model or your object model may be drivenby the logical ERD. Either way, you should notinitially concern yourself in any way with issueslike performance, scalability, or flexibility thetask is to model the problem domain properly.

Unlike other areas of software architecture,relational data architecture provides a veryformal process for optimizing your model forefficient resource usage, scalability, andflexibility. This formal process is known asnormalization. Normalization seeks to achievethe following goals:

Remove redundant data

A fully normalized database repeats nothingother than foreign keys. Removal ofredundant data guarantees that you arestoring the minimum data necessary tomodel your domain and protects theintegrity of your data by requiring just a

Page 118: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

single point of maintenance for any piece ofinformation.

Protect the relational model

The process of normalization forces you toexamine all aspects of your data model tomake certain that you are not violating anyof the basic principles of the relationalmodel (e.g., all attributes must be single-valued; only the table name, column name,and primary key value should be needed toidentify a row; etc.).

Improve scalability and flexibility

A normalized database guarantees theability of the data model to evolve witheven the most drastic of changes in theproblem domain with a minimal impact onthe applications it supports.

As I noted earlier, normalization is a formalprocess. It defines very specific criteria for yourdata model that it breaks out into normal forms.The normal forms establish a stringent andobjective set of rules to which a data modelmust adhere. Each one builds on requirements ofthe previous, as is shown in Figure 2-4, andimproves upon the overall design of the model.

Page 119: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 2-4. The six normal formsbuild on top of one another

Before a data model can be said to be in acertain normal form, it must meet all of therequirements of that normal form and any lessernormal forms. The second normal form, forexample, necessitates that a data model meetthe requirements for both the first and secondnormal forms.

No matter what your problem domain, you willwant to normalize your data model at least tothe third normal form. For most simple problemdomains, the third normal form is good enough.Deeper normal forms represent specific datamodeling issues that do not apply to most datamodels. Most data models in the third normalform are therefore already in the fifth normalform. If you have a very complex system, youshould go ahead and verify that it is in at leastthe fourth normal form. Formally normalizing

Page 120: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

your data model to the fifth normal form shouldbe left for very specific problem domains. I willdive into the details of each of these normalforms later in the chapter.

BEST PRACTICE: Very complex systemsshould be normalized to the fourth normalform.

In addition to the six normal forms noted here, aseventh normal form called the domain/keynormal form (DKNF) exists. The rule for DKNF isthat every logical restriction on attribute valuesresults from the definition of keys and domains.In theory, a table in DKNF cannot containanomalies. If nothing about DKNF makes anysense to you, don't worry about it no processexists to prove a table is in DKNF and thereforeit is not used in real world modeling.

2.3.1 Before Normalization

Before you begin the process of normalization,you should already have a logical ERD describingyour problem domain. This logical ERD shoulddescribe all of the entities that make up theproblem domain, their major attributes, and theirrelationships. For the purposes of this section, Iwill be referring to a data model to support aweb site for film fans. It specifically storesinformation about films and enables people to

Page 121: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

browse the films in the database based on thatinformation. Figure 2-5 shows the data modelbefore normalization.

Figure 2-5. The raw film site datamodel

Because we want this web site to be accessibleto all North American visitors, it has translationsinto Spanish and French. These translations aresupported through a duplication of the logicaldata model into three separate physicaldatabases.

2.3.2 Basic Normalization

Basic normalization addresses the designdemands common to any relational database. As

Page 122: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

a data architect, you will always want to carryyour design through to the third normal form.

2.3.2.1 First normal form

A table is in the first normal form (1NF) when allattributes are single-valued. This requirement isnot simply a good design requirement; it is afundamental requirement of the relationalmodel. At its simplest, it means that only asingle value may exist at the intersection of acolumn and a row.

The film database has three different violationsof 1NF:

The productionCompanies attribute in the Filmtable is multivalued.

The genre1 and genre2 columns in effectrepresent a multivalued attribute.

The duplication of the database formultilingual content also represents turningall values into multivalue attributes.

The problem with the first violation is that itmakes the database very inflexible. For onething, searching for films by a specific productioncompany is difficult. You cannot use a simpleequality check like:

Page 123: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SELECT filmID, titleFROM FilmWHERE productionCompanies = 'Imaginary Productions';

That column, after all, contains a comma-separated list of companies. Instead, you need amuch less efficient query like:

SELECT filmID, titleFROM FilmWHERE productionCompanies LIKE '%Imaginary Productions%';

The solution to the problem of multivaluedattributes is to create a new entity to supportthat attribute. In the case of the film database,we should create a ProductionCompany table withforeign key references to the primary key in theFilm table. We now have a one-to-manyrelationship between films and their productioncompanies.

Another, less obvious multivalue attribute is thegenre support for films. Because of a need tosupport the classification of films like BlazingSaddles that fall into two genres, we have in ourdata model two genre columns. This approachhas several problems associated with it.

The problems are:

It limits the assignment of genres to filmsto two genres.

Page 124: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Searching for a film by genre becomes acomplex operation.

Space is wasted for any film with a singlegenre.

The solution, again, is the creation of a newentity to support the multiple values. In thiscase, we will create a lookup table for genresand a many-to-many relationship between Filmand Genre.

The final problem with the raw data model is thefact that the entire database is duplicated forevery language we want to support. In order toadd a new language, we need to create a newduplicate of that database and replace its textvalues with translations for the target language.The application then needs to be configured touse that database as a data source for the newlanguage.

For this problem, we need to create translationentities for each of the text attributes in thedatabase. Adding support for a new languagemeans nothing more than adding new rows toeach translation table.

Figure 2-6 contains the film database in 1NF.

Figure 2-6. The film database in1NF

Page 125: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.3.2.2 Second normal form

A table is in the second normal form (2NF) whenit is in 1NF and all non-key attributes arefunctionally dependent on the table's entireprimary key. Functional dependency means thatan attribute is determined by another attribute.In the case of filmID and title, the title isfunctionally dependent on the filmID becausewhich film the row represents determines whatits title is. On the other hand, the title of thefilm does not necessarily indicate which film youare dealing with.

Page 126: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

When an attribute is not dependent on theentire primary key of the table it is in, it haslikely been placed in the wrong table. Our datamodel has this problem in the reviewer attributeof the Film entity. The purpose of this attributeis to capture the name of the person whoinitially reviewed the film for the site. Thereviewer attribute, however, does not depend onthe filmIDthe reviewer exists independent of thefilm.

The existence of attributes that violate 2NFcauses database anomalies. A database anomalyis an error or inconsistency that occurs whensome event takes place. Specifically, there are:

Insertion anomalies

An insertion anomaly occurs when you areforced to know information about an entityinstance that may not yet be knowable inorder to create an instance of anotherentity. In the case of reviewer, a personcannot be a reviewer until he has revieweda film. More to the point, we cannot captureany information about our reviewers untilthey have reviewed a film.

Deletion anomalies

Page 127: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

A deletion anomaly occurs when a deletecauses data that is not related to theinstance being deleted to be removed fromthe database. In our existing model,removing a film may remove the reviewerfrom the database.

Update anomalies

An update anomaly occurs when the samedata must be changed in more than onelocation to preserve database integrity. If areviewer has a name change, our datamodel requires the change be made to eachfilm reviewed and every other place in thedatabase with that reviewer's name.

Again, the solution to this normalization problemis the creation of a new entity to remove thenondependent attribute. This entity, Reviewer,contains the name of the reviewer and is relatedto many films.

Figure 2-7 shows our data model in 2NF.

Figure 2-7. The film database in2NF

Page 128: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.3.2.3 Third normal form

A table is in the third normal form (3NF) when itis in 2NF and no transitive dependencies exist. Atransitive dependency occurs when a functionaldependency is inherited through some otheridentifying attribute. In our data model, theforChildren attribute depends on the ratingattribute, which in turn depends on the filmID.Because the forChildren attribute has no direct

Page 129: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

dependency on the filmID, it is thus transitivelydependent on the filmID.

Violation of 3NF causes database anomalies.First of all, if the MPAA changes which ratingsare suitable for children, you will need to updateevery instance of the Film entity to reflect thatchange. An insertion anomaly also exists in thatany new ratings for children will not be reflectedin existing films. Of course, the insertionanomaly is not a huge problem for this databasesince films rarely change ratings. Finally,deletion of the only row with a rating associatedwith being for children causes us to lose allinformation about it being for children.

BEST PRACTICE: Normalize your data modelminimally to the third normal form.

To fix this problem, you need to move thetransitively dependent value into a table thatprovides functional dependency. In other words,move the forChildren attribute into the Ratingtable as shown in Figure 2-8.

Figure 2-8. The film database in3NF

Page 130: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.3.3 Specialized Normalization

Having your database in 3NF is generally goodenough to guarantee your system is free of themost common anomalies. The other forms ofnormalization handle special situations. In fact,if your database is not subject to the specialconsiderations of Boyce-Codd normal form orfourth normal form, your database isautomatically in 4NF. The fifth normal form isimpossible to verify without computer-aided

Page 131: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

modeling tools and is rarely worth seeking.

2.3.3.1 Boyce-Codd normal form

A table is in Boyce-Codd normal form (BCNF)when every determinant is a candidate key. Acandidate key is a set of attributes that couldpotentially serve as a primary key. BCNF isessentially a more generalized form of 3NF. Itspecifically addresses issues that arise in tableswith one or more of the following characteristics:

Multiple candidate keys

Composite candidate keys

Overlapping candidate keys

Our data model contains no relations to whichBCNF applies. To illustrate BCNF, consider atable that contains three or more columns with acouple of the combinations capable of uniquelyidentifying a row. An example might be a Showingtable that represents when a real estate agentshows a house to a client. The table has thestructure shown in Table 2-5.

Table 2-5. The structure of a table meetingBCNF

Attribute Domain Notes NULL?

Page 132: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

propertyID BIGINT PRIMARY KEY , FOREIGN KEY No

agentID BIGINT PRIMARY KEY , FOREIGN KEY No

t imeslot INT PRIMARY KEY , FOREIGN KEY No

buyerID BIGINT FOREIGN KEY No

notes VARCHAR(255)

For the sake of this example, assume that abuyer gets only one chance to view a property.Furthermore, only one agent can show a propertyto one buyer in a given time slot. In that case, itis possible for notes to be determined by eitherof the following combinations:

propertyID, agentID, timeslot

propertyID, agentID, buyerID

You could choose either of the twocombinations. BCNF simply states that as longas every column that determines notes is acandidate key, the table is in BCNF.

2.3.3.2 Fourth normal form

A table is in the fourth normal form when it is in

Page 133: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BCNF and all multivalued dependencies are alsofunctional dependencies. The problem here withthe current model is the FilmReviewer table. Itties film reviewers with the films and genresthey review. Table 2-6 shows some sample datafrom the table.

Table 2-6. Data in FilmReviewer

filmID reviewerID genreCode

101 1 ACT

101 1 SCI

102 2 DRA

102 2 COM

103 1 ACT

103 1 SCI

The full set of columns forms the primary key forthis table. It is thus normalized to BCNF.Unfortunately, it still contains redundant data.The redundancy is caused by multivalueddependencies. Specifically, reviewerID determinesthe values of filmID and genreCode independently.In the relations we have seen so far, thedeterminant establishes the full set of valuesthat together form the instance.

Page 134: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

We can fix this problem by splitting genreCode'sdependence into one table and reviewerID'sdependence into another. For example, we cancreate a ReviewGenre table that captures thegenres the reviewer specializes in. We cansimilarly create a ReviewerFilm table that containsthe film reviews. Figure 2-9 shows the resultingdata model.

Figure 2-9. The film database in4NF

Page 135: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Spending time normalizing to the fourth normalform is useful only for data models that have alot of complex join tables. If you have just a fewsuch tables, you are probably already in 4NFanyway. If you are not, the anomaly is almostcertainly of no consequence to your system.

Page 136: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.3.3.3 Fifth normal form

A table is in the fifth normal form (5NF) if it is in4NF and cannot have lossless decomposition intoany number of smaller tables. It is actually veryhard to tell when a table is truly in 5NF justabout any table in 4NF is also in 5NF. It canoccur in situations in which you have a many-to-many-to-many relationship as exists with Film,Actor, and Role. Given certain data, the databasecan end up making claims that simply are nottrue.

For simplicity's sake, assume that the databasehas a single actor in it who has appeared in twoseparate films playing two separate roles. Thejoined information from these tables looks likethe data in Table 2-7.

Table 2-7. Joining actor, film, and role

actorID filmID roleName Description

1 101 Thepresident

Stanley Anderson (1) played thepresident in Armageddon (101).

1 102 EdwinSneller

Stanley Anderson (1) played EdwinSneller in The Pelican Brief (102).

So far, this structure should seem quite normalto you. The three entities have threecorresponding join tables ActorFilm, FilmRole, and

Page 137: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

ActorRole to help manage the relationships. Theproblem arises when you insert particular data,such as adding Robert Culp who also played thepresident, but in the movie The Pelican Brief. Inshort, we add one row to Actor, one row toActorFilm, one row to ActorRow, and one row toFilmRole. No rows are added to Role or Film. Thejoin suddenly ends up with both true claims andsome utterly false ones as Table 2-8 shows.

Table 2-8. The false claims (in italic) of adatabase not in 5NF

actorID filmID roleName Description

1 101 Thepresident

Stanley Anderson (1) played thepresident in Armageddon (101).

1 102 EdwinSneller

Stanley Anderson (1) played EdwinSneller in The Pelican Brief (102).

2 102 Thepresident

Robert Culp (2) played the presidentin The Pelican Brief (102).

1 102 Thepresident

Stanley Anderson (1) played thepresident in The Pelican Brief (102).

2 101 Thepresident

Robert Culp (2) played the president inArmageddon (101).

The important thing to note about the databaseis that there is nothing wrong with the data inthe tables. The only thing wrong is what the

Page 138: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

relationships among the tables imply given avery specific data set.

By now, you have probably guessed that thesolution is to create another entity to managethis trinary relationship. The Appearance table inthe fully normalized Figure 2-10 manages thissolution.

Figure 2-10. The film database in5NF

Page 139: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 140: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.4 Denormalization

Denormalization is the process of consciouslyremoving entities created through thenormalization process. An unnormalizeddatabase is not a denormalized database. Adatabase can be denormalized only after it hasbeen sufficiently normalized, and solidjustifications need to exist to support every actof denormalization.

Nevertheless, fully normalized databases canrequire complex programming and generallyrequire more joins than their unnormalized ordenormalized counterparts. Joins are resource-intensive operations; thus, the more joins, themore time a query will take.

To deal with queries that take too long or aretoo complex to be maintainable, a databasearchitect denormalizes the database. As we haveseen from the process of normalization, eachlower normal form introduces databaseanomalies that can compromise the integrity,maintainability, and extensibility of thedatabase. Denormalization is thus a reasonedtrade-off between query complexity/performanceand system integrity, maintenance, and

Page 141: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and system integrity, maintenance, andextensibility.

Page 142: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 143: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The Perils of DenormalizationDenormalization must be approached w ith caution. Ingeneral, a table should have proven it requiresdenormalization in testing or even in production beforeyou actually denormalize it. Data architects verycommonly denormalize based on hunches aboutperformance or experience w ith similar applications inthe past a practice that leads down the path to a poorlydesigned database.

Denormalization can in some circumstances incurperformance penalties. More important, however, mostof the time you do not see the kinds of performanceimprovements from denormalization that actually makea difference. When you denormalize w ithout concreteperformance benchmarks backing the denormalization,you end up:

Denormalizing tables w ithout appreciableperformance improvement

Denormalizing again later, after you have doneperformance testing

The result is a database that looks more unnormalizedthan denormalized. The best rule of thumb is to provethe database needs denormalization and document thatneed for the people who w ill be maintaining thedatabase. Subsequently, you should prove that yourdenormalization actually improves performance andback out the changes if they fail to address theperformance concerns.

In most cases, you can deal with complexitysimply by creating views that hide thecomplexity. Performance is thus the general

Page 144: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

driver of denormalization. To determine whetherdenormalization makes sense, I recommendCraig Mullins's simple guidelines posted in anonline article for The Data AdministrationNewsletter in an article called "DenormalizationGuidelines"(http://www.tdan.com/i001fe02.htm):

Can you achieve performance goals withoutdenormalization?

W ill the system still fail to achieveperformance goals with denormalization?

W ill the system be less reliable as a resultof denormalization?

If you answer "yes" to any of these questions,you should not use denormalization as yourperformance tuning tool.

BEST PRACTICE: Denormalize only when youhave concrete proof that denormalization w illboost performance.

The most common temptation to denormalizecomes from queries that require joins to retrievea single value. Any query pulling a film'ssuitability for children along with the film from

Page 145: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

the database would fall into this category. Forexample:

SELECT Film.title, Film.language, Film.year, Rating.forChildrenFROM Film, RatingWHERE Film.filmID = 2AND Film.rating = Rating.code;

Denormalization would move the rating code andsuitability for children back into the Film table.Wouldn't the query perform much better withoutthat join? Actually, it probably would not performnoticeably betterthe join is done using a uniqueindex (Rating.code). Denormalization, however,would incur all of the anomalies that led us tonormalize the table in the first place.

A better candidate for normalization might bepulling a state name into an Address table alongwith the state code used in the join. If mostqueries actually want the state name and thequery would definitely benefit from avoiding thejoin to the State table, it can make sense to addan extra column to Address for stateName. You donot, however, remove the State table. Thisdenormalization works assuming real performancebenefits are achieved for the application becausethe state name is a candidate key for the Statetable. Though stateName would technically be atransitive depencency in the Address table (andthus violate 3NF), its status as a candidate key

Page 146: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

for State makes it almost a functional depencencyand consequently almost acceptable to put intothe Address table.

A common situation in which performance doestruly become a problem is reporting. Forreporting, database normalization is just one ofmany factors that lead to performancedegradation. Because complex reports generallyeat server resources regardless of normalizationissues, it is generally a bad idea to empowerusers to execute complex reports against livetables. Instead, you can denormalize byreplicating the data into special tables designedto support reporting needs. To create a table forreporting on westerns, we might create aWesternReport table that looks like the table inTable 2-9.

Table 2-9. A table for reporting on westerns

Attribute Domain Notes NULL?

filmID BIGINT PRIMARY KEY No

t it le VARCHAR(100) No

rat ing CHAR(5) Yes

forChildren CHAR(1) DEFAULT 'N' No

Page 147: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

otherGenres VARCHAR(255) Yes

directors VARCHAR(255) Yes

actors VARCHAR(255) Yes

ranking INT No

year INT No

Reporting on all of the westerns from 1992would look like this:

SELECT * FROM WesternReportWHERE year = 1992;

The alternative is to have users constantlyexecuting the following query against the tablesthat actually maintain your data:

SELECT Film.filmID, Film.title, Film.rating,IFNULL(Rating.forChildren, 'N'), Film.ranking, Film.yearFROM Film, FilmGenreLEFT OUTER JOIN Rating ON Film.rating = Rating.code

WHERE FilmGenre.code = 'WES'AND year = 1992AND Film.filmID = FilmGenre.filmID;

Use follow-up queries to get other genres,

Page 148: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

directors, and actors associated with the film.

Page 149: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.5 Object-Relational Mapping

You now have your data structured for optimalperformance and extensibility in your database.To make use of that data, you need to pull itinto applications in our case, Javaapplications that manipulate the data. Java is anobject-oriented programming language. In otherwords, it models its problem domain usingobject-oriented principles. In general, object-oriented principles can be summed up as:

Encapsulation

Encapsulation is the hiding of the data andbehavior of a thing behind a limited andwell-described interface. In Java terms, thelimited and well-described interface is theset of your public methods and attributes.

Abstraction

Abstraction is the modeling of only theessential characteristics of a thing andignoring or hiding the details of itsnonessential characteristics. A Javainterface is an example of an abstraction.

Page 150: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Polymorphism

Polymorphism means that a single interfacecan be used for a generic class of actionsrather than a single specific action. Theequals( ) method in Object is an example of apolymorphic interface because it meansdifferent specific things in different classeseven though it generally means testing forequality.

Inheritance

Inheritance is the ability for one thing totake on the behavior and characteristics ofanother. Java supports inheritances throughextending classes.

Though a relational database is a model of aproblem domain, it is a different kind of model.Your Java application models behavior and usesdata to support that behavior. The database,however, models the data in your problemdomain and its relationships. Java applicationlogic is inefficient at determining what actorswho have played the president during theircareer have appeared in films together. Similarly,a database is a poor tool for determining pricingrules for a set of products.

When a Java application needs to save its stateto some sort of data storage, it is said to require

Page 151: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

persistence. Often, complex Java applicationspersist against a relational database. The use ofa relational database for persistence has severaladvantages:

Relational databases are efficient at storingdata for later retrieval using complexcriteria. You cannot search on your storedobjects nearly as efficiently if they areserialized to a filesystem or storedsomewhere in XML.

Java's JDBC API is simple to learn. Otherpersistence mechanisms tend to be muchharder. Java's file access APIs, for example,are painful to write cross-platform codewith.

Most people have easy access to arelational database. MySQL andPostgresSQL are freely available to thosewith limited budgets, and mostorganizations already have a hugeinvestment in enterprise database engineslike Oracle and DB2.

When you attempt to persist your Java objectsto a relational database, however, you run intothe problem of the object-relational mismatch.The most basic question facing the object-oriented developer using a relational database ishow to map relational data into objects. Yourimmediate thought might be to simply map

Page 152: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

object attributes to entity attributes. Thoughthis approach creates a solid starting point, itdoes not create the perfect mapping for tworeasons:

Unlike relational attributes, objectattributes are multivalued. An object storeswithin itself attributes with multiple simplevalues as well as direct references togroups of complex objects.

The relational model has no natural way ofmodeling inheritance relationships.

BEST PRACTICE: Normalize data modelsbased on object-relational mapping just asyou would normalized any other data model:to 3NF or 4NF.

Figure 2-11 contains a sample class diagram fora system that should persist against a relationaldatabase. In the class diagram, you aremodeling a person who can play manyroles including the roles of employee andcustomer. Each employee has many addressesand phone numbers.

Figure 2-11. A simple classdiagram for a persistent system

Page 153: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.5.1 Inheritance Mapping

The biggest difficulty in object-relationalmapping arises in inheritance mapping themapping of class inheritance hierarchies into arelational database. In our class diagram, thisproblem appears in the structure related toroles. Do you need separate entities for Role,Employee, and Customer? Or does it make moresense to have Employee and Customer entities? Orperhaps just a Role entity will sufffice?

Depending on the nature of your class diagram,all three solutions can work. Figure 2-12 showsthree possible data models for supporting theclass diagram from Figure 2-11.

Figure 2-12. Three possible datamodels for roles

Page 154: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

As you can see from all three data models, therelational model's inability to support abstractiondoes some serious damage to the application.While the class diagram enables the addition ofnew roles to the system without impacting thePerson class, you cannot accomplish the sameflexibility in the data model. All three datamodels demand some understanding of allpossible roles available.

The simplest data model the one with only a Roleentity must contain all data associated with allpossible roles. This approach to object-relationalinheritance mapping when the implementationclasses contain mostly the same data and thedifferences among the roles from a dataperspective can be summarized through a role

Page 155: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

type.

On the other hand, if the commonalities in thedifferent roles are not interesting from a dataperspective, you can solve the problem with thesecond data model. In other words, model eachrole with its own entity and ignore the entireRole abstraction in the database. This approachfails if you need to ask questions like "Whatroles does this person have?" withoutnecessarily knowing what possible roles canexist.

The third approach is a sometimes unwieldycompromise between the first and secondapproaches. When you need to deal with theroles both abstractly and concretely, you have tocreate a relationally artificial structure to modelthose nuances. In this data model, the entitiesfor the concrete classes Employee andCustomerborrow their primary keys from the Roleentity. Only the Role entity contains the foreignkey of Person with whom the role is associated.You can now deal with the roles in an abstractsense by joining with the Role entity, or you canget specific information about individual rolesthrough a complex join.

In short, the proper way of modeling aninheritance relationship depends heavily on whatsort of queries you intend to use to retrieve thatdata. When in doubt, refer to this set of rules tohelp you in inheritance mapping:

Page 156: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Model only the superclass

If your queries rely heavily on dataassociated with the superclass and

If your queries do not rely on dataassociated with the subclasses and

If the subclasses do not contain asignificant number of distinct attributes

Model only the subclasses

If your queries rely heavily on dataassociated with the subclasses and

If your queries do not rely on dataassociated with the superclass

Model the superclass and its subclasses

For all other circumstances.

BEST PRACTICE: When modeling OO (object-oriented) inheritance, consider whether yourdatabase w ill be used by non-OO systems. Ifit is being used by non-OO systems, focusmore on the data model and less on mappingthe OO concepts to the relational world.

Page 157: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

2.5.2 Multivalued Attributes

Collections such as arrays, HashMaps, andArrayLists present another problem to object-relational mapping. In relational terms, thesekinds of object attributes represent multivaluedattributes. The solution to this problem startswith the same solution for multivalued attributesin your relational model: create entities tosupport the multivalued attributes.

That approach is simple enough for collections ofobjects like the Phone and Address classes in ourclass diagram. You create a Phone entity with aforeign key of personID and a primary key ofpersonID and type and you are done. The mappingbecomes tricky with attributes like int arrays orString collections.

BEST PRACTICE: If your database enginesupports SQL3 data types, map multivaluedattributes to the SQL ARRAY type.

In our class diagram, we store a list of favoritecolors as a String[ ]. The solution again is tohandle this mapping in the same way you wouldhandle the normalization of an entity withmultivalued attributes: create a new entity. Inthis case, we would create a FavoriteColor tablewith personID and color as a primary key.

Page 158: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

with personID and color as a primary key.

Page 159: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 160: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 3. TransactionManagement

Substances owe their special importance inthe enterprise of identification to the factthat they survive through time. But the ideaof survival is inseparable from the idea ofsurviving certain sorts of change of position,size, shape, colour, and so forth. As wemight expect, events often play anessential role in identifying a substance...Neither the category of substance nor thecategory of change is conceivable apartfrom the other.

Donald Davidson The Individuation ofEvents

This quote from Donald Davidson comes from apaper he wrote in the field of event theory.Event theory is an entire subdiscipline ofphilosophy focused on the question of what itmeans to be an event. As a software architectfor a database application, your job is to be anevent theorist. Specifically, you identify whatchanges will occur in your database and howthey combine into indivisible sequences that will

Page 161: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

not leave the database in an inconsistent state.

This is the practice of event management. Youthen package those indivisible events into adatabase operation called a transaction. Atransaction is a group of database events thatmust execute without interference from othertransactions; and they must execute together ornot at all. The transaction helps you guaranteethe integrity of the data in your database.

The classic example of a database transaction isthe transfer of money from one bank account toanother. When executing a transfer, a bankingapplication needs to make sure that both thedebit from the source account and the credit tothe target account execute. If one should fail,the system should return to the state it was inbefore the debit. W ithout the ability to abort thetransaction, a successful debit followed by afailed credit (perhaps the server crashedbetween the two operations) will result inmissing money.

Page 162: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

3.1 Transactions

A transaction is an event or sequence of eventsthat takes a database from one consistent stateto the next. If any of the events fails or thesequence fails to complete, the system isreturned to its initial state. Once it completes, itis guaranteed to be in the new consistent stateuntil it is acted upon to completion by anothertransaction.

3.1.1 ACID Requirements

Formally, a transaction is a group of databaseoperations that together have a shared set ofguaranteed properties commonly known as ACIDproperties. ACID is an acronym that stands forAtomicity, Consistency, Isolation, and Durability.

Atomicity

The atomicity of a transaction means that itrepresents an indivisible unit of work. Anyattempt to break the transaction intosmaller parts breaks the transaction.Atomicity is what guarantees that all of theoperations that make up a transactionsucceed or none of them succeeds.

Page 163: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Consistency

The consistency of a transaction means thatall of the operations that make up atransaction operate on a consistent set ofdata and leave the database in a consistentstate once it has completed. In otherwords, the transaction is ignorant of anychanges made to the database by othertransactions. Data is considered consistentwhen all of its constraints such as uniqueindexes and foreign indexes are intact.

Isolation

A transaction should be ignorant of theexistence of any other transactions. Inother words, from the point of view of agiven transaction, it is the only thingoperating on the database.

Durability

When a transaction commits, its changesare permanent even in the event of a systemfailure.

In other words, if you have an account transfer,it meets ACID requirements in the following

Page 164: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

ways:

The transfer is atomic if and only if the sumof the two bank accounts is the samebefore and after the transfer. The debit tothe savings account cannot occur withoutthe credit to the checking account following.

The transfer is consistent as long asnothing else happens to either accountwhile the transfer is in process. Forexample, the checking account cannot bedeleted from the database while the debitto the savings is occurring.

The transfer is isolated as long as anothertransaction is incapable of seeing thedebited savings account before the transferhas completed.

The transfer is durable as long as thetransfer can survive a catastrophic eventsuch as a server crash or other kind ofsystem failure.

Your database engine is largely responsible forguaranteeing the ACIDity of your transactions.You, the software architect, are neverthelessresponsible for identifying what events make upa transaction and how the application shouldpackage those transactions for the database.

Page 165: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Choose technologies thatw ill guarantee the ACIDity of yourapplication's transactions.

3.1.2 Transaction Design

The key to identifying transactions isdetermining what stages in your use casesrepresent consistent database states. If weexamine the transfer example, we see twodistinct events that make up the transfer:

1. Debit the savings account.

Credit the checking account.

After the debit of the savings account, thedatabase is said to be in an inconsistent statebecause important information about the systemwould be lost should the transfer fail tocomplete. In this case, the importantinformation is someone's money!

Inconsistency can also mean having orphaneddata in the database. Consider, for example, thedeletion of a person from a database with thefollowing steps:

1. Delete the person from the Person table.

Delete all addresses for the person from theAddress table.

Page 166: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Delete all phone numbers for the person fromthe Phone table.

If something goes wrong after the first step, youcould end up with a database full ofunreferenced addresses and phone numbersunless the transaction returns the system to itsinitial state. The database is therefore in aninconsistent state until all addresses and phonenumbers are deleted.

Though you want your transactions to be largeenough to prevent the database from enteringinconsistent states, you also want them as smallas possible. As you will see later in this chapter,transactions make huge demands on a database.The larger the transaction, the more resources iteats and the worse the performance of yourapplication.

BEST PRACTICE: Define your transactions tohave the minimum number of steps necessarywhile leaving the data store in a consistentstate.

To illustrate this problem in action, consider ane-commerce application that needs to create acustomer before the customer can place anorder. To make the application as easy to use forthe customer as possible, you may let her enterher customer information along with her firstorder. The use case thus looks something like

Page 167: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

this:

1. Add the customer information to theCustomer table.

Add address information to the Address table.

Add phone information to the Phone table.

Create an order in the Order table.

Add a line item in the LineItem table.

Decrease the inventory count in the Producttable.

It is the combined job of the business analystand information architect to craft this use caseas the best way for a new customer to buysomething. It is your job as the softwarearchitect to figure out its implications on thedatabase. In many situations, there will be aone-to-one correspondence between use casesand transactions. In this case, however, we havetwo separate transactions because the databasecan be in a consistent state with the customerinformation and no order information. In otherwords, steps 1-3 make up the first transactionand steps 4-6 make up the second. Figure 3-1contrasts the use case from the client'sperspective with the sequence from thearchitect's perspective.

Page 168: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 3-1. A multitransaction usecase from the perspectives of a

client application and an architect

By breaking this one use case into twotransactions, you will not sacrifice databaseconsistency but you will gain performance. Thedivision enhances performance because youenable other transactions that may be waitingon resources blocked only by the first threesteps to execute prior to the completion of theentire use case. If you encapsulated the usecase in a single transaction, then those othertransactions would have to wait until thecompletion of the use case. Figure 3-2 showshow breaking the use case into two transactionscan reduce blocking.

Figure 3-2. Reduced blocking bydividing work between two

transactions

Page 169: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 170: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 171: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

3.2 Concurrency

Transaction management is a big enoughproblem worrying only about consistency,atomicity, and durability. Perhaps one of thebiggest issues is isolation how do you managethe concurrent access to database resources bymany different users? The mechanism yourdatabase uses is generally hidden from thesoftware architect and database programmer. Adata architect, however, should be familiar withhow their database of choice manages isolation.

3.2.1 Isolation Levels

Before talking about the various mechanisms tosupport transaction isolation, it is useful toexamine the concept in more detail. As Imentioned earlier, isolation is the I in ACID.When a second transaction attempts to read thedata being modified by a first transaction, thatsecond transaction will not see any changes thefirst transaction has made. For example, if mywife read a joint savings account balance at thesame time I was transferring money fromsavings to checking, the following events might

Page 172: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

occur:

1. I see a savings account balance of$1,000.

I initiate a transfer of $500 from savings tochecking.

The system debits my savings account.

My wife requests the balance for the savingsaccount and sees $1000.

The system credits my checking account.

My wife should see $1,000 as the balance in thesavings account even though the system hasalready debited the savings account. She readsthe old value because the transfer transaction isin an inconsistent state at the time of herrequest.

So far in this chapter, we have looked attransaction isolation only in the context of fulltransaction isolation where a transaction can acton the database as if it were the only threadoperating on that database. In the real world,databases must support concurrent access bymultiple transactions. Business applications in

Page 173: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

multiple transactions. Business applications inparticular have significant concurrency demands.Because of the performance penalty of fulltransaction isolation, it is rarely practical formost systems.

ANSI SQL identifies four distinct transactionisolation levels that enable you to balanceperformance needs with data integrity needs. Inorder to understand the different transactionisolation levels, however, you should firstunderstand a few terms relating to theinteraction of concurrent transactions:

Dirty read

A dirty read occurs when one transactionviews the uncommitted changes of anothertransaction. If the original transaction rollsback its changes, the one that read itschanges is said to have "dirty" data.

Nonrepeatable read

A nonrepeatable read occurs when onetransaction reads different data from thesame query when it is issued multiple times

Page 174: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and other transactions have changed therows between reads by the first transaction.In other words, a transaction that mandatesrepeatable reads will not see the committedchanges made by other transactions. Anapplication needs to start a new transactionto see those changes.

Phantom read

A phantom read deals with changesoccurring in other transactions that wouldresult in new rows matching yourtransaction's WHERE clause. For example, ifyou had a transaction that reads allaccounts with a balance of less than $100and your transaction performs two reads ofthat data, a phantom read allows for newrows to appear in the second read based onchanges made by other transactions. Thissituation can occur if someone withdrewmoney between your reads. The new rowsare called phantom rows.

The four ANSI SQL transaction isolation levelsare:

Page 175: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Read uncommittted transactions

The transaction allows dirty reads,nonrepeatable reads, and phantom reads.

Read committed transactions

Only data committed to the database maybe read. The transaction can, however,perform nonrepeatable and phantom reads.

Repeatable read transactions

Committed, repeatable reads as well asphantom reads are allowed. Nonrepeatablereads are not allowed.

Serializable transactions

Only committed, repeatable reads areallowed. Phantom reads are specificallydisallowed at this level.

Page 176: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Assuming your database engine supports theselevels of transaction isolation, a Java databaseapplication can control its transaction isolationlevel through the JDBC Connection interface usingthe setTransactionIsolation( ) method:

Connection conn = dataSource.getConnection( ); conn.setTransactionIsolation( Connection.TRANSACTION_READ_COMMITTED);// perform your transaction

To find out what transaction isolation levels yourdatabase engine and driver support, use thesupportsTransactionIsolationLevel( ) method inDatabaseMetaData. Table 3-1 shows the transactionisolation constants in java.sql.Connection. You mayalso want to check whether the databasesupports transactions at all (mSQL, for example,does not support them). The methodsupportsTransactions( ) answers this question.

Table 3-1. Constants for managing JDBCtransaction isolation levels

Constant Meaning

Transactions are notsupported by the databaseengine. You never set the

Page 177: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

TRANSACTION_NONE transaction isolation levelw ith this value. It is simply areturn value from driverswhen transactions are notsupported.

TRANSACTION_READ_UNCOMMITTED

Reads are read uncommitted.This level represents theleast-restrictive form indatabases in whichtransactions are supported.

TRANSACTION_READ_COMMITTED Reads pull only committeddata from the database.

TRANSACTION_REPEATABLE_READ Reads are repeatable, butphantom reads are allowed.

TRANSACTION_SERIALIZABLE Phantom reads are notallowed.

As an application architect, your job is tobalance database integrity with applicationperformance. You therefore want to select thelowest level of transaction isolation that willprotect the integrity of the data as you have itstructured in your data model.

BEST PRACTICE: Use the lowest transactionisolation level that w ill still maintain the

Page 178: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

integrity of your database.

3.2.2 Locking

The way in which your database engine managesconcurrency is specific to your database engine.As long as it maintains ACIDity, it does notmatter from a standards perspective how it doesit. Nevertheless, database engines all use someform of locking.

Conceptually, concurrency at the database levelcan be understood using Java as an example.Java, of course, uses locks on objects to manageconcurrent access to synchronized blocks of Javacode. Consider the following three methods:

public class MyClass { public synchronized void first( ) { // do something } public void second( ) { synchronized( this ) { // do something else } }

Page 179: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public void third( ) { synchronized( otherObject ) { // do yet a third thing } }}

If two threads call first( ) at the same time, onewill be allowed to execute the method tocompletion before the other can start. Thissequencing occurs because the synchronizedkeyword indicates that you are locking against amonitor. In the default case, the monitor isalways this. Thus the monitor in first( ) and second() is this and the monitor for third( ) is otherObject.Only one thread at a time can execute codemonitored by a common object. In this example,first( ) and the synchronized section of second( )cannot be executed concurrently by multiplethreads. However, first( ) and third( ) can beconcurrently executed by two separate threadssince they are guarded by different monitors.

Databases use a different concurrencymechanism, but the Java concepts are relevant.A database allows for locks to be taken ondifferent scopes of data. A database can lock atable at any of the following levels:

Page 180: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

TablePageRow

Depending on your database engine, your locklevel can also be modified as read, update,exclusive, shared, or any other number ofattributes. SQL Server, for example, supports thefollowing kinds of locks:

IntentSharedUpdateExclusiveSchemaBulk update

You need a nice spreadsheet and anunderstanding of your database of choice toappreciate how two kinds of locks interact. Forexample, many different threads can acquire ashared lock. These shared locks may dependingon the database engine prevent another threadfrom acquiring an update lock until the sharedlocks are released. Because interaction varies bydatabase, a discussion is beyond the scope ofthis book.

The easiest lock level to understand is a table-

Page 181: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

level lock. In this case, only one thread cantouch the locked table during the lifetime of thelock. This approach is much like usingMyClass.class as the monitor for access to allmethods in your MyClass class. In other words, notwo threads would be able to access any MyClassinstance concurrently. As you can imagine, sucha trick would not perform well in a Javaapplication. Similarly, table-level lockingperforms horribly for databases. Page-levellocking has no Java analogy. In short, it preventsconcurrent access to all of the rows in a singlepage of memory. If, for example, you have rows1-3 in one page of memory and 4-6 in another,access to data from rows 1-3 with page-levellocking prevents other threads from accessingany of those three rows. A concurrent threadcan, however, access the data in rows 4-6.

Row-level locking is like making every nonstaticmethod in a Java class synchronized. It preventsconcurrent access by two threads to the samerow in the database. Two threads may, however,access two different rows concurrently.

On one hand, locking is necessary to guaranteeproper transaction isolation in a concurrentenvironment. On the other, locking slows downdatabase applications. Any transaction that has

Page 182: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

a long duration and a large number of resourcesassociated with it is going to drag down anyapplication. Later in the chapter, I introducesome approaches to concurrency that enable youto strike a balance between isolation andperformance.

Page 183: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

3.3 JDBC Transaction Management

No matter what style of database programmingyou select or what persistence model you follow,transactions will always be the mostfundamental element in database programming.Consequently, we will be returning to transactionmanagement repeatedly over the course of thisbook. For now, it is time to lay the foundationfor that database programming by showing thebasics of transaction management in Java code.

3.3.1 Basic Transaction Management

In any programming language, basic transactionmanagement is indicating the start and end of atransaction as well as handling any errors thatcome up during the transaction. In JDBC, atransaction begins implicitly whenever you createa statement of any kind. It ends when you callcommit( ) in the Connection instance. Finally, youabort the transaction and return the database toits initial state by calling rollback( ) in theConnection instance.

The Connection governs all of this transactionmanagement. You therefore cannot usestatements from different Connection instances inthe same transaction. You also have to tell theconnection that your application is managingtransactions; otherwise, it will commit everystatement after you send it to the database. Thefollowing code executes two updates in a singletransaction and rolls back on any errors:

public void transfer(Account targ, float amt) { Connection conn = null; try { PreparedStatement stmt;

Page 184: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

conn = dataSource.getConnection( ); conn.setAutoCommit(false); stmt = conn.prepareStatement("UPDATE Account SET balance = ? " + "WHERE id = ?"); stmt.setFloat(1, balance-amt); stmt.setInt(2, id); stmt.executeUpdate( );

stmt.setFloat(1, targ.balance + amt); stmt.setInt(2, targ.id); stmt.executeUpdate( ); balance -= amt; targ.balance += amt; conn.commit( ); } catch( SQLException e ) { try { conn.rollback( ); } catch( SQLException e ) { } } finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } }}

3.3.2 Optimistic Concurrency

In the days of client/server programming,applications often started a transaction byreading data from a database and ended thetransaction by modifying that data. In otherwords, you locked the data you read so thatsomeone else didn't overwrite any changes youmade. For example, if you and I read a customerrecord from the database with my goal to changethe phone number and your goal to change thelast name, one of us runs the risk of overwritingthe other's changes if neither of us has a read

Page 185: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

lock. If I saved my changes first, your clientapplication will likely overwrite my phone numberchange with the old phone number sinceapplications tend to send all fields with theirupdates. Figure 3-3 illustrates what can gowrong in this example.

Figure 3-3. Updates overwritingeach other

I can prevent you from overwriting my changesby starting a transaction when I read the data.That way you cannot even read the customerrecord until my change is saved. This techniqueis called pessimistic concurrency, and it is aterrible bottleneck. If I manage to walk awayfrom my desk while entering the phone number,your client will be waiting a long time to readthat data. In web-based applications, this kindof pessimistic concurrency is completelyuntenable.

Page 186: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

You can make pessimistic concurrency a littlemore acceptable by performing a SELECT FORUPDATE just prior to actually sending changes tothe database using the values returned from thefirst query. If the rows no longer match theoriginal select, then you will receive no rows andlock no resources in the database. Though thisform of pessimistic concurrency locks resourcesfor a much shorter time than the original, it isstill a relatively long-lived transaction. It alsorequires placing columns that are probably notindexed in a SELECT statement. The followingexample illustrates this flow:

SELECT firstName, lastName, phone, birthDay FROM CustomerWHERE id = ?; // on the client, make changes here// this could take a long, long time// minutes, even tens of minutes SELECT firstName, lastName, phone, birthDayFROM CustomerWHERE id = ?AND firstName = ?AND lastName = ?AND phone = ?AND birthDay = ?FOR UPDATE UPDATE Customer SET firstName = ?,lastName = ?,phone = ?,birthDay = ?WHERE id = ?

The alternative is optimistic concurrency. Wherepessimistic concurrency pessimistically assumesthat some other transaction will attempt tomake changes to your data behind your back,optimistic concurrency happily hopes that such a

Page 187: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

situation will not occur. As a backup, it usesvalues from the original row in the WHEREclause:

SELECT firstName, lastName, phone, birthDayFROM CustomerWHERE id = ? // again, make changes here... this could take a long time UPDATE CustomerSET firstName = ?,lastName = ?,phone = ?,birthDay = ?WHERE id = ?AND firstName = ?AND lastName = ?AND phone = ?AND birthDay = ?

Under optimistic concurrency, you acquire a lockonly when you are actually performing yourchanges. You still avoid overwriting the changesof another because you match your updateagainst the values you read. If someone elsechanges the lastName field, then your WHEREclause will not match and the update will fail.Unfortunately, you are still very likely matchingagainst unindexed columns.

The approach I use in nearly every databaseapplication I write is to create a special columnor two to store a value unique to each update.For example, you could use the natural primarykey of the table along with a last updatetimestamp. Each time you modify the database,you modify the last update timestamp and usethe old one in your WHERE clause:

Connection conn = null; try {

Page 188: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

PreparedStatement stmt; long ts; conn = ds.getConnection( ); stmt = conn.prepareStatement("UPDATE Customer " + "SET firstName = ?, lastName = ?, phone = ?, " + "birthDay = ?, lastUpdateTS = ? " + "WHERE id = ? AND lastUpdateTS = ?"); stmt.setString(1, firstName); stmt.setString(2, lastName); stmt.setString(3, phone); stmt.setDate(4, birthDate); stmt.setLong(5, ts = System.currentTimeMillis( )); stmt.setInt(6, id); stmt.setLong(7, lastUpdateTS); stmt.executeUpdate( ); lastUpdateTS = ts;}catch( SQLException e ) { e.printStackTrace( );}finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } }}

Figure 3-4 contrasts how optimistic concurrencyprevents this mishap, in contrast to Figure 3-3.

Figure 3-4. Optimistic concurrencyprevents dirty writes

Page 189: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

This approach has the advantage of preservingdatabase integrity just like pessimisticconcurrency while at the same time minimizingthe lifetime of the transaction and guaranteeingthat only indexed values are in the WHEREclause. The only true downside is that you arealso updating an indexed column, and updatesto indexes have their own performance impact.

BEST PRACTICE: Use optimistic concurrencyalong w ith timestamps to help maintain dataintegrity while still getting solid performance.

3.3.3 Batch Transactions

We have been dealing with transactions in aninteractive context where a user is initiating thetransaction through some action in a userinterface. Complex business systems have notonly interactive transactions, but also batchtransactions. Batch transactions are sets oftransactions that occur on the server

Page 190: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

transactions that occur on the serverindependent of user interaction. For example,the monthly process that calculates interest fora savings account is a batch transaction.

Until JDBC 2.0, Java was a miserable languagefor the execution of major batch transactions.Sometimes, people would have processes thatneeded to execute nightly but took two days torun. The overhead, of course, was partly due tothe interpreted nature of Java and the lack ofHotSpot VMs (virtual machines) at that time. Itwas also due to the fact that batch JDBCprogramming required a lot of back-and-forthbetween the batch application and the databaseas well as unnecessary string processing.

JDBC 2.0 introduced a batch processingmechanism that addressed the non-VM issues(HotSpot addressed the VM issues). Specifically,JDBC enables you to store multiple statementson the client to be sent over to the database asa group as a batch. When running that monthlyinterest process, you previously could send theupdate for each account to the database onlyone at a time. Now you can choose to send theupdates for all accounts at once, or you cangroup a bunch of the updates together and sendthem in waves.

As a general rule, the more updates you hold onthe client, the faster the batch processingoccurs. However, you are limited in the numberyou can hold by several factors:

RAM

You have to store those updates inmemory. Thus, the more updates you holdfor batch execution, the more RAM you areeating. If you eat up so much RAM that youstart swapping, you will destroy the

Page 191: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

performance benefits of batch processing.

The database transaction log

If you have auto-commit turned off, thenthe whole batch sent to the database isexecuted as a single transaction. If yousend too many updates over, you risk fillingup the database's transaction log.

Recovery processing

If you have auto-commit on and you arebatching numerous transactions, recoveryprocessing is much more involved becauseyou have to figure out what the lastsuccessful update was in your batch andthen recover from there. The more updates,the more complex the recovery process canpotentially be.

The trick is to batch up a reasonable number ofupdates together. Unfortunately, a reasonablenumber depends on the amount of RAM availableto the application, the size of your databasetransaction log, the amount of RAM on thedatabase server, and the complexity of anyrecovery processing. In some situations, itmakes sense to batch up 10 updates, while inothers 100 or more makes sense. The followingcode illustrates batching together 10 statementsat a time for updating account balances:

PreparedStatement stmt; conn.setAutoCommit(false);stmt = conn.prepareStatemment("UPDATE account " + "SET balance = ? " + "WHERE id = ?");for(int i=0; i<accts.length; i++) {

Page 192: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

int[ ] rows; while( (i%10 != 9) && (i<accts.length) ) { accts[i].calculateIntterest( ); stmt.setDouble(1, accts[i].getBalance( )); stmt.setInt(2, accts[i].getId( )); stmt.addBatch( ); i++; } rows = stmt.executeBatch( );}

For a more complete discussion of the way JDBCmanages batch processing, see the tutorial inChapter 11.

3.3.4 Savepoints

While JDBC 2.0 added batch processing to thetransaction arsenal of the JDBC programmer,JDBC 3.0 added something called savepoints.W ithout the benefit of savepoints, JDBC allowsfor only two possible consistent states in atransaction: the beginning state and the endstate. Some transactions, however, may havemore than two possible consistent databasestates. For example, you may have a transactionin which an error condition during processing isitself meaningful to the transaction and thusshould cause an alternate flow with an alternateconsistent end state.

BEST PRACTICE: Use savepoints to supporttransactions w ith multiple possible consistentend states.

I honestly have never encountered a situation inbusiness programming in which I felt I neededsavepoints. One possible example, however,would be a flexible tool for managing the

Page 193: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

addition of new users to a web site. On your website, you probably want to empower users toidentify themselves by unique names but youwant them to be able to change those names.Because they can change, they make poorcandidates for a primary key. Instead, youautomatically generate an otherwisemeaningless primary key and let them pickmeaningful names that are used as a uniqueindex.

Of course, it is possible that whatever name auser chooses is already in use. To make theprocess as simple for the user as possible, youwould have the following events in yourtransaction:

1. Generate a unique primary key from aSequence table (requires an update).

Save the user contact information to theContact table.

Add the username and timestamp to a newuser log.

Insert the user profile information (includingusername) into the Profile table.

If the chosen username is a duplicate, insertthe profile information into the Profile table usingthe primary key as a temporary username. Afterthat, log the new user ID and timestamp to thenew user log.

In this example, you could set a savepoint afterstep 2 and roll back the transaction to that pointin the event the chosen username is a duplicate.Using a savepoint, you can guarantee that theuser will appear in the new user log under theproper username.

Of course, you can avoid the need for savepoints

Page 194: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

by restructuring this contrived transaction.Nevertheless, it does illustrate the conditionalprocessing inherent in savepoint transactions.The following code shows how it works inpractice:

Connection conn = null; try { // the sequencer generates unique user ID's for us Sequencer seq = Sequencer.getInstance("userID"); PreparedStatement stmt; Savepoint sp; long id; conn = ds.getConnection( ); conn.setAutoCommit(false); id = seq.next(conn); stmt = conn.prepareStatement("INSERT INTO Contact ( userID, email ) " + "VALUES ( ? , ? )"); stmt.setLong(1, id); stmt.setString(2, email); stmt.executeUpdate( ); sp = conn.setSavepoint("contact"); stmt = conn.prepareStatement("INSERT INTO NewUser ( userName, when ) " + "VALUES ( ?, ? )"); stmt.setString(1, userName); stmt.setLong(2, System.currentTimeMillis( )); stmt.executeUpdate( ); stmt = conn.prepareStatement("INSERT INTO Profile ( userID, userName, pass ) "+ "VALUES ( ?, ?, ? )"); stmt.setLong(1, id); stmt.setString(2, userName); stmt.setString(3, password); try { stmt.executeUpdate( ); } catch( SQLException e ) { conn.rollback(sp); userName = "" + userID; stmt = conn.prepareStatement("INSERT INTO NewUser ( userName, when ) " + "VALUES ( ?, ? )"); stmt.setString(1, userName);

Page 195: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

stmt.setLong(2, System.currentTimeMillis( )); stmt.executeUpdate( ); stmt = conn.prepareStatement("INSERT INTO Profile ( userID, userName, " + "pass ) VALUES ( ?, ?, ? )"); stmt.setLong(1, id); stmt.setString(2, userName); stmt.setString(3, password); stmt.executeUpdate( ); }}catch( SQLException e ) { try { conn.rollback( ); } catch( SQLException e ) { }}finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } }}

Page 196: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

3.4 Transaction Management Paradigms

By this point, you should understand the role oftransactions in database programming and thetools that Java provides through JDBC to enableyou to manage transactions. The final step is tounderstand how they fit into the bigger picture,into the overall architecture of a transactionalsystem.

There is no "one size fits all" paradigm fortransactional systems. Different programmingtasks require different design patterns to helpyou support your database transactions. Themost common paradigms are:

Auto-commit transactions

This pattern is the simplest transactionmanagement pattern. You simply let thedatabase commit every statement you sendby leaving the connection in auto-commitmode. Unfortunately, there are few realworld problems for which you can use auto-commit mode.

Page 197: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

JDBC transactions

This paradigm is the one you see in mostJDBC texts. You turn off auto-commit andmanage the transactions yourself. You areresponsible for commits, rollbacks, andrecovery in your Java code.

Stored procedure transactions

Using stored procedures, you can capturethe complexity of any transaction and leaveyour Java code as simple as auto-commitmode programming. The stored procedurebegins the transaction and containscommits and rollbacks. This approach wouldbe the ideal if stored procedures did notrequire writing in some proprietary storedprocedure language.

EJB transactions

In an EJB environment, you can have theEJB container manage your transactions for

Page 198: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

you. If you are unfamiliar with the term"container," we will cover that and otherdetails of the J2EE platform in Chapter 9.For now, using EJB transactions means youdo not have to have to do any transactionhandling in your Java code. A third-partyproduct manages the transactions for you.

Distributed transactions

Any one of the preceding transactions canalso be a distributed transaction. Adistributed transaction is one that spansmultiple databases. You will generally beusing distributed transactions in an EJBenvironment. Consequently, your Java codedoes not do any transactionmanagement distributed transactions arealso managed by the container.

Throughout the rest of the book I will build onthese transaction patterns and show differentpersistence metaphors that rely on thesetransaction management patterns.

Page 199: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 200: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Part II: Persistence ModelsIn the object-oriented world of Javadevelopment, Java objects are said topersist against a data store. In other words,the objects that make up your Javaapplication save their data to a relationaldatabase so that data may be referenced ata later time. The approach you take tomapping your Java objects to the data storeis called a persistence model .

These days, Java programmers have manypersistence models from which to choose.In this section, we look at many of themost popular persistence models, including:

EJB, both container-managed andbean-managed

Java Data Objects

Third-party tools such as Hibernate andCastor

Custom persistence models

Page 201: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 202: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 203: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 4. PersistenceFundamentals

Objects contain the possibility of allsituations.

Ludwig W ittgenstein, Tractatus LogicoPhilosphicus

Persistence grants immortality to your businessapplications. W ithout it, you lose all of yourapplication data every time the server shutsdown. Database programming is thedevelopment of persistence mechanisms to savean application's state to a relational database.In this book, I will cover a variety of persistencemechanisms, but this chapter introduces thebasics through a custom guest book JSPapplication.

Page 204: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

4.1 Patterns of Persistence

The excellent book Design Patterns by ErichGamma, Richard Helm, Ralph Johnson, and JohnVlissides (Addison-Wesley) has popularized theconcept of design patterns. They are recurringforms in software development that you cancapture at a low level and reuse acrossdissimilar applications. W ithin any applicationscope are problems you have encountered;patterns are the result of recognizing commonproblems and leveraging a common solution.

People have been writing database applicationsfor nearly three decades. Over that time, manybest practices have evolved into design patterns.As we explore different modes of persistence inthis book, we will see many of these patternsover and over again.

4.1.1 Division of Labor

Perhaps the most essential element of goodpersistence design is a clear separation ofapplication logic into the following areas:

Page 205: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

View logic

The view logic is responsible for displayingthe user interface. It is the user's windowinto the control and business logic.

Control logic

The control logic handles user actions anddecides what should happen based on thoseactions. It handles data validation andtriggers the appropriate business logic onbehalf of the user.

Business logic

Business logic[1] encapsulates the basicbusiness concepts behind your application.They provide the view with getter methodsto access business data and provide theinterface for creating, searching, modifying,and deleting the business objects theysupport.

Page 206: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[1] You do not need to be writing a businessapplication to have business logic. Business logic is ageneric term that refers to any of the basic conceptsin your problem domain. If you are building a first-person shooter game, your "business objects" aremonsters, weapons, hazards, and the like.

Data access logic

Data access logic maps business objects tothe data storage layer. They are the heartof persistence.

Data storage logic

The database engine provides you with thistype of logic, which simply ensures yourdata is not lost at application shutdown.

Separation of logic with dependencies based onsimple interfaces is a core principle of object-oriented software engineering. When you capturethe essence of a business concept in a businessobject without burdening it with other logic, youenable it to be reused in other environments. Forexample, a bank account object that does notcontain display or data access logic can be

Page 207: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

reused with JSP, Swing, and other kinds offrontends. It can also persist against differentdatabase engines.

BEST PRACTICE: Divide applicationfunctionality into different logical componentsto facilitate component reuse.

This same principle extends beyond the businessobject layer. It also makes it easier to divide thework of building software among developers withdifferent skills. W ith a good tag library, the viewdeveloper needs to know only XHTML and yourtag library to write the view. The more difficultwork of JDBC programming can be easily handedoff to an experienced JDBC programmer withouthaving to hand the entire application to a JDBCprogrammer.

BEST PRACTICE: Divide application logic intomultiple tiers to match the complexity of yourapplication.

4.1.2 Sequence Generation

Page 208: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In almost any database application, you need togenerate unique identifiers to serve as primarykeys in your database. Most databases havesome sort of proprietary mechanism to help yougenerate sequences. Unfortunately, you cannotport a database application that relies on theseproprietary schemes to other databases withoutchanging the code that relies on those schemes.

I always recommend the use of a database-independent approach to sequence generation.Later in this chapter, I develop a sequencegenerator that will work for most databaseapplications. It stores sequence seeds in thedatabase. When an application needs a newunique number, it requests the unique numberfrom the sequence generator. If the sequencegenerator has the seed in memory, it uses thefollowing formula to create a new uniquenumber:

unique = (seed * 1000000) + last; last++;

If the seed is not in memory, it is loaded fromthe database, incremented, and the incrementedvalue is stored back in the database. When theseed runs out of unique values when last reaches1000000[2]it loads a new seed from the

Page 209: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database, increments that new seed, and savesthe incremented seed back to the database.

[2] The value 1,000,000 depends on the system. You w illwant lower numbers for systems w ith short uptimes andlarger numbers for systems w ith long uptimes.

This approach has several important features:

It generates unique values in a distributedenvironment. Multiple application serverscan save business objects to multipledatabases and still have the guarantee thatthe sequences being generated are uniqueacross the entire system.

You do not need to go to the databaseevery single time you generate a sequence.You go to the database only every millionsequences.

The sequences are not tied to a specifictable. You can create a sequence that isshared among several tables or even acrossthe entire database. Similarly, you can havemultiple values in the same table rely ondifferent sequences.

Page 210: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Use database-independentsequence generation.

4.1.3 Mementos

In the division of labor discussed earlier, thedata access object needs to know about thestate of the object it is persisting. You couldpass the business object to the data accessobject, but doing so would require the dataaccess object to know the intimate details ofhow the business object is implemented. Thememento design pattern from the DesignPatterns book comes to the rescue here.

A memento enables one object to share its statewith another without either object needing toknow anything about the other. Consider acommon situation in which you have one class(class A) that references the values of another(class B). If you delete an attribute in class B,class A will no longer compile if it has directreferences to the deleted attribute of class B. Ingeneral, this behavior is exactly what you want.

Sometimes especially in mapping objects to adatabase you want a looser coupling between

Page 211: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

two classes. The memento pattern creates thisindependence. It specifically enables you tomake code changes to the business objects anddata access objects independently of each other.A change to the business object will not requireany changes to the data access object unlessyou are adding new data elements or removingobsolete ones. The data access object knowsthat the only changes it will care about come inthe form of changes in the data contained in thememento. Similarly, any change to theunderlying tables in the database is hidden fromthe business object. It always passes its stateto the data access object and lets the dataaccess object worry about persistence issues.

BEST PRACTICE: Use mementos to passcomponent state between application tiers.

4.1.4 Object Caching

A database application must use the databaseas a persistent store not as a memory store. Inother words, you need to pull data from thedatabase and hold it in memory in businessobjects. If you go to the database every time

Page 212: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

you want to display some data about a businessobject, your database application will performterribly and fail to scale at all.

On the other hand, you don't want to load theentire database in memory and keep it there. Ifyou have a large amount of data, you will quicklyrun out of memory. It is therefore important todevelop an object caching mechanism thatstrikes a solid balance between memory usageand database access.

In architectures like the EJB architecture, theapplication server automatically managescaching for you. The Guest Book later in thischapter, however, does not use EJBs. Ittherefore needs something else to managecaching. It leverages a Cache class that uses aSoftReference to cache objects loaded from thedatabase.

BEST PRACTICE: If you are building your ownpersistence system, implement an efficientcaching scheme to prevent exhaustingsystem resources.

A SoftReference is a special kind of object injava.lang.ref that creates a soft reference to the

Page 213: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

object it stores. In Java, references betweenobjects are generally strong references. Forexample:

StringBuffer buffer = new StringBuffer( );

The reference to buffer is a strong reference. Thestrong reference is in force as long as thereference is in scope. If the references fall out ofscope, then the object is said to be no longerstrongly reachable. It is thus potentiallyavailable for garbage collection.

A soft reference is a reference via a SoftReferenceobject. By storing an object indirectly through aSoftReference instead of directly, you make theobject available for potential garbage collectionwhile still maintaining the ability to access theobject until it is garbage collected.

The Cache class implements the Java Collectioninterface. Internally, it even uses a HashMapinternally to store data. When an applicationloads an object from the database, it can put itin the cache using the cache( ) method:

public void cache(Object key, Object val) { cache.put(key, new SoftReference(val));}

Page 214: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

This method creates a soft reference around thebusiness object and then stores the softreference in the internal HashMap. As time goesby and the business object is no longer in use,the soft reference will expire and the memorythe business object occupies will be freed. Thecode that checks for the existence of a specificbusiness object in the cache thus needs to verifythat the soft reference has not expired:

public boolean contains(Object ob) { Iterator it = cache.values( ).iterator( ); while( it.hasNext( ) ) { SoftReference ref = (SoftReference)it.next( ); Object item = ref.get( ); if( item != null && ob.equals(item) ) { return true; } } return false;}

The get( ) method has to perform similar checks:

public Object get(Object key) { SoftReference ref = (SoftReference)cache.get(key); Object ob;

Page 215: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

if( ref = = null ) { return null; } ob = ref.get( ); if( ob = = null ) { release(key); } return ob;}

Page 216: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

4.2 A Guest Book Application

To illustrate these most fundamental persistenceconcepts, I will use a simple Guest Book JSPapplication from my web site. You can see thisexample in action athttp://george.reese.name/guestbook.jsp. TheGuest Book enables visitors to a web site toleave comments and view the comments left byothers. To prevent abuse, the application alsoincludes an administrative approval mechanism.The full code for the Guest Book can be found onO'Reilly's FTP site.

In accordance with the common persistencedesign patterns described earlier in the chapter,this application divides into view, control,business, data access, and data storage logic.Figure 4-1 is a UML class diagram illustratingthis division.

Figure 4-1. A UML class diagramfor the Guest Book application

Page 217: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The view and control logic exist in two separateJSP pages. These JSP pages reference a Commentobject containing the business logic. They areblissfully ignorant of any persistence logic or ofthe existence of persistence at all. The Commentobject, however, knows only that its data ispersisted, but not how that data is persisted,because it delegates its data access through aCommentDAO data access object.

I have chosen here to break down the dataaccess even further, into individual objectssupporting specific database operations. W ithoutthis trick, the data access object fills up with ajumble of SQL and JDBC that becomes difficult tomanage.

4.2.1 The View

The view is a JSP page that displays a form andthen lists all approved comments. Example 4-1contains the code for this JSP.

Page 218: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Example 4-1. A JSP view that listscomments and accepts new ones

<%@ page info="Guest Book Form" %> <%@ page import="java.util.ArrayList" %><%@ page import="org.dasein.gb.Comment" %> <%@ taglib uri="/WEB-INF/tlds/dasein.tld" prefix="dasein" %> <jsp:useBean id="user" scope="session" class="org.dasein.security.User"/> <% pageContext.setAttribute("user", user); %> <% String d = request.getParameter("done"); %><% boolean done = ((d= =null) ? false : d.trim( ).equalsIgnoreCase("true")); %><% String email, name, comment; %> <% email = request.getParameter(Comment.EMAIL); %><% name = request.getParameter(Comment.NAME); %><% comment = request.getParameter(Comment.COMMENT); %><% if( user != null ) { %> <% String fn = user.getFirstName( ); %> <% String ln = user.getLastName( ); %> <% name = ((fn = = null) ? "" : (fn + " ")) + ((ln = = null) ? "" : ln); %> <% email = user.getEmail( ); %><% } %><% if( email = = null ) { %> <% email = ""; %><% } else { %> <% email = email.trim( ); %><% } %><% if( name = = null ) { %> <% name = ""; %><% } else { %> <% name = name.trim( ); %><% } %><% if( comment = = null ) { %> <% comment = ""; %><% } else { %> <% comment = comment.trim( ); %>

Page 219: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<% } %> <% String err = request.getParameter("errorID"); %><% if( err != null ) { %> <% err = err.trim( ); %> <% if( err.length( ) < 1 ) { %> <% err = null; %> <% } %><% } %><% if( err != null ) { %> <dasein:printError/><% } else if( done ) { %> <p class="text"> Thank you for your comment! I will review the comment. Assuming you did nothing offensive, it will appear below after I review it. </p><% } %><% if( !done ) { %> <p class="text"> <form method="POST" action="guestbook-action.jsp"> <label class="text" for="<%=Comment.NAME%>">Name:</label> <input id="<%=Comment.NAME%>" type="text" name="<%=Comment.NAME%>" value="<%=name%>" size="25"/> <br/><br/> <label class="text" for="<%=Comment.EMAIL%>">Email:</label> <input id="<%=Comment.EMAIL%>" type="text" name="<%=Comment.EMAIL%>" value="<%=email%>" size="25"/> <br/><br/> <label class="text" for="<%=Comment.COMMENT%>">Comments:</label> <br/> <textarea id="<%=Comment.COMMENT%>" name="<%=Comment.COMMENT%>" wrap="virtual" rows="10" cols="60"/><dasein:clean><%=comment%></dasein:clean></textarea> <br/> <input type="submit" value="Submit"/> </form> </p><% } %><h3 class="section">Comments</h3><dl class="guestbook"> <% ArrayList cmts = Comment.getApproved( ); %> <% pageContext.setAttribute("cmts", cmts); %> <dasein:foreach id="cmt" source="cmts" className="org.dasein.gb.Comment"> <dt>On <%= cmt.getCreated( ) %>, <%=cmt.getName( )%> wrote:</dt> <dd><%=cmt.getComment( )%></dd>

Page 220: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

</dasein:foreach></dl>

The first part of this example pulls CGI (CommonGateway Interface) parameters into Javavariables. It is specifically looking for all of theform fields as well as a done parameter and anerrorID parameter. As we will see in thecontroller, whenever an error occurs, it sets theerrorID parameter and redisplays the view. If anyfield values are passed in, it uses those valuesas default values for the form. On success, it willredisplay the list of comments minus the form.

After the initial parameter parsing logic, itdisplays a form unless the done parameter wasset. Finally, the page uses a tag librarycontaining a looping construct in the form of thedasein:foreach tag. For each comment it pulls fromthe Comment.getApproved( ) call, it displays thedata from the comment.

4.2.2 The Controller

The form from the view posts to the controllerpage. Example 4-2 shows this simple code.

Example 4-2. The Guest Bookcontroller that handles newcomments

<%@ page info="Guest Book Action" %> <%@ taglib uri="/WEB-INF/tlds/dasein.tld" prefix="dasein" %><%@ taglib uri="/WEB-INF/tlds/guestbook.tld" prefix="guestbook" %> <%@ page import="org.dasein.jsp.Log" %> <guestbook:addComment error="error"> <% response.sendRedirect("guestbook-form.jsp?done=true"); %></guestbook:addComment>

Page 221: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<dasein:isNull name="error"> <dasein:when state="false"> <jsp:include page="guestbook-form.jsp"> <jsp:param name="errorID" value="<%=Log.storeException(error)%>"/> </jsp:include> </dasein:when></dasein:isNull>

The complexity of this action controller is hiddeninside a couple of tag libraries. The first is theguestbook:addComment tag. It triggers the actionof adding a new comment to the database. Onsuccess, the body of the comment is executed.In this case, the body of the comment redirectsto the view page with the done parameter set.

BEST PRACTICE: Delegate controller logic inJavaServer Pages through custom tags.

The special tag dasein:isNull will execute the bodyof the tag if the specified value in this case,erroris a null value. In this page, error will be nullonly if an error occurred while attempting to adda comment. It therefore stores the errormessage for later retrieval and displays the viewpage again so that the user may correct theerror.

As you can see from this simple page, acontroller does not do much in and of itself. Itsimply acts as a traffic cop, determining whatshould actually happen in response to a useraction. In this case, it triggers an event in thebusiness object through a tag library. The codein the tag library is shown in Example 4-3.

Example 4-3. A custom tag totrigger business logic

public int doStartTag( ) throws JspException {

Page 222: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

try { ServletRequest request = pageContext.getRequest( ); String name = request.getParameter(Comment.NAME); String email = request.getParameter(Comment.EMAIL); String comment = request.getParameter(Comment.COMMENT); HashMap data = new HashMap( ); Comment cmt; if( name != null ) { name = name.trim( ); if( name.length( ) < 1 ) { name = null; } } if( name = = null ) { if( error != null ) { pageContext.setAttribute(error, NO_NAME); error = null; return SKIP_BODY; } else { throw new JspException(NO_NAME); } } data.put(Comment.NAME, name); if( email != null ) { email = email.trim( ); if( email.length( ) < 1 ) { email = null; } } data.put(Comment.EMAIL, email); if( comment != null ) { comment = comment.trim( ); if( comment.length( ) < 1 ) { comment = null; } } if( comment = = null ) { if( error != null ) { pageContext.setAttribute(error, NO_COMMENT); error = null; return SKIP_BODY; } else {

Page 223: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

throw new JspException(NO_COMMENT); } } data.put(Comment.COMMENT, comment); cmt = Comment.create(data); pageContext.setAttribute(error, null); return EVAL_BODY_TAG; } catch( PersistenceException e ) { if( error != null ) { pageContext.setAttribute(error, "<p class=\"error\">" + e.getMessage( ) +"</p>"); error = null; return SKIP_BODY; } else { throw new JspException(e.getMessage( )); } }}

This tag library reads all of the form parametersand validates them. If they are not valid values,it sets an error value and ignores its body. Validvalues are stuck in a HashMap that acts as amemento. This memento is then passed to theComment.create( ) method to create a newcomment in the database.

4.2.3 The Business Object (Model)

Business objects form the heart of any majorapplication. They model the underlying conceptsof the application's problem domain. In the caseof the Guest Book, the underlying concepts areusers and the comments they leave behind. Forsimplicity's sake, we are not capturing users asobjects in this system. In a more complexsystem, we probably would.

The only business object being modeled here,then, is the Comment object. The guestbook-form.jsp view is, in short, a view of Commentobjects. The Comment business object

Page 224: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

encapsulates everything there is about being acomment. It stores comment data captured inthe comment forms and manages the creation,deletion, approval, and retrieval of comments.These operations have two elements:

Metaoperations such as creation andretrieval of comments via static methods

Object-specific operations via instancemethods

Example 4-4 contains the meta-operations.

Example 4-4. The metaoperationsof the Comment business object

package org.dasein.gb; import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.Iterator; import org.dasein.gb.persist.CommentDAO;import org.dasein.persist.PersistenceException;import org.dasein.persist.Sequencer;import org.dasein.util.Cache; public class Comment { static private final Cache cache = new Cache( ); static public final String APPROVED = "approved"; static public final String COMMENT = "comment"; static public final String COMMENT_ID = "commentID"; static public final String CREATED = "created"; static public final String EMAIL = "email"; static public final String NAME = "name"; static public Comment create(HashMap data) throws PersistenceException { Sequencer seq = Sequencer.getInstance(Comment.COMMENT_ID); Comment cmt;

Page 225: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Long id; id = new Long(seq.next( )); data.put(Comment.COMMENT_ID, id); CommentDAO.create(data); cmt = new Comment(id, data); synchronized( cache ) { cache.cache(id, cmt); } return cmt; } static public ArrayList getApproved( ) throws PersistenceException { Iterator results = CommentDAO.getApproved( ).iterator( ); ArrayList cmts = new ArrayList( ); while( results.hasNext( ) ) { Long id = (Long)results.next( ); cmts.add(Comment.getComment(id.longValue( ))); } return cmts; } static public Comment getComment(long cid) throws PersistenceException { Long id = new Long(cid); synchronized( cache ) { Comment cmt = (Comment)cache.get(id); if( cmt = = null ) { HashMap data = CommentDAO.getComment(cid); data.put(Comment.COMMENT_ID, id); cmt = new Comment(id, data); cache.cache(id, cmt); } return cmt; } } static public ArrayList getPending( ) throws PersistenceException { Iterator results = CommentDAO.getPending( ).iterator( ); ArrayList cmts = new ArrayList( );

Page 226: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

while( results.hasNext( ) ) { Long id = (Long)results.next( ); cmts.add(Comment.getComment(id.longValue( ))); } return cmts; }}

In addition to representing a comment, theComment class acts as a factory that containsfour meta-operations:

create( )

Creates new comment objects

getApproved( )

Retrieves all approved comments

getComment( )

Retrieves a specific comment by itscomment ID

getPending( )

Retrieves all comments awaiting approval

The central data element for these operations isthe comment cache stored in the static cacheattribute. This cache uses the Cache classdescribed earlier in the chapter. Whenever acomment is sought externally, this cache ischecked first to see if the desired Commentinstance has already been loaded. If not, theclass will go to the data access object to load anew instance from the database. Otherwise, we

Page 227: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

can avoid a costly trip to the database and pullthe object straight from the cache.

BEST PRACTICE: Always define literal valuesin constants.

You probably also notice the constants definedat the top of the class. We saw them referencedearlier in the view page. It is simply a solidcoding practice never to use literals in code.Instead, you should use constants like these tohelp avoid application bugs caused by spellingerrors.

private Boolean approved = null; private String comment = null; private Long commentID = null; private Date created = null; private String email = null; private String name = null; private Comment(Long cid, HashMap data) { super( ); commentID = cid; load(data); } public String getComment( ) { return comment; } public long getCommentID( ) { return commentID.longValue( ); } public Date getCreated( ) { return created; } public String getEmail( ) { return email; }

Page 228: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public String getName( ) { return name; } public boolean isApproved( ) { return approved.booleanValue( ); } private void load(HashMap data) { approved = (Boolean)data.get(Comment.APPROVED); comment = (String)data.get(Comment.COMMENT); commentID = (Long)data.get(Comment.COMMENT_ID); created = (Date)data.get(Comment.CREATED); email = (String)data.get(Comment.EMAIL); name = (String)data.get(Comment.NAME); } public void remove( ) throws PersistenceException { HashMap data = new HashMap( ); data.put(Comment.COMMENT_ID, commentID); CommentDAO.remove(data); synchronized( cache ) { cache.release(commentID); } } public void save(HashMap data) throws PersistenceException { data.put(Comment.COMMENT_ID, commentID); CommentDAO.save(data); load(data); }}

The instance operations are largely simple gettermethods. The exceptions are the following:

load( )

The load method pulls data from ourHashMap memento and assigns that data toinstance variables.

Page 229: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

remove( )

The remove( ) method deletes the object andremoves it from the cache.

save( )

The save( ) method tells the data accessobject to save changes to the comment.

The most critical thing to notice about thebusiness object is that it hides all knowledgeabout persistence from the view and thecontroller. The view and controller simply do notneed to know if the object persists or how itpersists. In fact, the business object knows onlythat it persists it knows nothing about how itpersists. That knowledge is saved for the dataaccess objects.

4.2.4 The Data Access Objects

The data access object, CommentDAO, provides asimple interface to the business object forpersisting comments to the database. In short,it has methods to load, delete, update, andcreate comments. When the methods requiredata from the comment, the data is passed via amemento. They throw generic persistenceexceptions. The data access object thus needsto know nothing about the internal structure ofcomments, and comments need to know nothingabout the persistence details of the data accessobject. Example 4-5 contains the code for theCommentDAO class.

Example 4-5. The CommentDAOdata access object

Page 230: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

package org.dasein.gb.persist; import java.util.ArrayList;import java.util.HashMap; import org.dasein.gb.Comment;import org.dasein.persist.Execution;import org.dasein.persist.PersistenceException; public abstract class CommentDAO { static public void create(HashMap data) throws PersistenceException { CreateComment.getInstance( ).execute(data); } static public ArrayList getApproved( ) throws PersistenceException { HashMap data = new HashMap( ); data.put(Comment.APPROVED, new Boolean(true)); data = ListComments.getInstance( ).execute(data); return (ArrayList)data.get(ListComments.COMMENTS); } static public HashMap getComment(long cid) throws PersistenceException { HashMap data = new HashMap( ); data.put(Comment.COMMENT_ID, new Long(cid)); data = LoadComment.getInstance( ).execute(data); return data; } static public ArrayList getPending( ) throws PersistenceException { HashMap data = new HashMap( ); data.put(Comment.APPROVED, new Boolean(false)); data = ListComments.getInstance( ).execute(data); return (ArrayList)data.get(ListComments.COMMENTS); } static public void save(HashMap data) throws PersistenceException { SaveComment.getInstance( ).execute(data); } static public void remove(HashMap data) throws PersistenceException { RemoveComment.getInstance( ).execute(data); }

Page 231: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

}

This data access object further delegates tooperation-specific objects to avoid clutter in thisclass.

4.2.4.1 Loading comments

These delegates use the framework I describedearlier in the chapter. Example 4-6 shows theLoadComment delegate that performs the SQL toload a comment from the database.

Example 4-6. Loading a commentthrough a special delegate

package org.dasein.gb.persist; import java.sql.SQLException;import java.util.HashMap; import org.dasein.gb.Comment;import org.dasein.persist.Execution;import org.dasein.persist.PersistenceException; public class LoadComment extends Execution { static public LoadComment getInstance( ) { return (LoadComment)Execution.getInstance(LoadComment.class); } static private final String LOAD = "SELECT approved, email, name, comment, created " + "FROM Comment " + "WHERE Comment.commentID = ?"; static private final int COMMENT_ID = 1; static private final int APPROVED = 1; static private final int EMAIL = 2; static private final int NAME = 3; static private final int COMMENT = 4;

Page 232: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

static private final int CREATED = 5; public HashMap run( ) throws PersistenceException, SQLException { long id = ((Long)data.get(Comment.COMMENT_ID)).longValue( ); HashMap res = new HashMap( ); String tmp; statement.setLong(COMMENT_ID, id); results = statement.executeQuery( ); if( !results.next( ) ) { throw new PersistenceException("No such comment: " + id); } tmp = results.getString(APPROVED); res.put(Comment.APPROVED, new Boolean(tmp.trim( ).equalsIgnoreCase("Y"))); tmp = results.getString(EMAIL); if( results.wasNull( ) ) { res.put(Comment.EMAIL, null); } else { res.put(Comment.EMAIL, tmp.trim( )); } res.put(Comment.NAME, results.getString(NAME)); res.put(Comment.COMMENT, results.getString(COMMENT)); res.put(Comment.CREATED, results.getDate(CREATED)); return res; } public String getDataSource( ) { return "jdbc/george"; } public String getStatement( ) { return LOAD; }}

You should notice here again the liberal use ofconstants instead of literals throughout thecode. This practice is very important in JDBCprogramming since the most efficient way toaccess columns in a result set is by columnnumber.

Page 233: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BEST PRACTICE: Access JDBC columns bynumber and use constants to keep thosecolumn values readable and maintainable.

The code executes a SQL SELECT and places theresult into a memento. That memento goes backto the calling business object, which then sendsit through the business object's load( ) method. Ifa JDBC error or some other exception occurs, theexception will be wrapped up in aPersistenceException and sent back to the callingbusiness object.

4.2.4.2 Sequence generation

Throughout this book, I reference the bestpractice of relying on your own, database-independent primary key generation mechanism.No discussion of the data access tier would becomplete without a discussion of primary keygeneration.

Every database engine provides a feature thatenables applications to automatically generatevalues for identity columns. MySQL, for example,has the concept of AUTO_INCREMENT columns:

CREATE TABLE Person ( personID BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, lastName VARCHAR(30) NOT NULL, firstName VARCHAR(25) NOT NULL);

When you insert a new person into this table,you omit the primary key columns:

INSERT INTO Person ( lastName, firstName)VALUES ( 'Wittgenstein', 'Ludwig' );

MySQL will automatically generate the value forthe personID column based on the highest currentvalue. If one row exists in the database with apersonID of 1, Ludwig W ittgenstein's personID willbe 2. Some other databases have similar ways

Page 234: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

be 2. Some other databases have similar waysto generate primary keys; others provide wildlydifferent tools.

Reliance on your database engine's primary keygeneration tools has the following drawbacks:

Every database engine handles keygeneration differently. It is thus difficult tobuild a truly portable JDBC application thatuses proprietary key generation schemes.

Until JDBC 3.0, a Java application had noclear way of finding out what keys weregenerated on an insert.

In many databases, you can autogenerateonly a single unique value per table.

In many databases, you cannot use theprimary key generation mechanism togenerate values unique across multipletables.

I recommend the development of a database-independent primary key generation API thatstores potential primary key values in thedatabase. If you take this approach, you need totake care not to make too many trips to thedatabase. You can avoid this pitfall bygenerating keys in memory and storing seedvalues in the database.

The heart of this database-independent schemeis the following table:

CREATE TABLE Sequencer ( name VARCHAR(20) NOT NULL, seed BIGINT UNSIGNED NOT NULL, lastUpdate BIGINT UNSIGNED NOT NULL, PRIMARY KEY ( name, lastUpdate ));

The first time your application generates a key,it grabs the next seed from this table,

Page 235: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

increments the seed, and then uses that seed togenerate keys until the seed is exhausted.Example 4-7 through Example 4-9 contain someof the code for a database-independent utilitythat handles unique number generation. Itenables your application to simply use thefollowing calls to create primary keys:

Sequencer seq = Sequencer.getInstance("personID"); personID = seq.next( );

The tool guarantees that you will receive a valuethat is unique across all personID values.Example 4-7 contains the static elements thatimplement the singleton design pattern to handout shared sequencers.

Example 4-7. The code to serve upsequencers

public class Sequencer { static private final long MAX_KEYS = 1000000L; static private final HashMap sequencers = new HashMap( ); static public final Sequencer getInstance(String name) { synchronized( sequencers ) { if( !sequencers.containsKey(name) ) { Sequencer seq = new Sequencer(name); sequencers.put(name, seq); return seq; } else { return (Sequencer)sequencers.get(name); } } } ...}

The code provides two critical guarantees for

Page 236: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

sequence generation:

All code that needs to create new numbersfor the same sequence (like personID) willshare the same sequencer object.

Because of the synchronized block, twoattempts to get a previously unreferencedsequence at the same instant will not causetwo different sequencers to be generated.

The attribute declarations and initialization for asequencer define two attributes that correspondto values in the Sequencer table as well as a thirdattribute, sequence, to track the values handedout for the current seed, as shown in Example 4-8.

Example 4-8. Setting up thesequencer

private String name = null;private long seed = -1L;private long sequence = 0L; private Sequencer(String nom) { super( ); name = nom;}

The core element of the sequencerits publicAPI is the next( ) method. It contains thealgorithm for generating unique numbers. Thealgorithm has the following process:

Check to see if the seed is valid. The seedis invalid if this is a newly generatedsequencer or if the seed is exhausted. Aseed is exhausted if the next sequence hasa value greater than MAX_KEYS.

If the seed is not valid, get a new seed

Page 237: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

from the database.

Increment the sequence.

Multiply the seed by MAX_KEYS and add thatvalue to the incremented sequence. This isthe unique key.

Example 4-9 contains the algorithm.

Example 4-9. Generating asequence ID

public synchronized long next( ) throws PersistenceException { Connection conn = null;

// when seed is -1 or the keys for this seed are exhausted, // get a new seed from the database if( (seed = = -1L) || ((sequence + 1) >= MAX_KEYS) ) { try { String dsn = System.getProperty(DSN_PROP, DEFAULT_DSN); InitialContext ctx = new InitialContext( ); DataSource ds = (DataSource)ctx.lookup(dsn);

conn = ds.getConnection( ); reseed(conn); } catch( SQLException e ) { throw new PersistenceException(e); } catch( NamingException e ) { throw new PersistenceException(e); } finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } } } // up the sequence value for the next key sequence++;

Page 238: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

// the next key for this sequencer return ((seed * MAX_KEYS) + sequence);}

The rest of the code is the database access thatcreates, retrieves, and updates seeds in thedatabase. The next( ) method triggers a databasecall via the reseed( ) method when the seedceases to be valid.

The logic for reseeding the sequencer is fairlystraightforward:

Fetch the current values for the sequence inquestion from the database.

If the sequence does not yet exist in thedatabase, create it.

Increment the seed from the database.

Update the database

Set the new seed and reset the sequenceattribute to -1 (this makes the first numbergenerated 0).

You can find the full code for the Sequencer classon O'Reilly's FTP site in the directory for thisbook.

Page 239: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 240: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 5. EJB CMPBlessed are the sleepy ones: for they shallsoon doze off.

Friedrich Nietzsche, Also Sprach Zarathustra

Container-managed persistence (CMP) is apersistence model in which the EJB containerworries about persistence issues while you worryabout business logic management. Under theCMP model, you leave most of the EJBpersistence methods ejbFindXXX( ), ejbLoad( ),ejbStore( ), and ejbRemove( )empty. Based on amapping you define in the application'sdeployment descriptor, the container implementsthose methods and crafts the SQL to map yourbeans to the database.

EJB 2.0 CMP is a drastic departure from andimprovement upon EJB 1.0 CMP. Nevertheless,the majority of systems in production these daysare still in EJB 1.x environments. This chaptertakes a look at both CMP models and describeshow to use them in a production environment. Aswith any automated persistence mechanism,there is not a lot that EJB CMP requires you asthe developer to do. The focus for this chapter is

Page 241: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

specifically on the aspects of the EJB 1.0 andEJB 2.0 CMP models that most impactpersistence issues. Once you understand theseconcepts, you will find that you are left withalmost no persistence coding to do under EJBCMP all your work lies in setting up the databaseand writing deployment descriptors.

This chapter assumes you have a basicunderstanding of Enterprise JavaBeans. Itspecifically assumes that you know thedifference between entity and session beans andare familiar with home interfaces, remoteinterfaces, and implementation objects. If youdo not have this background, you should reviewthe Enterprise JavaBeans section of Chapter 9. Ialso strongly recommend the book EnterpriseJavaBeans (O'Reilly) by Richard Monson-Haefel ifyou intend to do serious programming in an EJBenvironment.

Page 242: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

5.1 Which CMP Model to Use?

While container-managed persistence soundsgreat, the initial EJB implementations of CMPthrough EJB 1.1 have had some seriousdrawbacks:

Most EJB servers will provide automatedpersistence only against JDBC-supporteddatabase engines. If you are using someother data storage product like an object-oriented database or a specialized digitalasset management data store, you willhave to do the work yourself.

Container-managed persistence demandsthat your persistent attributes have publicvisibility. Public attributes violate a keyelement of good OO design: encapsulation.Consequently, container-managed beansmake it very easy for people to make poordesign choices that rely on the public natureof those attributes.

Container-managed persistence makes itdifficult to tweak your data model formaximum performance. For example, if you

Page 243: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

maximum performance. For example, if youwant to perform lazy-loading of certainattributes, you must use bean-managedpersistence.

Container-managed persistence is incapableof supporting the complex classrelationships common to enterprisesystems. For example, container-managedpersistence cannot support some one-to-many or many-to-many relationships. Ifyour analysis models require those kinds ofrelationships, your architecture must use analternative persistence model.

Lazy-loading is a technique through whichcertain attributes in an object are notrestored from the database immediately butare instead restored in a background threador when the system asks for that data. ACountry object, for example, may beassociated w ith quite a few cities likely morecities than you want to load into memorywhen most clients are looking only for thename and ISO code for the country. Usinglazy-loading, you can put off loading allassociated cities until a later time.

In spite of its drawbacks, EJB 1.x CMP does have

Page 244: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

some redeeming qualities. Specifically, it is agreat tool if you are writing a simple applicationbut you do not want to worry about the databaseat all. By simple application, I mean anapplication that has no complex dependenciesamong entity beans and whose attributes areprimitives or serializable objects. The minute theslightest complexity enters the picture or youneed to control the data model, EJB 1.x CMPfalls apart.

BEST PRACTICE: Use CMP especially EJB 2.0CMP whenever possible, but be prepared touse BMP if EJB 2.0 CMP is not an option.

Page 245: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

5.2 The EJB 1.0 CMP Model

EJB 1.x CMP generates the code to mappersistent entity bean fields to columns in arelational database. Under this model, you canmap only Java primitives and serializable fields.You cannot, for the most part, map entity beansor any other nonserializable Java object. Table5-1 shows the attributes of two analysis-levelbusiness objects: an Author class and a Bookclass.

Table 5-1. The attributes of two businessobjects and EJB 1.x CMP's ability to manage

them

Class Attribute Type Manageable by EJB 1.x CMP?

Author authorID long Yes

firstName String Yes

lastName String Yes

Book bookID long Yes

author Author No

t it le String Yes

EJB 1.1 introduced the ability to map entity beanreferences to the database. The actualimplementation of this support, unfortunately,varies from container to container. As a general

Page 246: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

rule, you should store the primary keys of anyentity bean references and let the request objectmap it to the entity reference. The Book bean inTable 5-1, for example, could have an authorIDfield instead of an author field. Example 5-1shows this approach.

Example 5-1. A container-managed Book bean thatreferences an Author bean

package book; import javax.ejb.EntityBean;import javax.ejb.EntityContext; public class BookEntity implements EntityBean { public Long authorID;

public Long bookID; public EntityContext context; public String title; public void ejbActivate( ) { } public Long ejbCreate(Long bid, Long aid, String ttl) { bookID = bid; authorID = aid; title= ttl; return null; } public void ejbLoad( ) {

Page 247: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} public void ejbPassivate( ) { } public void ejbPostCreate(Long bid, Long aid, String ttl) { } public void ejbRemove( ) { } public void ejbStore( ) { } public Long getAuthorID( ) {return authorID;} public Long getBookID( ) { return bookID; } public String getTitle( ) { return title; } public void setEntityContext(EntityContext ctx) { context = ctx; } public void unsetEntityContext( ) { context = null; }}

I will discuss the details of this class later. If Ihave code that needs the author of the book, Ican get the authorID and then request the Author

Page 248: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

by its primary key:

public Author getBookAuthor(Book book) throws Exception { Context ctx = new InitialContext( ); Object ref = ctx.lookup("java:comp/env/Author"); AuthorHome home = (AuthorHome)PortableRemoteObject.narrow(ref, AuthorHome.class); return home.findByPrimaryKey(book.getAuthorID( ));}

This approach has two virtues. First, it avoidsthe lack of ability in EJB 1.x CMP to mapbetween entities. Second, it creates the sameeffect as lazy-loading by loading the Author onlywhen a client actually needs access to it.

5.2.1 Field Mapping

One of the weaknesses in the EJB 1.x CMP modellies in how it maps attributes to the database.Each container provides its own mechanism fordefining the mapping between an entity beanand a table. In most cases, you can use a GUItool that enables you to relate a bean attributeto a relational column. If you do not care at allabout the underlying data model, you can simplywrite up an XML deployment descriptor thatenumerates the entity attributes to be mapped.Example 5-2 shows a sample deploymentdescriptor.

Example 5-2. A sample EJBdeployment descriptor

Page 249: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<?xml version="1.0"?><!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.2//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_2.dtd"> <ejb-jar> <description> </description> <enterprise-beans> <entity> <description> </description> <ejb-name>BookBean</ejb-name> <home>book.BookHome</home> <remote>book.Book</remote> <ejb-class>book.BookEntity</ejb-class> <primkey-class>java.lang.Long</primkey-class> <reentrant>False</reentrant> <persistence-type>Container</persistence-type> <cmp-field><field-name>bookID</field-name></cmp-field> <cmp-field><field-name>title</field-name></cmp-field> <cmp-field><field-name>authorID</field-name></cmp-field> <primkey-field>bookID</primkey-field> </entity> <entity> <description> </description> <ejb-name>AuthorBean</ejb-name> <home>book.AuthorHome</home> <remote>book.Author</remote> <ejb-class>book.AuthorEntity</ejb-class> <primkey-class>java.lang.Long</primkey-class> <reentrant>False</reentrant> <persistence-type>Container</persistence-type> <cmp-field><field-name>authorID</field-name></cmp-field> <cmp-field><field-name>firstName</field-name></cmp-field>

Page 250: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<cmp-field><field-name>lastName</field-name></cmp-field> <primkey-field>authorID</primkey-field> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>BookBean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>AuthorBean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor></ejb-jar>

This deployment descriptor tells your containerthat you have created an entity bean with thespecified home, remote, and implementationclasses. The fields in the <cmp-field> tagsidentify which BookEntity attributes should persistto your database.

If you deploy this simplistic application on anOrion Server, it will create a BookBean table inyour database and set up bookID, title, andauthorID columns for you with bookID establishedas the primary key. You do not have to write anyJDBC code. You do not have to write any SQL.You do not have to create any tables.

Page 251: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

If you have a data model constructed already,you will need to use the proprietary tools thatcome with your J2EE container to map the beanto the data model. In the case of Orion Server,for example, you can create an orion-ejb-jar.xmlfile to handle custom mappings. Most applicationservers provide a GUI to help identify themappings.

5.2.2 Persistence Methods

If you look back to Example 5-1, you will noticethat most of the methods required for an EJBentity bean are empty. They are empty becausethe container is handling the persistenceoperations for you. The persistence operationsthat generally contain code under a CMP modelare the ejbCreate( ) and ejbPostCreate( ) methods.

The container passes both methods the valuesspecified by the client. It calls ejbCreate( ) beforepersisting the bean to the database andejbPostCreate( ) afterward. Assuming you have nobusiness logic associated with object creation,the responsibility of ejbCreate( ) is to assign theinitial values to the bean:

public Long ejbCreate(Long bid, Long aid, String ttl) { bookID = bid; authorID = aid; title= ttl; return null;}

The return value has no meaning under CMP. Youshould therefore return null as I did in the

Page 252: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

BookEntity class.

You must make sure you assign the primary keyvalue in all ejbCreate( ) methods. Youconsequently cannot rely on any underlyingdatabase tools, such as the MySQLAUTO_INCREMENT feature, to generate primarykeys. At the end of Chapter 4, I introduced adatabase-independent approach to generatingunique values. This approach uses a Sequencerobject to generate unique long values. TheAuthorEntity class takes advantage of theSequencer:

public Long ejbCreate(String fn, String ln) throws CreateException { try { Sequencer seq = Sequencer.getInstance(AUTHOR_ID); authorID = new Long(seq.next( )); } catch( PersistenceException e ) { throw new CreateException(e.getMessage( )); } firstName = fn; lastName = ln; return null;}

Instead of requiring the client to worry aboutprimary key generation, the burden has beenplaced where it belongs inside the creation logicfor the bean.

BEST PRACTICE: Perform primary keygeneration in your CMP EJB instead of theclient.

Page 253: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The container calls ejbPostCreate( ) once the beanis established as a persistent entity to enableyou to perform any extra initialization. The statediffers at the time of ejbCreate( ) in twosignificant ways:

A record is inserted into the database orother persistent store between the twocalls.

The association between the bean and theEJB object is established between the twocalls.

5.2.3 Searches

One of the great weaknesses of EJB 1.x CMP isits poor support for searching on anything butthe primary key. To search for a book with aspecific title, for example, you would add afinder method to your home interface:

Collection findByTitle(String ttl) throws RemoteException, FinderException;

The good news is that you do not have to codeanything other than the basic search signature inthe home interface. The bad news is that thereis no container-neutral method for telling an EJBcontainer exactly what findByTitle( ) is supposedto do. Is it supposed to look for exact matches?Is the ttl value being passed a regularexpression? The only thing a container knowsfrom a finder method signature is whether thatmethod is expected to find a unique value or

Page 254: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

multiple hits. The EJB 1.x specifications saynothing about how a container is supposed toidentify what you mean to search for. As aresult, you must rely on proprietary deploymenttools to assist the container in defining your EJBfinder methods.

5.2.4 Transactions

Without being flip, I believe it is safe to saythat if you need complex transactions youprobably should not be using EJB 1.x CMP youshould instead be using 2.x CMP or BMP. Youdescribe the level of transaction support yourbeans need in the EJB deployment descriptor.The deployment descriptor in Example 5-2 hadno transaction support. Indeed, this simpleapplication needed no transaction support.

EJB lets you specify the transactioncharacteristics of beans on a method-by-methodbasis as part of the deployment descriptor. Thedeployment descriptor approach is calleddeclarative transaction management. Declarativetransaction management is a huge advantage ofall EJB persistence models. Whereas most othermodels require the programmer to managetransaction semantics in code the hardest part ofdatabase programming EJB does not require theprogrammer to understand anything abouttransaction semantics. Only the deployer needsto worry about such things, and the deployer cantweak the transactional attributes of the systemwithout modifying and recompiling code.

Page 255: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

If you are unfamiliar w ith the basic conceptsof transaction management, now is anexcellent time to go back and read Chapter 3.

When you deploy a bean entity or session youassign it a transactional attribute in thedeployment descriptor. The transactionalattribute tells the container how to handletransactions for that bean. You can even assigndifferent transactional attributes to differentmethods within the bean if you desire that levelof control. The transactional attributes are:

NotSupported

No transaction scope is propagated to themethod. In other words, if this method iscalled in the middle of another transaction,that transaction is suspended to allow thismethod to execute. No transactionalcontext exists for any calls made within thismethod. Once this method completes, theoriginal transaction resumes.

Supports

This attribute says that the method inquestion will act with whatever transactionscope it is executed in. If not called in anexisting transactional scope, it will notattempt to create one.

Page 256: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Required

A method with a Required attribute must beexecuted in a transactional context. If notcalled in an existing transactional context,it will initiate a new one.

RequiresNew

No matter what context in which themethod in question is called, this methodwill create a new transaction context. It willsuspend any existing transactional contextuntil it completes.

Mandatory

The method in question can never initiateits own transactional context it must alwaysoccur inside a caller's transactional context.If it is called without any transactionalcontext, the container will throw anexception.

Never

The opposite of Mandatory, Never means thatthe method in question can never be calledinside a transactional context. If it is, thecontainer will throw an exception.

Page 257: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The transactional attributes in Example 5-2 werespecified in the following lines:

<container-transaction> <method> <ejb-name>BookBean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute></container-transaction><container-transaction> <method> <ejb-name>AuthorBean</ejb-name> <method-name>*</method-name> </method> <trans-attribute>NotSupported</trans-attribute></container-transaction>

This descriptor states that transactions for allmethods in both beans are not supported. If forsome reason a client calls them within atransactional context, that context will besuspended until the methods in these beanscomplete.

The <container-transaction> tag associates amethod with a transactional attribute. Inside the<method> tag, I use * for the method name toindicate that the attribute applies to all methodsin the specified bean. The <trans-attribute> tag isthe tag that identifies which transactionalattribute to assign. You can override a * valueby naming a specific method in a later <container-transaction> tag.

I have just touched on the basics of transactionmanagement in the EJB 1.x CMP persistencemodel. Much of the detail, however, applies both

Page 258: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

model. Much of the detail, however, applies bothto the BMP and EJB 2.x CMP persistence models,which are covered in the next section and laterin this chapter.

Page 259: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

5.3 The EJB 2.0 CMP Model

EJB 2.0 is a significant, revolutionaryimprovement over the original EJBspecification especially when it comes tocomponent persistence. Persistence changesinclude a more solid CMP architecture and aspecialized EJB query language (EJBQL) forperforming bean searches. Beyond persistence,EJB 2.0 provides for exciting features such asmessage-driven beans.

5.3.1 Container-Managed Relationships

Under EJB 1.x, container-managed persistencemeant the container managed keeping all beanattributes in sync with the data store. This jobbecame problematic for any attributesrepresenting relationships to other beans. Thegeneral solution was to store a primary key forthe relationship and let clients worry aboutreferencing the other bean.

EJB 2.0 introduces a concept called container-managed relationships, or CMR. A CMR field is abean attribute that is a relationship to anotherbean. CMR relationships can take any of thefollowing forms:

One-to-oneOne-to-manyMany-to-many

Page 260: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In addition, each relationship can beunidirectional or bidirectional. If, for example,the relationship between Author and Book isunidirectional, I can ask for all books by aspecific author but I cannot ask for the author ofa specific book. In other words, the Author beanhas a reference to its Book instances but theBook bean has no reference to its author. Ofcourse, it would be more appropriate for thisparticular relationship to be bidirectional,meaning that I can navigate from Author to Bookand Book to Author.

BEST PRACTICE: Try to make relationshipsunidirectional unless absolutely necessary.

5.3.1.1 CMR basics

You identify CMR relationships in yourdeployment descriptor inside the <relationships>tag. For each relationship, you specify an ejb-relation element:

<ejb-jar> ... <enterprise-beans> <entity> <ejb-name>BookEJB</ejb-name> <local-home>com.imaginary.ora.BookHome</local-home> <local>com.imaginary.ora.Book</local> <cmp-version>2.x</cmp-version> ...

Page 261: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

</entity> <entity> <ejb-name>AuthorEJB</ejb-name> <local-home>com.imaginary.ora.AuthorHome</local-home> <local>com.imaginary.ora.Author</local> <cmp-version>2.x</cmp-version> ... </entity> </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Book-Author</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> A Book has an Author </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <cascade-delete/> <relationship-role-source> <ejb-name>BookEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>author</cmr-field-name> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> An Author has many Books </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>AuthorEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>books</cmr-field-name>

Page 262: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

</cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> ...</ejb-jar>

Though for our purposes the bean declarationsthemselves are not relevant to persistence, Iincluded part of their declarations to show thatthe relationships section references by thenames you declare in the <ejb-name> tags underthe enterprise-beans element.

This deployment descriptor says that an authorhas many books and a book has one author. TheAuthor bean tracks its books via the CMR fieldbooks. Similarly, the Book bean tracks its authorby the author CMR field.

You must define a pair of accessor methods agetter and setterfor any CMR fields you declare.You declare these methods as abstract in thebean implementation class. The return type forthe getter and parameter for the setter is aCollection for the "many" side of a one-to-many ormany-to-many relationship. You can useimplementations of Collection to suit theunderlying needs of the relationship: TreeSetinstances for ordered lists, Set instances forunique lists, and so on. Similarly, the type forthe "one" side of a one-to-one or one-to-manyrelationship is the local interface.[1] The Bookinterface therefore has these methods:

Page 263: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[1] In addition to remote interfaces, EJB 2.0 added theconcept of local interfaces for reference w ithin thecontainer.

public abstract Author getAuthor( ); public abstract void setAuthor(Author auth);

Similarly, the Author interface includes:

public abstract Collection getBooks( ); public abstract void setBooks(Collection bks);

In practice, you rarely want to set the whole listof books associated with an author at all once.Instead, you probably want to add books as newbooks are written. You can add other methodssuch as an addBook( ) method to support theseneeds. The EJB specification, however, demandsthat you write at least a getter and setter.

5.3.1.2 CMR magic

The beauty of EJB 2.0 CMR is its ability tomanage the referential integrity of theserelationships. If you assign one bean's collectionof relationships to another bean, that collectionis automatically removed from the first bean. Ifyou delete the primary bean in a relationshipmarked in the descriptor with a <cascade-delete>tag, its dependent beans are also deleted.[2] Inthe sample descriptor, a Book will be deletedwhenever its Author is deleted from the database

Page 264: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

to prevent us from having books with no authors.

[2] This feature is also known as a cascade delete.

5.3.2 EJB QL

Besides entity relationships, EJB 1.x CMP alsohad difficulties with searches. The main problemwas that you had to write a different findermethod to support every way you could possiblysearch for a bean or set of beans. Furthermore,the semantics of these finder methods left a lotto interpretation. For example, everyone knowswhat getTitle( ) and setTitle( ) do. Do you knowwhat findBooksByYear( ) does? On the face of it,you would think it would provide all bookspublished in a specific year. However, it can alsomean find all books published after a specificyear or before a specific year or even by authorsborn in a specific year. A container simply has noway to know from the EJB 1.x semantics.

5.3.2.1 Finders

EJB 2.0 introduced a query language called theEJBQL to address these searching issues. Thebest way to think of EJBQL is as SQL for EJBs. Inother words, as SQL enables you to query tablesin a relational database, EJBQL lets you querybeans in your application.

You define EJBQL queries inside your deployment

Page 265: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

descriptor:

<ejb-jar> <enterprise-beans> <entity> <ejb-name>BookEJB</ejb-name> <local-home>com.imaginary.ora.BookHome</local-home> <local>com.imaginary.ora.Book</local> <cmp-version>2.x</cmp-version> <abstract-schema-name>Book</abstract-schema-name> <primkey-field>bookID</primkey-field> <cmp-field><field-name>title</field-name></cmp-field> <query><query-method><method-name>findByTitle</method-name><method-params><method-param>java.lang.String</method-param></method-params></query-method><ejb-ql>SELECT OBJECT(b) FROM Book b WHERE b.title = ?1</ejb-ql></query> </entity> ... </enterprise-beans> ...</ejb-jar>

The <query> tag introduces a query thatapplications can perform on the bean. It has twoparts. The first part <query-method>describes theexternal interface, a finder method calledfindByTitle(String). The second part <ejb-ql>describes the actual query. It looks a lot like

Page 266: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SQL but is different enough to make you tilt yourhead sideways.

The key to the EJB QL is the bean's abstractschema name. When you construct an EJB QLstatement, you reference beans by their abstractschema names. In this example, the Book beanhas the abstract schema name of Book. Thus,any time a book is referenced, it is referencedthrough the Book abstract schema name.Naturally, no two beans can share the sameabstract schema name.

Two other pieces to the query are very much un-SQL. The first piece is the superfluous functionOBJECT( ). It is supposedly an indicator to thecontainer that you expect an EJB reference forthat value. Of course, since you specified it as aBook, that desire is rather obvious. Just humorthe container and use OBJECT( ) wherever you arereferencing an EJB.

The last piece is the ?1 token. This tokenparallels JDBC prepared statement tokens. Themajor difference is that you add a parameternumber after the ?. Thus ?1 represents the firstparameter to the findByXXX( ) method, ?2 thesecond, and so on.

For the most part, the rest of EJB QL continuesto look a lot like SQL except with lessfunctionality. It is missing many of the functionssuch as MAX( ) that are basic to SQL.[3]

Furthermore, it has no concept of ordering. A fulldiscussion of EJB QL's syntax is beyond thescope of this book.

Page 267: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[3] Some containers provide container-specificimplementations of these missing functions.

You can define a finder method in your homeinterface to return single instances orcollections. It will not matter to the container. Itwill generate the appropriate code for your finderbased on the return type you specify in theinterface's declaration for the finder.

5.3.2.2 Selectors

The audience for finders is external clients andother beans. EJB 2.0 also introduced a brandnew class of query methods called selectors.Selectors support internal queries by a bean. Inother words, you cannot call a selectorexternally.

Inside your bean implementation class, youprovide abstract declarations for any selectorsyou desire:

public abstract Author ejbSelectWithBook( ) throws FinderException;

This query which could appear in any beanimplementation class that needs it identifies theauthor with the specified book. It isaccompanied by a deployment descriptor withthe following <query> tag:

<query>

Page 268: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<query-method> <method-name>ejbSelectWithBook</method-name> <method-params> <method-param>com.imaginary.ora.Book</method-param> </method-params> </query-method> <ejb-ql> SELECT OBJECT(a) FROM Author a IN (a.books) bk WHERE bk = ?1 </ejb-ql></query>

In addition to being another way to query forbeans, selectors also enable you to query fordata from beans:

SELECT b.title FROM Book b WHERE b.title LIKE '%rain%'

This code provides the titles of all books as aCollection of String instances for the books thathave the substring "rain" in their titles.

You cannot use query parameters in EJBQLLIKE comparisons.

Selectors and finders are very similar animals. Asyou can see from the ability of selectors toreturn partial bean data, however, selectors haveslightly richer capabilities. The huge difference istheir visibility. Selectors are not part of theremote or local bean interfaces; finders are.Finders are meant to enable externalcomponents to find beans matching some set of

Page 269: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

criteria. Selectors, on the other hand, are meantto enable a bean to perform its own arbitrarysearches.

Page 270: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

5.4 Beyond CMP

Container-managed persistence is the ideal. Itenables you to build large-scale enterpriseapplications without worrying about thedatabase. This chapter has described some bestpractices from a persistence perspective shouldyou choose one of the two CMP models that EJBoffers. However, EJB CMP is not a panacea. Inthe remaining chapters of this section, we willaddress the options out there that allow you toadhere to standard persistence models.

Page 271: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 272: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 6. EJB BMPBeings are, so to speak, interrogated withregard to their being. But if they are toexhibit the characteristics of their beingwithout falsification, they must for theirpart have become accessible in advance asthey are in themselves. The question ofbeing demands that the right access tobeing be gained and secured in advancewith regard to what it interrogates.

Martin Heidegger, Being and T ime

If you want something done right, sometimesyou have to do it yourself. This is definitely trueof building persistence into EJB 1.x systems. Asyou read in Chapter 5, EJB 1.x CMP is amazinglysimple, but it is also amazingly simplistic. I havealready spent enough time on the drawbacks ofthe model. To address these drawbacks, youmay need to handle bean persistence yourself.

This chapter tells you how to handle persistenceon your own using the EJB bean-managedpersistence (BMP) model. Even if you areinterested in some form of container-managedpersistence, you should spend some time with

Page 273: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

this chapter since I cover many issues commonto all three EJB persistence models in thischapter. Furthermore, through an understandingof the detailed mechanics of the BMP model, youwill have a better understanding of the magicyou are taking for granted under container-managed models.

Page 274: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

6.1 EJBs Revisited

As in the chapters before this one, I hereassume that you have a basic understanding ofEnterprise JavaBeans. Chapter 9 provides anintroduction to Enterprise JavaBeans that youshould review if you do not have this foundation.Nevertheless, I want to start off with a review ofthe basic elements of the EJB architecture. Ifyou have no experience with EnterpriseJavaBeans, you will find this review lacking. Itherefore recommend going through a book onthe subject such as Enterprise JavaBeans(O'Reilly) by Richard Monson-Haefel to go indepth into EJB programming.

6.1.1 The Components of a Bean

Figure 6-1 is a UML class diagram that shows allof the elements of a single entity bean.

Figure 6-1. The classes that makeup a single EJB

Page 275: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Each EJB requires three classes:

A home interface

A remote interface

An implementation class

Though coding three classes to manage onebasic business concept can be tedious, manyIDEs manage that tedium for you these days.

The home interface identifies themetaoperations that control the bean at a classlevel. It manages the creation of new instances,the deletion of instances, and the searching forbean instances. It is basically your gateway tothe bean.

The remote interface defines the public businessoperations supported by the bean. You include in

Page 276: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

operations supported by the bean. You include inthis interface only those operations you wantclients to be able to trigger.

Finally, the implementation class is where yourattention should be focused. It is not animplementation of either the home or remoteinterfaces though you do have to implementsome of the methods they prescribe. The EJBcontainer generates classes to implement yourhome and remote interfaces. Those container-generated classes delegate their behavior to theactual business logic that you write in theimplementation class. It also handles thepersistence operations I will be describing laterin the chapter.

You create the server side of an EJB applicationby putting together a set of session and entitybeans to support your business transactions andthe logic behind them. Session beans managethe business transactions and entity beansmanage the persistent concepts involved inthose transactions. For example, in Chapter 5, Iintroduced two entity beans: a book and anauthor. If we were to create a library systemthat enabled you to manage books in a library,you might have a "front desk" session bean tohandle check-in and check-out operations. Figure6-2 illustrates these dynamics.

Page 277: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 6-2. Session and entitybeans working together

6.1.2 Kinds of Beans

The core persistent elements in any EJB systemare the entity beans. They represent theconcepts in your problem domain that transcendthe particulars of workflow. If you were to builda travel reservations system, for example, youwould have core concepts like a seat on a plane,a room in a hotel, or a rental car. No matterwhat kind of travel agency you have businesstravel or leisure travel, major agency or a one-person shop these concepts will not vary.

In an enterprise system, entity beans represent

Page 278: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

those timeless concepts that operateindependent of the particulars of the workflowsin which they are managed. What vary are theworkflows that describe the way in which thesetimeless things interact. For example, the rulesgoverning the booking of travel for businesstravel vary greatly from the rules for leisuretravel. Session beans are the EJB tools fordescribing those rules.

6.1.2.1 Entity beans

Under the initial EJB paradigm published by Sun,an entity bean was any persistent object. Aspeople began developing EJBs, they found thattreating entity beans so narrowly resulted inunworkable applications. Looking back to theexample of the card catalog from the previouschapter, a client application listing books mightbe inclined to call getBookID( ) and getTitle( ) oneach book to display the list in a table.

While elegant in theory, this approach isunworkable in practice. The first problem is thatlong lists of entities end up being loaded intomemory on the server when only a subset ofdata from a handful of them is required. For a

Page 279: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

travel reservations system in which a client willpull from a list of thousands of flights, the resultis a system that cannot meet performancedemands.

Another problem with this approach is the needto make multiple network calls to get thenecessary data. For each book in the list, theclient makes two network calls one for eachmethod. It also needs to make a network call forthe initial bean lookup and another call for thesubsequent book search.

These days, EJB developers hide entity beansfrom clients using a variety of techniques I willcover throughout this chapter. The entity bean isstill the ultimate representation oftranscendental business concepts. Instead ofbeing the business concept as it was originallyintended, it can now be thought of as the soul ofthe business concept.

BEST PRACTICE: Never access entity beansfrom client applications.

6.1.2.2 Session beans

Page 280: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

As entity beans were designed as persistentbusiness objects, session beans were designedas nonpersistent business objects. Anonpersistent business object is a businessobject that exists, at most, for the lifetime ofthe application instance. A user session in a webapplication is the eponymous example of aconcept that should be represented as a sessionbean. The user session exists only as long asthe user is logged in. When the user goes away,the session goes away.

As we shall see as we dive deeper into thischapter, session beans have become thewindows through which client applications accessthe system. Through them, you executetransactions and gain access to the informationencapsulated in entity beans.

6.1.2.3 Message-driven beans

The EJB 2.0 specification introduced a new kindof bean, the message-driven bean. Unlikeregular beans, message-driven beans areasynchronous. In other words, a client calls oneof their methods and returns immediately. The

Page 281: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

logic generally involving sending messages toexternal systems happens in another thread.Practically speaking, message-driven beansenable you to build EJB components that interactwith Java Message Service (JMS) API-supportedmessaging services like IBM Websphere MQ.

Page 282: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

6.2 BMP Patterns

The fundamental philosophy behind bean-managed persistence is that the EJB containermanages the components and the transactionswhile you manage their persistence. Thecontainer tells you when interactions with thedata store need to take place, and you makethose interactions happen. The persistencepatterns I described in Chapter 4 are thereforecritical to bean-managed persistence. Figure 6-3places the library business objects from Figure 6-2 into a real world BMP system.

Figure 6-3. EJBs in the real worldusing BMP

To support three basic concepts, I have added ahost of new classes. Some of them such as thedata access objects provide direct support for

Page 283: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

bean-managed persistence. Others like the valueobjects are useful to real world EJB applicationsno matter what persistence model you follow.

As you can see from Figure 6-3, programming inan EJB context brings with it a lot of overhead.That overhead is necessary to support large-scale enterprise applications that requireclustering, high-availability, and robusttransaction management. If you have a fairlysimple application, the use of EJBs will makethat application unnecessarily complex.

BEST PRACTICE: Be certain EnterpriseJavaBeans are the right tool for the job.

Looking back at Chapter 4, our application modelincluded view logic, controller logic, businesslogic, data access logic, and data storage logic.As this book is about database programming, weassume the data storage logic is handled by arelational database. EJB does not address theview or controller logic. It is primarily concernedwith the business logic. If you are using CMP, itcares about the data access logic. Under BMP,however, you provide the data access logic. InFigure 6-3, the data access objects BookDAO andAuthorDAOmanage the data access logic.

The value objects in Figure 6-3 are not directlyrelated to persistence. They are instead tools tohelp model entity beans and minimize theoverhead that comes with entity beans. Because

Page 284: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

they do minimize database access, however,they are critical to the proper operation of apersistent EJB system.

6.2.1 Data Access Objects

I introduced the general concept of data accessobjects in Chapter 4. In the case of BMP, a dataaccess object is a delegate for an EJB to handleits persistence operations. We can see how thisworks in practice by combining code fromChapter 4 and Chapter 5.

The persistence code under the CMP model foran AuthorBean looked like this:

public Long ejbCreate(Long bid, Long aid, String ttl) { bookID = bid; authorID = aid; title= ttl; return null;} public void ejbLoad( ) {} public void ejbPassivate( ) {} public void ejbPostCreate(Long bid, Long aid, String ttl) {} public void ejbRemove( ) {}

Page 285: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public void ejbStore( ) {}

The only thing remotely interesting was ejbCreate(), which assigned initial values to a new bean.We could, of course, add the logic to create thebook in the database inside the ejbCreate( )method:

static private final String CREATE = "INSERT INTO Book ( bookID, authorID, title ) " + "VALUES ( ?, ?, ? )"; public Long ejbCreate(Long bid, Long aid, String ttl) throws CreateException { PreparedStatement stmt = null; Connection conn = null; bookID = bid; authorID = aid; title = ttl; try { Context ctx = new InitialContext( ); DataSource ds = (DataSource)ctx.lookup("jdbc/ora"); conn = ds.getConnection( ); stmt = conn.prepareStatement(CREATE); stmt.setLong(1, bookID.longValue( )); stmt.setLong(2, authorID.longValue( )); stmt.setString(3, title); if( stmt.executeUpdate( ) != 1 ) { throw new CreateException("Failed to add book: " + bookID); } return bookID;

Page 286: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} catch( NamingException e ) { throw new EJBException(e); } catch( SQLException e ) { throw new EJBException(e); } finally { if( stmt != null ) { try { stmt.close( ); } catch( SQLException e ) { } } if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } }}

Though this example code works and is the waymost books should teach you BMP, it is not howyou want to build your beans in real worldapplications. In order to better divide the workof persistence, it helps to pull the database codeout of our entity bean and place it into a dataaccess object. W ith a data access object inplace, the ejbCreate( ) method evolves intosomething much simpler:

static public final String AUTHOR_ID = "authorID";static public final String BOOK_ID = "bookID";static public final String TITLE = "title"; public Long ejbCreate(Long bid, Long aid, String ttl) throws CreateException {

Page 287: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

HashMap memento = new HashMap( ); memento.put(BOOK_ID, bookID = bid); memento.put(AUTHOR_ID, authorID = aid); memento.put(TITLE, title = ttl); CommentDAO.create(memento); return bookID;}

BEST PRACTICE: Under EJB BMP, separatepersistence logic from bean logic through theuse of data access objects.

Each bean-managed EJB has at least fourpersistence operations. The code for eachpersistence operation is fairly involved and haslittle or nothing to do with the business logicthat the bean represents. By moving persistencelogic into a data access object, we havesimplified the bean using a logical division oflabor. Maintenance of persistence logic can nowoccur without requiring changes to the bean, andchanges to business logic can now occur withoutrequiring changes to the persistence handlers.

If you are wondering what the data accessobject code looks like for the bean, you areabout to get another bonus of following thismodel: it looks exactly like the data accessobject from Chapter 4. In other words, usingdata access objects not only makes themaintenance of your application simpler, itmakes it possible to port an application between

Page 288: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

vastly different component models.

Both the data access object and the mementofrom Chapter 4 combined to give the persistencelogic total independence from the businesslogic and vice versa. Thus, we are not only ableto take our persistence logic from thehomegrown component model of Chapter 4, wecould also take our entity bean from this chapterand write a data access object to store the beanto an object database or a filesystem.

6.2.2 Value Objects

As we have already encountered, the distributedparadigm under which entity beans operaterepresent operational challenges for an EJBsystem. One of the tools for mitigating thisproblem is the value object an object thatencapsulates the state of an entity bean for aremote client.

Chapter 4 did not work under a distributedprogramming model. As a result, its componentsdid not face the issues I have presented forentity beans. The component itself was, in amatter of speaking, its own value object.

Unfortunately, value objects violate thesensibility of object purists. This clash betweenobject-oriented elegance and real worldperformance demands has resulted in a varietyof approaches to building value objects. Whichapproach you prefer depends largely on where

Page 289: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

you sit on the object purity/conveniencecontinuum.

BEST PRACTICE: Use value objects to shareentity bean data w ith clients.

6.2.2.1 Simple value objects

Simple value objects sit strongly on theconvenience side of the equation. You've seenthe simplest form of a value object in theHashMap memento. Depending on the operationin question, your entity bean can shove theminimum amount of information necessary tosupport that operation into a HashMap and give itout to clients. One network call provides theclient with everything it needs to know about anentity.

On the other hand, this approach throws most ofthe benefits of object-orientation out thewindow. You get absolutely no type safety andyou risk chaos with calculated fields.

6.2.2.2 Complex value objects

Complex value objects basically attempt to beserializable mirrors of their entity beancounterparts. They have all of the methods and

Page 290: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

some of the business logic supported by theentity bean. As a result, type safety andencapsulation of logic are guaranteed.

Unfortunately, complex value objects are difficultto maintain. Any logic around getting and settingvalues must be maintained in two places theentity bean and its value object and you add yetanother class to code for every single businessconcept you have in your domain model.

6.2.2.3 Other alternatives

Many alternatives to these two extremes exist.Examples include:

Providing only methods to access valueobjects in the entity bean. You can thusmaintain the business logic in only thecomplex value objects and avoid doing it inthe entity bean.

Having no primitive attributes in the entitybean, but instead storing the data in avalue object in the bean.

Managing the internal representation of thevalue object as a HashMap while providing anobject-oriented wrapper around the HashMap.

6.2.3 Sessions as Transactions

Page 291: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Value objects are just one part of insulatingentity beans.[1] Another approach is the use ofsessions as the gateways into all server-sideoperations. In essence, any transaction read orwrite should go through a session bean. Thesession bean thus becomes a transactionalbusiness object.

[1] This section also applies to applications usingcontainer-managed persistence.

BEST PRACTICE: Use session beans toencapsulate all transactional logic.

When you think of transactions, you probablyconjure up examples of transactions in which youare changing the state of the data store. Someof the most problematic transactions from a pureEJB perspective, however, are read transactionslike searches and lookups.

6.2.3.1 Searches

If you remember the way searching occurs in EJB1.x, you have to write finder methods for eachkind of search you want to support. The findermethods then return collections of matchingprimary keys. When you want the data for thosematching keys, the container will load each ofthe entities from which you request data.Searching under EJB 1.x is thus problematic for a

Page 292: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

variety of reasons:

You have to write finder methods to matchevery conceivable manner of searching andplace that logic inside your entity beanimplementation class.

You need to load a ton of entity beans justto get minimal information from each beanin a result set.

You end up making many database callsjust to support a simple search.

By placing searching logic into a session beanand combining this approach with the use ofvalue objects, you can mitigate most problems.To find all books by Stephen King, we couldcreate a session bean called BookSearch with amethod that looks like this:

static private final String FIND = "SELECT title FROM Book WHERE authorID = ?"; public Collection getTitles(Long aid) throws FinderException { PreparedStatement stmt = null; Connection conn = null; ResultSet rs = null; try { Context ctx = new InitialContext( ); DataSource ds = (DataSource)ctx.lookup("jdbc/ora"); ArrayList results = new ArrayList( );

Page 293: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

conn = ds.getConnection( ); stmt = conn.prepareStatement(FIND); stmt.setLong(1, aid.longValue( )); rs = stmt.executeQuery( ); while( rs.next( ) ) { results.add(rs.getString(1)); } return results; } catch( NamingException e ) { throw new EJBException(e); } catch( SQLException e ) { throw new EJBException(e); } finally { if( rs != null ) { try { rs.close( ); } catch( SQLException e ) { } } if( stmt != null ) { try { stmt.close( ); } catch( SQLException e ) { } } if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } }}

You still have to write many finder methods tosupport a variety of needs. Nevertheless, youget the entire overhead associated with entitybeans out of the way. A more common approach

Page 294: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

than simply providing a title would be to providethe minimal information necessary for the clientto support a list view plus a primary key. Theclient can then reference a specific bean byprimary key if it wishes to drill down further orexecute a write transaction.

6.2.3.2 Updates

Sessions are critical for updates as well asreads. In the context of an update, they helpglue together all of the individual entities thatare involved in a given transaction. Figure 6-4shows how a session can be used to "gluetogether" two bank accounts into a transfertransaction.

Figure 6-4. Hiding the details of atransfer behind a session bean

Page 295: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In this example, the client calls a single method,transfer( ) in the AccountManager session bean.That session bean, in turn, modifies the accountbalances for each account. The entire transactionsucceeds or fails together.

It is important to note here that, although youare managing the persistence, you are notmanaging the transactions. While it is possibleto manually handle transactions using bean-managed transactions, bean-managedtransactions and bean-managed persistence aretwo distinct concepts. In general, you neverwant to use bean-managed transactions.

BEST PRACTICE: Avoid using bean-managedtransactions.

Page 296: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 297: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

6.3 State Management

As a developer of the persistence logic for abean-managed bean, your job is to make surethat the state of the bean matches the state ofthe database. The container's role is simply tolet you know when interesting things relating tothe bean state occur.

6.3.1 Lazy-Loading

Loading a simple bean is fairly straightforwardusing the tools we have discussed in thischapter and previous chapters. One of thedrawbacks I mentioned for container-managedpersistence, however, was the inability toperform lazy-loading.

Lazy-loading is a tool that enables you to put offmaking queries to support complex beanrelationships until that information is actuallyneeded. An example of such a relationshipincludes a one-to-many relationship in which themany side requires a complex query orrepresents very many. Another example is anentity bean that stores a huge chunk of binarydata.

For binary data like a Video bean representing avideo clip, you do not want to load that videointo memory for several reasons. First, it is a lotof data to load into memory. In fact, you never

Page 298: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

really want the whole clip to be in memory youwant to stream it. The other reason not to loadit is because it will take a long time to load andthus hold up simple queries against the video'smetadata.

BEST PRACTICE: Take advantage of lazy-loading when your entity bean stores largebinary or text values or has complex objectrelationships.

The following code shows the ejbLoad( ) method(without using data access objects) for a Videobean implementation:

static private final String LOAD = "SELECT title, runningTime, size FROM Video WHERE videoID = ?"; public void ejbLoad( ) { PreparedStatement stmt = null; Connection conn = null; ResultSet rs = null; try { Context ctx = new InitialContext( ); DataSource ds = (DataSource)ctx.lookup("jdbc/ora"); Long id = (Long)context.getPrimaryKey( ); conn = ds.getConnection( ); stmt = conn.prepareStatement(LOAD); stmt.setLong(1, id.longValue( )); rs = stmt.executeQuery( ); if( !rs.next( ) ) {

Page 299: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

throw new EJBException("No matching value."); } videoID = id; title = rs.getString(1); runningTime = rs.getString(2); size = rs.getLong(3); if( rs.next( ) ) { throw new EJBException("Multiple matching values."); } } catch( NamingException e ) { throw new EJBException(e); } catch( SQLException e ) { throw new EJBException(e); } finally { if( rs != null ) { try { rs.close( ); } catch( SQLException e ) { } } if( stmt != null ) { try { stmt.close( ); } catch( SQLException e ) { } } if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } }}

The actual video is not loaded. The loadingoccurs when a client calls for it:

Page 300: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

static private final String STREAM = "SELECT dataStream FROM Video WHERE videoID = ?"; public DistributedDataInputStream getStream( ) { PreparedStatement stmt = null; Connection conn = null; ResultSet rs = null; try { Context ctx = new InitialContext( ); DataSource ds = (DataSource)ctx.lookup("jdbc/ora"); DistributedDataInputStream is ; Clob clob; conn = ds.getConnection( ); stmt = conn.prepareStatement(STREAM); stmt.setLong(1, videoID.longValue( )); rs = stmt.executeQuery( ); if( !rs.next( ) ) { throw new EJBException("No matching value."); } clob = rs.getClob(1); is = new DistributedDataInputStream(clob.getBinaryStream( )); if( rs.next( ) ) { throw new EJBException("Multiple matching values."); } return is; } catch( NamingException e ) { throw new EJBException(e); } catch( SQLException e ) { throw new EJBException(e); }

Page 301: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

finally { if( rs != null ) { try { rs.close( ); } catch( SQLException e ) { } } if( stmt != null ) { try { stmt.close( ); } catch( SQLException e ) { } } if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } }}

For this example to work, of course, you needsome kind of special streaming class that willsend an input stream across the network to beread by a distributed client. That class isrepresented in the example by theDistributedDataInputStream class.

Depending on your database of choice, storingbinary data in a database may be a bad idea. Asa general rule of thumb, I recommend againststoring any binary data in a database for acouple of reasons:

Many database engines are incapable ofproperly streaming binary data. Even thoughthey may support the JDBC Clob interface,they are really reading the entire binaryvalue into memory and faking the

Page 302: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

streaming. If your database does notnatively support streaming (for example,MySQL), this general rule of thumb shouldbe an inviolable law.

The database becomes an intermediarybetween your application and the data onthe disk and thus slows down performance.At its core, this is exactly what a databaseis supposed to be. W ith binary data,however, the advantages of having thisintermediary begin to be outweighed by thedisadvantages.

Moving binary data to the filesystem, however,has its drawbacks. Most notably, you risk dataintegrity when you move the binary data directlyto the filesystem. Your EJB must handle both thedeletion of the metadata in the database andthe file on the filesystem. More problematic,however, is the fact that you cannot do both asan atomic transaction.

BEST PRACTICE: Avoid storing binary data inthe database; store it on the filesystem w ithpointers in the database.

Regardless of the approach you choose, lazy-loading can help you gain the optimal efficiencyfor managing large binary and characterattributes.

Page 303: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

6.3.2 To Store or Not to Store

Containers can be a little ejbStore( ) happy. If thecontainer thinks there is the slightest possibilitythat a bean could have been modified during thecourse of a transaction, it will trigger a call toejbStore( ). This approach is great when all of thebeans involved in a transaction actually hadstate changes. In a transaction that touchesdozens of beans yet modifies only one or two,however, this can seriously harm systemperformance.

A very common practice in EJB development withbean-managed persistence is to create a "dirty"flag and set it whenever a transaction actuallymodifies a bean. In our book example, we mighthave a setTitle( ) method that looks like this:

public void setTitle(String ttl) { title = ttl;}

We can add a simple call to:

dirty = true;

This call will indicate to ejbStore( ) that the beanhas, in fact, undergone a state change. We canthen write ejbStore( ) like this:

public void ejbStore( ) { if( !dirty ) { return;

Page 304: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} // perform the actual save}

After a call to setTitle( ), ejbStore( ) saves the beanto the database. If the store-happy container,however, triggers ejbStore( ) without havingmodified the bean, nothing will happen. Thistrick thus saves at least one unnecessary trip tothe database.

Page 305: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

6.4 Exception Handling

The final piece in bean-managed persistence isexception handling. The EJB specificationclassifies three different exception conditions:

Remote exceptions

EJB exceptions

Application exceptions

All bean interface methods throw remoteexceptions java.rmi.RemoteException. The underlyingdistributed computing architecture throws aremote exception whenever something goeswrong with the network. You should never throwone in your code.

EJB exceptions javax.ejb.EJBExceptionare signalsfrom your code to the container that somethinghas gone wrong with the application outside ofthe normal application states. In the examplesearlier in this chapter, I threw EJB exceptions fordatabase errors and JNDI errors. As a developer,you should never catch an EJBException.

Page 306: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Anything that represents a flaw in theapplication state counts as an applicationexception. The container ignores applicationexceptions.

From the perspective of database access, yourfirst task is to turn all data access exceptionsinto EJB exceptions as shown in the examples inthis chapter. On the other hand, when you checkfor valid values, you will throw applicationexceptions to indicate a failure to match therequired value. In the code to create a book, forexample, I could have added the following checkthat throws a CreateException:

if( bookID.longValue( ) < 0L ) { throw new CreateException("Invalid book ID.");}

Page 307: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 308: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 7. JDO PersistenceThose who feel that liberation fromtradition is a good thing rejoice at thischange, while those who fear the resultslament the loss of roots.

David Kolb, The Critique of Pure Modernity

JDBC provides your application with direct accessto a relational data store. Though JDBC tries toobjectify the data store using objects thatrepresent relational database concepts, it doesnot provide an object-oriented picture of yourproblem domain. Your job in JDBC programmingis to use information from those databaseobjects to build an OO picture of your problemdomain. This task is the problem of object-relational mapping we talked about in Chapter 4.

Also in Chapter 4, I introduced the concept ofthe data access object pattern. Using thispattern, business objects delegate theirpersistence to something else called a dataaccess object. Chapter 4 then showed you howto use JDBC to build data access objects.Chapter 6 showed you how to use the dataaccess object pattern in an EJB system to

Page 309: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

provide JDBC-based persistence.

You do not need to write the persistence layerfor this pattern to be valid. EJB CMP "delegates"its persistence operations to the container. EJBCMP, however, is not the only automatedpersistence option for Java architects anddevelopers. This chapter covers the majorstandard option to EJB CMP, the Java DataObjects (JDO) specification. If you are notfamiliar with this specification, Chapter 12provides a tutorial to introduce you to JDOprogramming.

Page 310: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

7.1 JDO or EJB?

This question is actually too simplistic. Yourpersistence options are much richer than JDO orEJB:

JDBC

JDO

Alternative persistence systems

Serialization

EJB CMP

EJB BMP + JDBC

EJB BMP + JDO

EJB BMP + alternative persistence systems

EJB BMP + serialization

Each of these options even serialization can bethe right answer for a particular persistence

Page 311: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

the right answer for a particular persistenceissue. EJB is overkill for small web applications.Using EJB will kill the performance of your smallapplication and require significant effort to getinitial functionality out the door. JDBC, on theother hand, is a bad solution for a programmingteam with limited database programmingexperience or with a significant number ofpersistent objects to code. JDO, finally, is poorlysuited to teams with little understanding oftransaction management or that require massivescalability. Table 7-1 describes differentproblems and the persistence mechanisms bestsuited to them. It is definitely notcomprehensive and does not address theadvantages of alternative persistence systems.

BEST PRACTICE: Do not use a one-size-fits-all approach to persistence--choose thepersistence option that fits the requirementsand scale of your application.

Table 7-1. Sample applications and matchingpersistence models

Application Persistencemodel Rationale

Enables the development of a

Page 312: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

EmbeddedPDA phonebook

JDO

persistent application w ith thelightest footprint besidesserialization. Unlike serialization,however, the use of JDO preservesobject relationships in the datastore.

EnterpriseCRM system

EJB + EJB2.0 CMP

Supports the scalability needs of amassive enterprise system whilehiding the complexities of transactionmanagement and object-relationalmapping. Also enables developersw ith less experience to be moreproductive in the development of thesystemfewer bottlenecks created byarchitects and senior Javadevelopers.

Medium-sized webapplicationagainst alegacydatabase

JDBC

Provides the greatest ability tocontrol the object-relational mappingfor an application w ith lighttransactional and scalabilitydemands.

Massive webapplicationagainst alegacydatabase

EJB + JDBC

Provides the greatest ability tocontrol the object-relational mappingfor an application w ith heavytransactional and scalabilitydemands.

Massive webapplicationwith agradualmigration EJB + JDBC

Enables control over object-relationalmapping in the short term w ith theadvantages of automated

Page 313: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

migrationfrom a legacydata store toa new datastore

and JDO persistence for simpler componentswhile avoiding mixing CMP and BMPmodels.

Sw ingapplicationthat needsto save itsstate acrossexecutions

Serialization

Supports quick storage and retrievalof the JavaBeans representing yourapplication state w ith none of theoverhead of the other tools.

The issues in Table 7-1 are just the surfaceissues. In short, you really need to know yourproblem domain and the pluses and minuses ofeach persistence mechanism in order to choosethe best tool to support your application. One ofthe purposes of this book is, of course, to armyou with an understanding of the differentpersistence options so you can make thatdecision for the systems you design and build.

The most fundamental distinction between thetwo persistence models, however, lies in theconcept of transparency. In order to takeadvantage of EJB persistence whether BMP orCMP you must adhere to the EJB componentmodel. Any components outside of that modelcannot be made persistent. JDO, on the otherhand, enables you to make any user-defined

Page 314: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

class persistent. In other words, the persistencemodel is transparent to the developer. Thoughyou do not write any persistence code under EJBCMP, you are still writing your classes to adhereto the EJB CMP persistence.

BEST PRACTICE: When not building yourbusiness objects to a specific componentmodel such as Enterprise JavaBeans, designyour business objects to the JavaBeansspecification.

Page 315: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

7.2 Basic JDO Persistence

Most JDO applications fall into the small-to-medium scale. In general, you have a simple tomoderately complex domain model built into anyone of the following kinds of architectures:

Web application

Server application

Two-tier client/server

The tutorial in Chapter 12 covers the basics ofbuilding such an application.

7.2.1 Transaction Management

Though JDO persistence is designed to betransparent to the business componentdeveloper, it is not transparent to theapplication developer. The examples in Chapter12 show only how to manage persistent objectsin the main( ) method of a contrived application.In reality, you will be managing persistentobjects through JSPs and servlets, Swingcomponents, and even other persistent objects.

Figure 7-1 shows how JDO might interact with aweb application. The JSP views perform queriesand display data from the persistent objects.

Page 316: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Controllers create, modify, and delete thepersistent objects. In other words, the JSP pagesperform the same role as the main( ) methodfrom Chapter 12's examples.

Figure 7-1. JDO in a simplisticweb application

This approach works and you will see noproblems from it until your domain model beginsgrowing in complexity. One of the drawbacks ofJDO, however, is that it does not manage objectrelationships automatically you are responsiblefor maintaining the integrity of all relationshipsamong persistent objects. When you embed thelogic for the creation and deletion of persistentobjects in views and controllers, you create amaintenance problem.

For example, your web application could havetwo controllers: one that deletes an author andanother that deletes a book. Each controllerwould require code that not only callsdeletePersistent( ), but that also protects theintegrity of the relationship between Author and

Page 317: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Book. If the rules governing this relationshipchange, you need to make sure you find allplaces in the application where the relationshipis being managed and make the appropriatechanges.

To diminish the risk of managing relationships inyour application, you need to centralize the logicfor managing your persistent objectrelationships. I recommend the creation of anEJB session bean-like class that performsmetaoperations on your persistent classes.Example 7-1 shows such a class.

BEST PRACTICE: Centralize the logic formanaging object relationships to preservetheir integrity and the integrity of theunderlying data store.

Example 7-1. A Bookshelf class tomanage object relationships

package com.imaginary.ora; import javax.jdo.*; public abstract class Bookshelf { static private PersistenceManager getPersistenceManager( ) { PersistenceManagerFactory factory; Properties props = new Properties( );

Page 318: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

// load JDO properties factory = JDOHelper.getPersistenceManagerFactory(props); return factory.getPersistenceManager( ); } static public void createAuthor(Author auth) { PersistenceManager mgr = getPersistenceManager( ); Transaction trans; trans = mgr.currentTransaction( ); trans.setOptimistic(false); try { trans.begin( ); mgr.makePersistent(auth); trans.commit( ); } catch( Exception e ) { e.printStackTrace( ); } finally { if( trans.isActive( ) ) { trans.rollback( ); } mgr.close( ); } } static public void deleteAuthor(Author auth) { PersistenceManager mgr = getPersistenceManager( ); Transaction trans; trans = mgr.currentTransaction( ); try { trans.setOptimistic(true); } catch( JDOUnsupportedOptionException e ) { }

Page 319: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

try { Iterator books = auth.getBooks( ).iterator( ); trans.begin( ); while( it.hasNext( ) ) { mgr.deletePersistent((Book)it.next( )); } mgr.deletePersistent(auth); trans.commit( ); } catch( Exception e ) { e.printStackTrace( ); } finally { if( trans.isActive( ) ) { trans.rollback( ); } mgr.close( ); } } static public void createBook(Author auth, Book book) { PersistenceManager mgr = getPersistenceManager( ); Transaction trans; trans = mgr.currentTransaction( ); try { trans.setOptimistic(true); } catch( JDOUnsupportedOptionException e ) { } try { trans.begin( ); book.setAuthor(auth); auth.addBook(book); mgr.makePersistent(book); trans.commit( );

Page 320: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} catch( Exception e ) { e.printStackTrace( ); } finally { if( trans.isActive( ) ) { trans.rollback( ); } mgr.close( ); } } static public void deleteBook(Book book) { PersistenceManager mgr = getPersistenceManager( ); Transaction trans; trans = mgr.currentTransaction( ); try { trans.setOptimistic(true); } catch( JDOUnsupportedOptionException e ) { } try { trans.begin( ); book.getAuthor( ).removeBook(book); mgr.deletePersistent(book); trans.commit( ); } catch( Exception e ) { e.printStackTrace( ); } finally { if( trans.isActive( ) ) { trans.rollback( ); } mgr.close( ); }

Page 321: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

}}

This class performs two critical tasks:

It clearly demarcates the boundaries oftransactions involving Author and Bookinstances.

It centralizes all logic relating to themanagement of Author and Bookrelationships.

It also has the hidden benefit of making thepersistence model transparent to your controllerclasses. The JSP code to create a new authorlooks like this:

<% Bookshelf.createAuthor(new Author(firstName, lastName)); %>

This code also uses optimistic transactionmanagement for optimal performance. In doingso, it checks for the possibility that the JDOimplementation does not support optimistictransaction management. Not all JDOimplementations support optimistic transactionmanagement, and not all transactions are wellsuited to optimistic transaction management. Ingeneral, optimistic transaction managementworks when you are performing multipleoperations and each operation targets a differentobject.

The exception in this example was the code to

Page 322: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

create a new Author. Because the operationtouched only the Author class for a singleoperation, it is going to see better performanceunder data store transaction management.

BEST PRACTICE: Use optimistic transactionmanagement for long transactions involvingmultiple persistent objects.

7.2.2 Query Control

The previous section made the use of JDOtransparent to controllers views still use JDOqueries to retrieve collections of persistentobjects. This issue is not the maintenanceproblem that running creates and deletes inmultiple locations produced. It wouldnevertheless be nice to centralize query logic toprovide view pages with the same transparencyas well as give us a single location to tweakquery logic. The Bookshelf class looks like a goodcandidate. On the other hand, it probably makesmore sense to have a one-to-one associationbetween a persistent class and the class thatmanages its queries. Example 7-2 shows anAuthorFinder class to handle queries.

Example 7-2. A class thatcentralizes query logic for Authorinstances

Page 323: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

package com.imaginary.ora; import java.util.*; import javax.jdo.*; public abstract class AuthorFinder { static private final String GENRE = "gen"; static private final String YEAR = "yr"; static public Collection findByGenreYear(String gen, int yr) { Extent ext = mgr.getExtent(Author.class, true); Query query = mgr.newQuery(ext, "books.contains(book) & (book.year=yr & book.genre = gen)"); HashMap params = new HashMap( ); query.declareParameters("int yr, String gen"); query.declareVariables("com.imaginary.ora.Book book"); params.put(GENRE, gen); params.put(YEAR, yr); return(Collection)query.executeWithMap(params); }}

This example provides a single query, but inreality it will likely contain a variety of queries tohelp support various Author searches. Thisparticular query provides the application with alist of all authors who published a book of aspecific genre in a specific year. Even though thesearch has only two parameters, I usedexecuteWithMap( ) because it helps prevent any

Page 324: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

maintenance ugliness associated with matchingparameter order.

BEST PRACTICE: Use executeW ithMap( ) whenexecuting multiparameter queries.

Page 325: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

7.3 EJB BMP with JDO

From a JDO perspective, persisting EJBs as partof a bean-managed persistence model has littledifference from persisting other kinds of objects.The most common difference is that you tend tobe in a managed environment when working withEJBs; similarly, you tend to be in a nonmanagedenvironment when building other kinds ofapplications. You can, of course, build webapplications in a managed environment and EJBapplications that use bean-managedtransactions.

One key differentiator between working with JDOin a managed J2EE container versus anonmanaged environment besides the obviousimpact of transaction management is the way youreference the PersistenceManagerFactory class. In anon-J2EE container or a nonmanagedenvironment, you pass a set of properties to theJDOHelper class. The JDOHelper class then handsyou the appropriate PersistenceManagerFactory.

When working in a J2EE container, you can relyon JNDI to provide you with aPersistenceManagerFactory without worrying aboutproperties:

Page 326: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Context ctx = new InitialContext( );PersistenceManagerFactory factory; factory = (PersistenceManagerFactory)ctx.lookup("jdo/pmf");

7.3.1 Transaction Management

Because you are working in an EJB environment,transaction management issues disappear fromyour radar when using JDO as a bean-managedpersistence tool. The exception to thisadvantage comes when you decide to use bean-managed transactions. Managing your owntransactions is one of the pitfalls of working withJDO in a nonmanaged environment. Youdefinitely do not want to introduce that pitfallinto this environment unless something makesbean-managed transactions your only option. Ifyou do opt for bean-managed transactions, youshould remember that it is a really bad idea tomix bean-managed and container-managedtransactions. Chapter 5 has a detailed discussionof this topic.

BEST PRACTICE: Avoid bean-managedtransactions unless there is an overridingneed for them.

Page 327: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

7.3.2 Persistence Strategies

In an EJB application, session beans perform therole we set aside for the Bookshelf class in theprevious section. They may also create valueobjects for the entities that match any queriesperformed by the session bean. The entitybeans, on the other hand, contain the businesslogic behind any persistent object. Depending onyour EJB architecture philosophy, either theentity bean itself or its value object can be theJDO PersistenceCapable class. Using the valueobject, however, and having the entity beandelegate to the value object for all stateinformation enables you to maintain stateinformation in a single location.

If you take the approach of using the JDOinstance as your value object, you need to takecare that it is not involved in an uncommittedtransaction when you serialize it to the client.Doing so may cause unpredictable exceptionalconditions.

Page 328: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 329: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 8. AlternativePersistence Frameworks

Reason must in all its undertakings subjectitself to criticism; should it limit freedom ofcriticism by any prohibitions, it must harmitself, drawing upon itself a damagingsuspicion. Nothing is so important throughits usefulness, nothing so sacred, that itmay be exempted from this searchingexamination, which knows no respect forpersons. Reason depends on this freedomfor its very existence. For reason has nodictatorial authority, its verdict is alwayssimply the agreement of free citizens, ofwhom each one must be permitted toexpress, w ithout let or hindrance, hisobjection or even his veto.

Immanuel Kant, The Critique of PureReason

As an enterprise application architect, you havemore options than just choosing between apersistence model blessed by Sun and rollingyour own model. In fact, alternative persistencemodels have been gaining in popularity recently

Page 330: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

for a variety of reasons:

EJBs are complex and heavy and theyrequire an application server.

JDBC is time-consuming and requires asignificant degree of database programmingskill.

JDO is late on the scene and still lacking inimplementations.

A quick search of the Internet will reveal avariety of alternative persistence systems. Twoof the most popular are the Castor JDO (not animplementation of the Sun JDO specification)and Hibernate projects.[1] This chapter looks atCastor and Hibernate as alternative XML object-relational mapping tools.

[1] Both are open source projects available atSourceForge (http://www.sourceforge.net).

Page 331: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 332: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Software RequirementsCastor and Hibernate are not a standard part of anyJava platform. You therefore need a host of tools tosupport these APIs. Each API has a different set ofrequirements, which you can find more about at theirrespective home pages:

Castor

http://castor.exolabs.org.

Hibernate

http://hibernate.sf.net.

Page 333: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

8.1 Why Alternative Frameworks?

The Java philosophy is heavy on the idea thatyou adhere to the standards and compete onimplementation. As a general rule of thumb inthe Java world, you should avoid deviating fromstandards unless the standards in questionsimply do not meet your needs. Java'spersistence models, however, are far from well-accepted standards. Part of the reason behindthis divergence is that no single persistencemodel can support the needs of everyapplication. Each approach to persistencerequires design decisions that necessarilyexclude features provided by other systems.

Each alternative framework brings its ownadvantages to database programming. As ageneral rule, alternative frameworks offer you:

The ability to meet specific needs notaddressed in the EJB or JDO standards.

As with EJB and JDO, Hibernate and Castorrely on XML descriptor files for persistencemapping. This lends itself to providing avery easy to understand mapping file that

Page 334: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

describes complex database relationships.

The alternatives in this chapter limit theamount of code developers need to write inorder to make objects persistent.

The alternatives in this chapter are opensource. As such, they come with all of thebenefits and the drawbacks of open sourcetools.

BEST PRACTICE: Use alternative persistenceframeworks in applications designed for low-cost deployment environments or forapplications that have niche requirements forwhich an alternative framework is uniquelysuited.

Alternative persistence APIs are not withouttheir own drawbacks:

Alternative persistence APIs are simplythat: an alternative. These APIs do notconform to recognized standards such asEJB 1.1, EJB 2.0, and JDO.

Alternative persistence APIs do not provide

Page 335: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

a container-managed transaction systemsuch as those provided by the EJBcontainer. W ith EJBs, the transactiondemarcation is done automatically bydefining the transaction attributes in yourdeployment descriptor and is strictlyenforced by the container.

Page 336: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 337: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The Open Source ModelThe open source model is a model for distributingsoftware based on the philosophy that the people whouse software should have the right to the source codefor the software, including the ability to modify thesource code. Though it is often associated w ith theconcept of free meaning w ithout cost software, opensource software describes itself as free, as in speech. Inother words, open source software may or may not costany money.

The benefits of open source software include:

Greater control over your software, including theability to improve the software instead of waitingfor a vendor to fix it for you.

Given a large contributor base, open sourcesoftware tends to have a more diverse developerbase than proprietary software.

Open source software even when it is not free isgenerally cheaper than proprietary software sincethe business models for open source companiestend to be based on services around theirsoftware.

On the other hand, open source software has itsdrawbacks:

Support for the software often depends on thewhims of its developers rather than a solidservice agreement.

Releases of open source software w ithout largedeveloper bases are inconsistent and even prone

Page 338: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

to long periods of inactivity.

The benefits of the greater control over yoursoftware can become liabilities if you lose theability to maintain your changes.

BEST PRACTICE: Do not use alternativeframeworks for applications meant to bedeployed in a variety of corporateenvironments. In such environments,adherence to standards is critical to theconfidence of those who w ill be responsiblefor supporting the application.

Page 339: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

8.2 Persistence Approach

As you have seen with all of the otherautomated persistence systems in this book,Castor and Hibernate both persist componentattributes by reading an XML configuration filethat defines persistence mapping. Table 8-1shows the attributes of two business objects wemight want to persist to a database.

BEST PRACTICE: Though each frameworklets you specify all persistence mapping in asingle XML file, you should limit each XML fileto describing the mapping of a single class.

Table 8-1. The attributes of two businessobjects with the mapping type to be used

Class Attribute Type

Author authorID Long

firstName String

lastName String

Publicat ions List

Book bookID Long

Author Author

Tit le String

Example 8-1 contains the code for the Authorclass described in Table 8-1.

Example 8-1. A persistent Authorclass

package book;

Page 340: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public class Author { private long authorID; private String firstName; private String lastName; private Set publications; public long getAuthorID ( ) { return authorID; } public String getFirstName( ) { return firstName; } public String getLastName( ) { return lastName; } public Set getPublications ( ) { return publications; } public void setAuthorID (long id) [ authorID = id; } public void setFirstName(String fn) { firstName = fn; } public void setLastName(String ln) { lastName = ln; } public void setPublications (Set pubs) { publications = pubs; }}

This business class is very simple nothing butgetters and setters to manage the attributes. Nopersistence code is present. Example 8-2contains the basic code for the Book class.

Example 8-2. Book value object

Page 341: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

that contains an Author valueobject reference

package book; public class Book { private Author author; private long bookID private String title; public Author getAuthor ( ) { return author; } public long getBookID ( ) { return bookID; } public String getTitle ( ) { return title; } public void setAuthor (Author auth) { author = auth; } public void setBookID (long id) { bookID =id; } public String setTitle (String ttl) { title = ttl; }}

8.2.1 Castor Field Mapping

The key to Castor and Hibernate persistence isthe XML file. Each API has it own definitionlanguage for defining the mapping betweenobjects and a table. Example 8-3 shows howCastor maps the business objects to a database.

Page 342: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Example 8-3. Castor XML mappingdescriptor

<?xml version="1.0"?><!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.exolab.org/mapping.dtd"> <mapping> <class name="book.Author" identity="authorID" key-generator="MAX"> <map-to table="AUTHOR"/> <field name="authorID" type="long"> <sql name="AUTHORID"/> </field> <field name="firstname" type="java.lang.String"> <sql name="FIRSTNAME"/> </field> <field name="lastname" type="java.lang.String"> <sql name="LASTNAME"/> </field> <field name="publications" type="book.Book" collection="set"> <sql many-key="authorid"/> </field> </class> <class name="book.Book" identity="bookID" key-generator="MAX"> <map-to table="BOOK"/> <field name="bookID" type="long"> <sql name="BOOKID"/> </field> <field name="title" type="java.lang.String"> <sql name="TITLE"/> </field> <field name="author" type="book.Author"> <sql name="AUTHORID"/> </field> </class></mapping>

For each class you wish to map, you have aclass[2] entry in your XML-descriptor. This tagidentifies the following:

[2] The use of the word class makes this XML dialecttechnically illegal since class is a reserved word in XML.

Page 343: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The name of the Java class being mapped.

The name of the identity attribute (theattribute that uniquely identifies aninstance of the class).

The key generation tool to use to generateidentity values. Both Castor and Hibernateprovide several methods of generatingunique values.

BEST PRACTICE: Choose the sequencegeneration method that best suits yourpersistence framework of choice.

Castor supports the following key generationalgorithms:

HIGH-LOW

This algorithm uses a mechanism similar tothe custom sequence generation algorithmdescribed in Chapter 4. It requires a specialsequence table whose keys are the namesof tables and whose columns are seedvalues for sequence generation. For more onseed values, look at the sequencegeneration part of Chapter 4.

IDENTITY

The value generated is based on the valuegenerated by the proprietary identitygeneration scheme of the underlyingdatabase engine. Supported databasesinclude Hypersonic SQL, MS SQL Server,MySQL, and Sybase ASE/ASA.

MAX

The value generated is one greater than the

Page 344: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

maximum value currently in the database.

SEQUENCE

The value generated comes from theproprietary SEQUENCE concept of Interbase,Oracle, PostgreSQL, and SAP DB.

UUID

This algorithm generates a globally uniquevalue based on the IP address, currentsystem time in milliseconds, and a staticcounter.

The SEQUENCE and HIGH-LOW algorithmsrequire parameters. You can specify theparameters using the key-generator tag outsidethe class tag:

<key-generator name="HIGH-LOW"> <param name="table" value="Sequence"/> <param name="key-column" value="name"/> <param name="value-column" value="seed"/> <param name="grab-size" value="1000000"/></key-generator>

BEST PRACTICE: Use the HIGH-LOW keygeneration algorithm.

Within the <class></class> enclosure is the set oftags that defines the mapping of class attributesto database tables. The first tag in the group isthe map-totable tag. As its name suggests, itspecifies the name of the database table towhich the attributes of this class map.

The rest of the tags define the actual field-to-column mappings. The tag of special interest isthe one that defines how an Author relates toBook. Instead of identifying a column in theAUTHOR table, it identifies an attribute in theBook class. Castor then uses the mapping of this

Page 345: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

column to perform the appropriate joins.

8.2.2 Hibernate Field Mapping

Field mapping in Hibernate is quite similar.Example 8-4 shows the XML descriptor thatdefines that mapping of the sample classes to adatabase.

Example 8-4. Hibernate XMLmapping descriptor

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-1.1.dtd"> <hibernate-mapping > <class name="book.Author" table="AUTHOR"> <id name="authorID" column="AUTHORID" type="long"> <generator class="vm.long"/> </id> <property name="firstname" column="FIRSTNAME" type="string"/> <property name="lastname" column="LASTNAME" type="string"/> <set role="publications" lazy="true"> <key column="AUTHORID"/> <one-to-many class="book.Book"/> </set> </class> <class name="book.Book" table="BOOK"> <id name="bookID" column="BOOKID" type="long"> <generator class="vm.long"/> </id> <property name="title" column="TITLE"/> </class></hibernate-mapping>

The Hibernate code is similar to the Castor code,yet different in many important ways. Again,Hibernate uses a class tag to define thepersistence mapping for a specific Java class.Unlike Castor, Hibernate defines the tablemapping as a tag attribute.

W ithin a class, you identity the ID, properties,

Page 346: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and sets of the class. The ID is the primary keyfield. The id tag contains a generator tag tospecify a key generation algorithm to use forautomated key generation. This tag identifies aJava class that performs a key generationalgorithm. If the algorithm requires parameters,they may be specified in the body of thegenerator tag as param tags:

<generator class="org.dasein.persist.Sequence"> <param>sequence</param></generator>

The generator class is an implementation ofcirrus.hibernate.id.IdentifierGenerator. Hibernateprovides the following built-in generators:

assigned

Enables the application to generate its ownidentifiers.

hilo.hex

This algorithm is the same as hilo.long,except the result is a string of 16characters.

hilo.long

Generates unique long values using a HIGH-LOW algorithm. This generator should notbe used in JTA environments or with user-supplied connections.

native

Generates a unique value based on theidentity columns for DB2, MS SQL Server,MySQL, Sybase, and Hypersonic SQL.

Page 347: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

seqhilo.long

Generates a unique long value for a namedsequence using the HIGH-LOW algorithm.

sequence

Generates a unique value based on theSEQUENCE concept from DB2, Interbase,Oracle, PostgreSQL, and SAP DB.

uuid.hex

Generates a globally unique 32-characterstring.

uuid.string

Identical to uuid.hex, except it generates a16-character ASCII string. This algorithmshould not be used with PostgreSQL.

vm.hex

Generates unique strings based onhexadecimal digits. This algorithm shouldnot be used in a cluster.

vm.long

Generates unique long values. Thisalgorithm should not be used in a cluster.

BEST PRACTICE: Most persistence platformsoffer a variety of sequence generationapproaches; it is important to use a sequencegenerator that w ill fit your overall high-levelarchitecture for system requirements such as

Page 348: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

clustering.

Properties are the basic attributes of the class.Sets, on the other hand, represent the one-to-many or many-to-many mappings for the class.Again, our objects map one author to manybooks. Hibernate captures this relationshipthrough the set tag.

Hibernate supports six different collection tags:

<array>

<bag>

<list>

<map>

<primitive-array>

<set>

For all of these set types except arrays, you canenable lazy-loading through the lazy="true"attribute. Using lazy-loading can greatly increasethe speed of your application for operations suchas searching. Additional approaches such ascaching can also greatly increase the speed ofyour application. It is worthy to note that mostalternative persistence APIs offer some type ofbuilt-in object caching that can be turned on oroff.

BEST PRACTICE: When choosing apersistence API it is important to fullyunderstand the different mapping types thatan API supports. Each persistence system w illhave its own weaknesses and may notsupport advanced mapping types such asone-to-many and many-to-one mappingtypes.

Page 349: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

8.3 Persistence Operations

The Author and Book classes in Example 8-1 andExample 8-2 do not contain any persistence-related methods. Both Castor and Hibernate,however, require you to add code to triggerpersistence operations.

W ith any database-intensive application, theflushing of new state to the database is a time-expensive process. One advantage to controllingwhen the flushing of your data occurs is that youcan manage this expense.

W ith both persistence systems, persistenceoperations are done by loading the mappingfiles, obtaining a database connection, callingfor an object to be persisted, and closing out thetransaction. Abstracting the persistence codewith a data access object will help you create acleaner implementation.

BEST PRACTICE: Encapsulate persistenceoperations using both frameworks in dataaccess objects similar to those we have usedin other persistence models in this book. Thisw ill allow you to easily refactor your code toan alternative persistence system such asEJBs.

8.3.1 Castor Persistence

In our example, we need the ability to add anew book to an author's list of books. In Castor,the method to perform this task might look likethis:

public Book addBook (Book book) throws Exception { JDO jdo = new JDO("alternativepersistencedb");

Page 350: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

jdo.loadConfiguration("database.xml"); Database db = jdo.getDatabase( ); db.begin( ); db.create(book); db.commit( ); db.close( ); return book; }

BEST PRACTICE: Using a singleton tomanage the loading and parsing of yourpersistence configuration files w ill increasethe speed of your persistence operations.

This code references a new XML file, thedatabase.xml configuration file. It describes yourdatabase connections to enable Castor to accessa JDBC data source. Example 8-5 shows whatsuch a file looks like.

Example 8-5. Castor databaseconnection descriptor

<!DOCTYPE databases PUBLIC "-//EXOLAB/Castor JDO Configuration DTD Version 1.0//EN" "http://castor.exolab.org/jdo-conf.dtd"> <database name="aps" engine="sql-server"> <driver class-name="net.sourceforge.jtds.jdbc.Driver" url="jdbc:jtds:sqlserver://localhost:1433/aps"> <param name="user" value="aps"/> <param name="password" value="research"/> </driver> <mapping href="mapping.xml"/></database>

With the connection information defined, adatabase session is established by calling the

Page 351: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

JDO class method getDatabase( ). To start atransaction, the begin( ) method is called on theDatabase session. The Book class is now ready tobe persisted. This is accomplished by callingcreate( ) on the Database session. The new Bookhas been persisted, and connection cleanupneeds to be performed by closing the transactionwith commit( ) and close( ) on the Database session.If a transaction error occurs, aTransactionAbortedException will be thrown by theDatabase session.

8.3.2 Hibernate Persistence

Hibernate persistence works very much likeCastor persistence. You basically have to makecalls to methods with similar names in differentclasses:

public Book addBook (Book book) throws Exception { Datastore ds = Hibernate.createDatastore( ); ds.storeFile("hibernate.xml"); SessionFactory sessionFactory = ds.buildSessionFactory( ); Session session = sessionFactory.openSession( ); session.beginTransaction( ); session.saveOrUpdate(book); session.flush( ); session.connection( ).commit( ); session.close( ); }

The first line of code calls createDatastore( ), whichloads the Hibernate connection descriptor (anexample is provided in Example 8-6). An XML-based connection descriptor is also available.

Example 8-6. Hibernate databaseconnection descriptor

Page 352: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

hibernate.connection.driver_class=net.sourceforge.jtds.jdbc.Driverhibernate.connection.url=jdbc:jtds:sqlserver://localhost:1433/apshibernate.connection.username=apshibernate.connection.password=research

With the connection information loaded, thestoreFile( ) method then reads in the mappingdescriptor. The SessionFactory is used to managesession connections across the application. Forour example, we are creating the SessionFactorywith each request. To start a transaction, thebeginTransaction( ) method on the current Session iscalled. The saveOrUpdate( ) method is then calledto create or update any object that needs to bepersisted. The flush( ) must be called at the endof any transaction cycle. Flushing is used tosynchronize the database with persistent objectsin memory. To close the transaction, the commit() method is called, and the transaction is closedwith the close( ) method. Transaction errors willthrow a SQLException.

BEST PRACTICE: Both frameworks supportdatabase connection pooling or the use ofJNDI data sources. Take advantage of thissupport in your database applications.

Page 353: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

8.4 Searches

Searching with both persistence systems lookssimilar to JDO. They both use object-basedquery languages and leverage a similar API set.

8.4.1 Castor Searches

Castor uses the Object Query Language (OQL).OQL queries are similar to standard ANSI SQLbut use object names in place of column fields.Example 8-7 details the implementation of abook search with Castor.

Example 8-7. Searching for a bookby title with Castor

public Book findBookByTitle(String title) throws Exception { JDO jdo = new JDO("alternativepersistencedb"); jdo.loadConfiguration("database.xml"); Database db = jdo.getDatabase( ); db.begin( ); OQLQuery query = db.getOQLQuery("SELECT b FROM book.Book b WHERE title=$1"); query.bind("Alternative Persistence Systems"); QueryResults results = query.execute( ); // assume the first book found is the desired book Book book = (Book) results.next( ); db.commit( ); db.close( ); return book;}

As before, all configuration information needs tobe loaded and ready before any databaseoperations can be performed. Once theconnection has been established, the OQLQuery

Page 354: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and QueryResults classes are used for searching.The most important line here is the getOQLQuery() method. This particular search looks for allentities that have a title value equal to the titleattribute supplied by the calling method. If noresults exist when next( ) is called, aNoSuchElementException will be thrown.

8.4.2 Hibernate Searches

Searching with Hibernate is almost identical tothat with Castor. Example 8-8 details theimplementation of searching with Hibernate.

Example 8-8. Searching for a bookby title with Hibernate

public Book findBookByTitle(String title) throws Exception { Datastore ds = Hibernate.createDatastore( ); ds.storeFile("hibernate.xml"); SessionFactory sessionFactory = ds.buildSessionFactory( ); Session session = sessionFactory.openSession( ); Book book = null; List results = session.find("from o in class book.Book where title = ?", title, Hibernate.STRING); if (results.isEmpty( )) { throw new Exception ("Entity not found: " + title); } else { book = results.get(0); } session.close( ); return book;}

The difference with Hibernate is that rather thanthrowing an exception when no entities arefound, the framework supplies the methodisEmpty( ) to determine if your search yielded noresults.

Page 355: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

results.

Page 356: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

8.5 Beyond the Basics

A full discussion of the details of eachalternative framework is well beyond the scopeof this book. Furthermore, Castor and Hibernateare not your only alternatives. You should now,however, have an appreciation of how these twoframeworks operate, some things to look for,and the role of alternative persistenceframeworks in database programming.

Page 357: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 358: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Part III: TutorialsThe first two sections of the book cover avariety of technologies. You should befamiliar with many of the them, but youmay not be familiar with all of them. As anEJB programmer, you probably know J2EEtechnologies like EJB and JNDI well, but youmay not be familiar with JDO. This sectionprovides a JDO tutorial just for you.Because you know EJB and JNDI so well,however, you will find no use for the J2EEtutorial.

In short, not every tutorial chapter is forevery reader of this book. Some advancedreaders, in fact, will have no use for any ofthe tutorial chapters. I do expect mostreaders will find the need to reference atleast one of these chapters before tacklinga chapter earlier in the book. If you have noexperience in JDO, for example, youprobably want to look at the JDO tutorialbefore reading the chapter on JDOpersistence. If you have no EJB experience,read the J2EE chapter before tackling eitherof the EJB persistence chapters. Finally, youneed to understand the material in the

Page 359: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

JDBC and SQL tutorials to appreciate justabout any chapter in Part I or Part II.

Page 360: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 361: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 9. J2EE BasicsWe must know the secret union of soul andbody, and the nature of both thesesubstances; by which the one is able tooperate, in so many instances, upon theother.

David Hume, An Enquiry Concerning HumanUnderstanding

Most of the time when you are working with adatabase in a Java environment, you are workingin some aspect of the J2EE framework. Rarelywill you build a pure JDBC application with noreliance on the J2EE platform. It is therefore nosurprise that many of the chapters in this bookassume some level of appreciation for the J2EEAPIs.

This tutorial is far from a comprehensive how-toon building J2EE applications. If you are lookingto learn J2EE, then you should pick up a bookdedicated to the subject. In this chapter, I offeran overview of the most important concepts inthe J2EE platform so that you can tackle thesubject matter of this book's first eight chapters.

Page 362: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 363: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

9.1 The Platform

A platform provides application developers witha full abstraction of a generic computingenvironment. The W indows platform, forexample, is a suite of APIs that enablesdevelopers to write desktop applications for anysystem running W indows, regardless of theunderlying hardware they are using. The mainJava platform, Java 2 Standard Edition (J2SE),does the same thing except its abstractionspans all desktop systems.

Whereas the J2SE platform creates a standardfor desktop programming independent ofhardware and operating system, the J2EEplatform provides a standard for enterprisesystems. It is a superset of J2SE. It adds thefollowing abstractions:

Enterprise JavaBeans (EJB)

Java Servlets

JavaServer Pages (JSP)

Java Naming and Directory Interface (JNDI)

Page 364: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Java Naming and Directory Interface (JNDI)

Java Transaction Architecture (JTA)

Java Message Service (JMS)

Java Mail

J2EE Connector API

XML support

Two APIs critical to the J2EE platform, JDBC DataAccess and Remote Method Invocation (RMI),predate the J2EE platform and exist in the J2SEplatform.

The focus of this book is simply one aspect ofJ2EE programming, application persistencethrough relational databases. A full discussion ofthe J2EE platform is thus beyond the scope ofthis book. Nevertheless, as a databaseprogrammer, a foundation in a few of these APIsis important. I provide an overview of JNDI,JavaServer Pages, RMI, and Enterprise JavaBeanshere. Later in the book, I provide a moredetailed tutorial on JDBC.

Page 365: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

9.2 Java Naming and Directory Interface

The Java Naming and Directory Interface APIprovides a single set of classes for accessing anykind of naming or directory service. If you areintent on learning just one enterprise API, youshould learn JNDI with it; it is the door throughwhich you will have to work to program in anenterprise environment.

BEST PRACTICE: If you intend to work w iththe J2EE APIs, make sure you learn JNDI.

9.2.1 Naming and Directory Services

Naming and directory services are among themost fundamental tools of computing. Theyenable us to access computing resources usinghuman-friendly names. It would be hard toimagine using a computer in which you had toaccess a file on a hard drive by its physicallocation or select a printer for a print job basedon its I/O port. Instead, you have a filesystemthat lets you use a name that is automaticallytranslated to a physical location on request.Before you can access just about anyresource local or remote you need to access anaming or directory service.

A naming service is nothing more than adatabase that associates familiar names with

Page 366: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

technical values. A very simple example of anaming service is the Internet Domain NameService (DNS). DNS associates computer nameswith IP addresses. If you want to access my website, you type in www.imaginary.com and theapplication checks with a DNS server to translatethat name value to the IP address that providesthe actual location of my server on the Internet.Not only is www.imaginary.com easier toremember than a quad of numbers; the use of aneasy-to-remember name enables me to changethe physical location of the server withoutimpacting your ability to access it.

A directory service is simply an extension of anaming service that enables you to structuredata in a hierarchical namespace. In otherwords, not only does a directory service supportaccess to some network object by an easy-to-remember name, but it also enables you tocreate a tree of information in which that objectis stored. A domain object, for example, couldcontain many hosts. Microsoft's Active DirectoryService (ADS) is among the newest examples ofdirectory services. In ADS, W indows 2000 storesa variety of network resources, including users,computers, domains, and printers.

You may be wondering what the differences arebetween a directory service storing userinformation and a relational database storinguser information. Both directory services andrelational databases are specific kinds ofdatabases. A directory service stores informationin a hierarchical format and a relational database

Page 367: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

in a more complex format consistent withrelational theory. A directory service is bestsuited to read-heavy, hierarchical data. By read-heavy, I mean that access to that data is mostlyread access with occasional writes.

When writing database applications, you willdeal with a variety of directory services. Themost common directory services include:

ActiveDirectory

LDAP

NIS

The most common directory service you willaccess, however, is the directory service builtinto your J2EE application server. It may useLDAP or some other directory service, or it mayfollow a proprietary format. You will use it tolook up J2EE resources such as JDBC datasources.

9.2.2 JNDI Architecture

JNDI is the J2EE gateway into different namingand directory services. Using JNDI, anapplication can store information in and retrieveinformation from naming and directory services.Like other Java enterprise APIs, the beauty ofJNDI is that the application does not care whatkind of naming or directory service is being used.

Page 368: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The same API serves to access LDAP directories,OpenDirectory, ADS, NIS+, NDS, DNS, and more.Sun even provides an implementation of JNDIthat stores information in a regular filesystem.

Some of the J2EE APIs serve as abstractions forcommon kinds of architectural components inenterprise systems. JNDI is one of thesearchitectural abstractions. Enterpriseapplications talk to a JNDI service provider usingthe generic JNDI API. Figure 9-1 illustrates thisarchitecture.

Figure 9-1. The JNDI architecture

No matter what naming or directory service youare using, your application will use the exactsame JNDI calls to perform the exact samefunctions. The JNDI classes know how to find theservice providers for different services based onthe application's runtime configuration. Theseservice providers implement an API called theJNDI Server Provider Interface (SPI). The SPI isspecifically a set of Java interfaces that a serviceprovider must implement in order to give JNDIaccess to its directory service. The advantage of

Page 369: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

this approach is that you can literally switch anapplication from NIS to ActiveDirectory simply bychanging configuration information no codechanges are required. For the most current list ofservice providers, visithttp://java.sun.com/products/jndi/serviceproviders.html.

9.2.3 The Basics of JNDI Programming

A Java application basically wants to do one oftwo things with a directory service:

Find objects stored in the directory service

Bind new or modified objects to thedirectory service

Because a directory service is a read-heavy datastore, applications really spend most of the timelooking up objects stored in the directory.

9.2.3.1 InitialContext

The first JNDI code you write in any JNDIapplication is code that creates an initialcontext. A context is simply a base from whicheverything is considered relative. In your localphone book, for example, the context is yourcountry code and often an area code. Thenumbers in the phone book do not mention theircountry code or area code you just assume those

Page 370: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

values from the context. A JNDI context performsthe exact same function. The initial context issimply a special context to get you started witha particular naming and directory service. Thesimple form of initial context construction lookslike this:

Context ctx = new InitialContext( );

In this case, JNDI grabs its initializationinformation from your system properties. Inusing this format, you make it possible for anapplication to be directory service-independent.You can, however, specify your own initializationvalues by passing the properties to theInitialContext constructor:

Properties props = new Properties( );Context ctx; // Specify the name of the class that will serve// as the context factoryprops.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");ctx = new InitialContext(props);

This code will create an initial context for thefilesystem provider. You can now use thiscontext to bind Java objects to the filesystem orto look them up. The most common configurationproperties are:

java.naming.factory.initial(Context.INITIAL_CONTEXT_FACTORY)

Page 371: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

This property identifies the service providerto be used by specifying the fully qualifiedclass name of the factory class that createsthe initial context object.

java.naming.language (Context.LANGUAGE)

This property stores the languagepreferences of the user accessing thenaming or directory service. This value canbe a colon-separated list of language tags.If left unspecified, the service providerdetermines the language preference.

java.naming.security.authentication(Context.SECURITY_AUTHENTICATION)

This property stores the security level to beused by the service provider. Its value mustbe one of the following strings: "none","simple", or "strong". The security level isdependent on the service provider when thisproperty is not specified.

java.naming.security.credentials(Context.SECURITY_CREDENTIALS)

This property stores whatever data will helpauthenticate the user (principal) to thenaming or directory service. For example,

Page 372: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

this property could store a user's passwordor X.509 certificate.

java.naming.security.principal(Context.SECURITY_PRINCIPAL)

This property identifies the principal usingthe naming or directory service. The actualvalue depends on the authenticationscheme being used. For example, withusername/password authentication, thisproperty will store the username.

java.naming.security.protocol(Context.SECURITY_PROTOCOL)

This property stores text identifying thesecurity protocol to be used. For example, itmight contain the text "ssl" to specify SSL(Secure Sockets Layer). If left unspecified,the service provider can interpret thisproperty as it sees fit.

When you create a new InitialContext, theInitialContext class which implements the Contextinterface asks the service provider's initialcontext factory for an initial context. That objectthen delegates to the service provider's initialcontext to handle any operations.

9.2.3.2 Lookups

Page 373: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Lookups under JNDI are very simple. Thefollowing code finds a printer using thefileservice provider:

Printer p = (Printer)ctx.lookup("printers/laser");

This code will do a search in the directory for theobject with the matching DN. If the matchingobject is not a printer, then you will see aClassCastException.

Names are one of the tricky parts of JNDI.Specifically, each naming and directory servicehas its own name format. Examples fromdifferent domains include:

cn=GeorgeReese,ou=Web,dc=imaginary,dc=com

c=us,o=imaginary,ou=Web,cn=Sal

/usr/local/bin/python

Of course, there are also names that spanmultiple directory services. The URLhttp://www.imaginary.com/Java/index.html, forexample, references the file/prd/www/html/Java/index.html (a filename) onthe machine www.imaginary.com (a DNS name).JNDI provides the Name class to help abstractaway from naming service-specific conventions.All Context methods that look for a name as anargument will accept either a String

Page 374: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

representation of the name or a Name objectrepresentation.

Before you can look and object up in JNDI, itmust first be bound to the directory. The task ofassigning an object to a DN is called binding:

Printer = new Printer( );Context ctx = new InitialContext(props); p.setManufacturer("HP");p.setModel("LaserJet 4ML");ctx.bind("printers/Laser", p);ctx.close( );

9.2.3.3 References

This code shows JNDI returning a Java Printerobject from the directory. JNDI supports twodifferent ways of storing Java objects in adirectory:

Directly via Java serialization

Indirectly using special reference objects

The direct method stores the Java object in adirectory as binary data representing theserialized form of the Java object. Many directoryservices, however, do not understandserialization. Furthermore, not all applicationsaccessing a directory service are written in Java.JNDI therefore supports an alternate mechanism

Page 375: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

for storing Java objects in a directory in the formof references.

The JNDI Reference class enables a directoryservice to save the internal state of a Javaobject to a directory. A Reference also knows howto instantiate a copy of the desired Java objectfrom data in the directory. In order to enableyour Java objects to be stored by referenceinstead of serialization, they need to implementthe Referenceable interface. This interfaceprescribes a single method: getReference( ). Thejob of this method is to create a Referenceinstance populated with the attributes to bestored. Example 9-1 shows how a User objectmight accomplish this task.

Example 9-1. ImplementingReferenceable for storage in JNDI

import javax.naming.NamingException;import javax.naming.Reference;import javax.naming.Referenceable;import javax.naming.StringRefAddr; public class User implements Referenceable { private String email = null; private String userID = null; public User(String uid, String em) { super( ); userID = uid; em = email;

Page 376: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} public String getEmail( ) { return email; } public Reference getReference( ) throws NamingException { String cname = UserFactory.class.getName( ); Reference ref = new Reference(getClass( ).getName( ), cname, null); ref.add(new StringRefAddr("email", email)); ref.add(new StringRefAddr("userID", userID)); return ref; } public String getUserID( ) { return userID; }}

The UserFactory class referenced in the User classis used by the service provider to create a Userinstance when an application reads a User objectfrom the directory service. Example 9-2 providesan implementation of this class.

Example 9-2. A factory for Userinstances

import java.util.Hashtable;import javax.naming.NamingException;import javax.naming.Reference;

Page 377: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

import javax.naming.spi.ObjectFactory; public class UserFactory extends ObjectFactory { public UserFactory( ) { super( ); } public Object getObjectInstance(Object ob,m Name nom, Context ctx, Hashtable env) { if( ob instanceof Reference ) { Reference ref = (Reference)ob; if( ref.getClassName( ).equals(User.class.getName( )) ) { RefAddr tmp = ref.get("userID"); String uid, em; if( tmp != null ) { uid = (String)tmp.getContent( ); } tmp = ref.get("email"); if( tmp != null ) { em = (String)tmp.getContent( ); } return new User(uid, em); } } return null; }}

9.2.3.4 Attribute manipulation

Reading from a directory means more than doing

Page 378: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

straight lookups. An application will also look upobject attributes. In such cases, your applicationshould get a specific kind of context, thedirectory context. A directory context isrepresented by the JNDI class DirContext:

DirContext ctx = new InitialDirectoryContext( );

You can then grab the attributes associated witha DN using the following code:

Attributes atts = ctx.getAttributes("cn=Sal,ou=Web,dc=imaginary,dc=com");

The Attributes class is a collection holding all ofthe attributes associated with an object in thedirectory. You can get a specific attribute fromthe collection using the get( ) method:

Attribute pw = attrs.get("password");

Finally, you can access the actual attribute valueusing the Attribute class's get( ) method:

System.out.println("Your password is: " + pw.get( ));

Though getting attributes from a directory ispretty straightforward, changing them can bedownright bizarre. You have to create aModificationItem instance with an Attributerepresenting the attribute to modify. Finally, youtell the directory context to make the change:

ModificationItem[ ] changes = new ModificationItem[1];BasicAttribute attr = new BasicAttribute("password", "secret");

Page 379: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

changes[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);ctx.modifyAttributes("cn=Sal,ou=Web,dc=imaginary,dc=com", changes);

All of this code does nothing more than changeSal's password to "secret". Under this paradigm,however, you can change multiple attributes forthe same object at once. You need only addmore elements to the changes array. In addition toreplacing an attribute, you can use this API toadd a new attribute or delete an obsoleteattribute:

ModificationItem[ ] changes = new ModificationItem[2];BasicAttribute tel, cell; tel = new BasicAttribute("telephone", "+1.763.555.1778");cell = new BasicAttribute("cellphone");changes[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, tel);changes[1] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, cell);ctx.modifyAttributes("cn=Sal,ou=Web,dc=imaginary,dc=com", changes);

9.2.3.5 Searching the directory

Attributes instances are also critical to searchingthe directory for objects. To perform a simplesearch, you construct an instance ofBasicAttributeswhich implements the Attributesinterface and specify the attributes on which you

Page 380: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

wish to search:

DirContext ctx = new DirContext( );Attributes attrs = new BasicAttributes(true);NamingEnumeration res; attrs.put(new BasicAttribute("favoriteColor", "red"));res = ctx.search("ou=Web", attrs);while( res.hasMoreElements( ) ) { // process matching element}

The result, of course, is a list of all of the peoplein the web department whose favorite color isred. The true parameter passed to theBasicAttributes constructor says that we do notwant case sensitivity in our attribute matching.Each element in the resulting enumeration isactually an instance of a class called SearchResult.The SearchResult represents the object bound inthe directory service. If you want the actualobject, you can call getObject( ). On the otherhand, you can just grab its attributes if that isall you are after:

while( res.hasMoreElements( ) ) { SearchResult sr = (SearchResult)res.nextElement( ); Attributes attrs = sr.getAttributes( ); Attribute cn = attrs.get("cn"); System.out.println(cn.get( ) + " likes red!");}

This simple search is not particularly interesting.You may want to ask questions like "Who has aSocial Security number starting with 042?" or

Page 381: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Social Security number starting with 042?" or"Who has a last name of Smith?" For these morecomplex searches, you need to use searchfilters. If you are familiar with regularexpressions from languages like Perl or Python,JNDI search filters will be at least somewhatfamiliar to you. Specifically, JNDI relies on RFC2254 for defining its matching rules. Table 9-1lists the symbols included in this RFC with theirmeanings.

Table 9-1. JNDI search filter symbols fromRFC 2254

Symbol Name Description

& Conjunction The expression is true if all componentexpressions are true.

| Disjunction The expression is true if only onecomponent expression is true.

! Negation Negates the truth-value of the expression.

= EqualityThe expression is true if the attributematches the specified value in accordancewith the matching rules for that attribute.

~= Approximateequality

The expression is true if the attributecomes close to matching the specifiedvalue in accordance w ith the matchingrules for that attribute.

>= Greaterthan

The expression is true if the attribute isgreater than the specified value inaccordance w ith the matching rules forthat attribute.

Page 382: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<= Less thanThe expression is true if the attribute isless than the specified value in accordancewith the matching rules for that attribute.

=* Presence The attribute has a value, but the actualvalue is unimportant.

* Wildcard Matches zero or more characters in itsposition.

\ Escape Escapes special symbols, including ( and ),when they appear in a filter.

The format of the search filters is a bitunintuitive. Each expression is enclosed byparentheses. Two expressions may be joined bya & or | symbol. For example:

(&(cn=* Reese)(favoriteColor=red))

This expression translates to all objects in whichthe cn ends with "Reese" (i.e., a last name ofReese) and the favoriteColor value is "red". Youcan end up with some fairly LISP-like[1]

expressions on complex search filters. Thefollowing code performs a search using a morecomplex search filter:

[1] If you missed out on the joys of LISP in college, it is arather odd programming language in which all notation isin reverse-polish notation, the format shown in theexamples.

NamingResult res;String flt;

Page 383: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

flt = "(&(favoriteColor=red)(|(cn=* Reese)(cn=* Viega)))";res = ctx.search("ou=Web", flt, null);while( res.hasMoreElements( ) ) { // process results}

9.2.4 Access to Enterprise Componentsvia JNDI

If you have done any JDBC programming, youknow what a nightmare it can be to connect tothe database. Your application must bothregister a vendor-specific class with JDBC andprovide connection information specific to thatdriver, including such information as the driver-specific URL, user ID, and password. In short,your application needs to know a lot about thespecific connection requirements of a specificvendor tool to access a specific database. Theresult is a cumbersome connection process thatis too easily tied to proprietary components.

In a robust architecture, components referenceone another by name only. Just as the IPaddress for my web server can change withoutaffecting your ability to reach my web sitebecause you are using a name via a namingservice, you can code your application to findother architectural components by name byregistering them with some sort of namingservice. For JDBC, you can store databaseconfiguration information in a directory serviceunder a specific name. An application seeking adatabase connection then accesses the desired

Page 384: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database connection then accesses the desireddatabase by name. As a result, systemadministrators can change configurationinformation in the directory service without anyimpact on the production application.

JNDI is probably the single most important APIon the J2EE platform exactly because most APIsrely on a directory service to store informationabout enterprise resources. The best way toaccess JDBC and RMI is through JNDI. The onlyway to access EJB is through JNDI.

9.2.4.1 JNDI and JDBC

On the J2EE platform, an application gainsaccess to a database via JDBC's DataSource class.A DataSource instance contains all of theinformation necessary to make a connection.Using this class, an application can connectusing the following simple code:

Connection conn;DataSource ds; // some code to get a DataSource instance goes hereconn = ds.getConnection( );

So where does the application get a DataSourceinstance? Naturally, it retrieves it from adirectory service via JNDI. At deployment time, asystem administrator goes into theadministrative tool appropriate for the directoryservice being used and enters information about

Page 385: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

the database to which the DataSource shouldconnect. The system administrator then assignsa name to this DataSource and saves theconfiguration.

How the configuration actually works is naturallydependent on the directory service being used.Ideally, this information will be stored in aserialized DataSource object in the directoryservice. If the directory service is incapable ofstoring serialized Java objects, then theconfiguration tool will use an alternativemechanism. Either way, your application doesnot care. The earlier missing code looks like this:

Context ctx = new InitialContext( );Connection conn;DataSource ds; ds = (DataSource)ctx.lookup("enterpriseExamples");conn = ds.getConnection( );

9.2.4.2 JNDI and EJB

EJB, like JDBC, has a special class through whichapplications access the system. Unlike JDBC, anapplication does not seek access to the EJBapplication server as a whole, but instead tospecific business objects within the applicationserver. The special class through which thesebusiness objects are accessed is called theirhome. A Flight business object, for example,would have a FlightHome home.

Page 386: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Homes are configured during the process ofdeploying an Enterprise JavaBeans application.The EJB application server takes the informationfrom the deployment process and creates anentry in its directory service. A client then usesthe application server's JNDI implementation togain access to the deployed EJB.

In order to access a specific Flight instance, youneed to know only the name under which thehome is registered and the primary key for theflight being sought:

Context ctx = new InitialContext( );FlightHome home;Flight flight; home = (FlightHome)ctx.lookup("FlightHome");flight = home.findByPrimaryKey(somePK);

9.2.4.3 JNDI and other enterprisecomponents

You should see a pattern emerging here.Everywhere one enterprise component needs toaccess another, it does so via JNDI. All of theinformation required for that access is stored ina JNDI-supported directory. This architectureenables components to change drasticallywithout any effect on the other components inthe system. The freedom to reconfigurecomponents in a runtime is critical to scalability.For example, an application that was launched

Page 387: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

with the web server, application server, anddatabase server all on the same physicalmachine can be reconfigured to run on threedifferent machines without requiring any codechanges or regression testing.

Page 388: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

9.3 JavaServer Pages

JavaServer Pages are the Java way to build web-based user interfaces using Java as a scriptinglanguage for generating dynamic XHTML.[2] Inother words, JSP enables you to embed Javacode inside your XHTML so that the full contentof the XHTML page can be dependent on thestate of the system when a user requests apage. Example 9-3 shows your obligatory "HelloWorld" application as a JSP page.

[2] JSPs are not limited to XHTML. They can generateHTML, XML, or any other kind of textual markup.

Example 9-3. A simple JSP page

<%@ page info="Hello World" %> <% String msg = "Hello World!"; %> <html> <head> <title><%=msg%></title> </head> <body> <h1><%=msg%></h1> <p> Though this example is largely uninteresting, it does demonstrate how Java can be embedded in an XHTML page to generate content dynamically. </p> </body></html>

As with any "Hello World" application, this one ismind-numbingly dull. What you should take fromit, however, is the basic structure that enablesyou to call methods in Java objects and drive

Page 389: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

content from Java values. Though I used asimple String instance in this example, the <title>and <h1> values could have been drawn from adatabase.

The web server or application server in which theJSP runs interprets anything between <% and%> as Java code and anything between <%=and %> as values to be printed out. When arequest is made for a JSP page, that page isturned into a Java object. Your embedded Javacode becomes part of that compilation. TheXHTML in your page becomes a string to sendout. The server then executes the method intowhich your Java code was compiled.

This compile happens only once as long as theserver remains running and no one changes theJSP source. If you make a change to the JSPsource, however, the server will recompile it thenext time it is requested.

JSPs become interesting when you hook them upto an EJB system or a database. Naturally, wewill be doing just that throughout Part II of thisbook. This section simply describes the basicsbehind JavaServer Pages.

9.3.1 Page Structure

A JSP page consists of static content, JSPdirectives, Java code, and JSP tags:

Static content

Static content is the XHTML into which yourJSP code is embedded.

JSP directives

Page 390: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

These elements appear between <%@ and%> markers. They indicate directives to theserver prior to compiling the JSP page.

Java code

Java code is everything between <% and%> and between <%= and %> tags. Thiscode is executed for each page view.

JSP tags

A JSP tag is an XML-like interface into alibrary of Java code. The JSP specificationprescribes a core set of tags, but you canadd your own through custom tag libraries.

As a general rule, the fewer lines of Java code inyour JSP page, the better. When you add a lot ofJava code to a JSP page, you, in a sense, defeatthe purpose of using JSPs over the Java ServletAPI. Specifically, defining your user interface asa set of JSPs enables you to transfer the work ofuser interface writing to XHTML programmersinstead of Java programmers. This transferhopefully results in more creative resourcesbeing responsible for UI development.

9.3.2 JSP Programming

Example 9-4 provides a more typical JSP pagethan the "Hello World" code in Example 9-3.

Example 9-4. A JSP page thatdrives content from a contentmanagement database

Page 391: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

<%@ page info="Page Loader" %><%@ page import="org.dasein.tractatus.jsp.ErrorLog" %><%@ page import="org.dasein.tractatus.jsp.Tractatus" %> <%@ taglib uri="/WEB-INF/tld/tractatus.tld" prefix="tractatus" %> <jsp:useBean id="user" scope="session" class="org.dasein.security.User"/><% pageContext.setAttribute(Tractatus.USER, user); %><% user.setPreferredLocale(request.getLocale( )); %> <tractatus:setTarget/> <% pageContext.setAttribute("template", target.getTemplate( )); %><% if( target.getContent( ) != null ) { %> <% pageContext.setAttribute("contentTemplate", target.getContent( ).getTemplate( )); %><% } else { %> <% pageContext.setAttribute("contentTemplate", null); %><% } %> <tractatus:authorize> <tractatus:allowed> <tractatus:isNull name="template"> <tractatus:true> <tractatus:isNull name="contentTemplate"> <tractatus:true> <tractatus:printContent/> </tractatus:true> <tractatus:false> <jsp:include page="<%=target.getContent( ).getTemplate( ).getRelativeURL( )%>"/> </tractatus:false> </tractatus:isNull> </tractatus:true> <tractatus:false> <jsp:include page="<%=target.getTemplate( ).getRelativeURL( )%>"/> </tractatus:false> </tractatus:isNull> </tractatus:allowed> <tractatus:denied> <% String msg = "<p class=\"error\">Access denied.</p>"; %> <jsp:include page="page.jsp"> <jsp:param name="target"

Page 392: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

value="<%=target.getSite( ).getErrorPage( ).getPageID( )%>"/> <jsp:param name="error" value="<%=ErrorLog.storeException(msg)%>"/> </jsp:include> </tractatus:denied> <tractatus:unauthenticated> <% response.sendRedirect(target.getSite( ).getLoginPage( ).getRelativeURL( ) + "&previous=" + target.getPageID( )); %> </tractatus:unauthenticated></tractatus:authorize>

Though all of the content for this page isdynamically generated, very little of it is directJava code. It starts out with three directives:

<%@ page info="Page Loader" %><%@ page import="org.dasein.tractatus.jsp.ErrorLog" %><%@ page import="org.dasein.tractatus.jsp.Tractatus" %> <%@ taglib uri="/WEB-INF/tld/tractatus.tld" prefix="tractatus" %>

The first directive provides metainformationabout the JSP page for tools. The second andthird directives tell the server what Java importstatements to use for this page when compilingit. The final one tells the server where to finddefinitions for the custom tags in use in thispage.

Only the last directive requires any elaboration.When you build a library of Java objects that canserve as JSP tags, you need to create an XMLdescriptor file that maps tag names to Javaclasses. The uri value for the taglib directivepoints to this XML file. The prefix value thennames what prefix will appear for the tags inthis JSP page. In this case, the prefix istractatus.

You will use the tag in the next line of code,<jsp:useBean>, in almost all of your JSP pages. Itenables you to store and access a regularJavaBean as part of the user session

Page 393: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

information. In this case, I am storing a Userobject representing the site visitor.

The next two lines are the first bit of actual Javacode:

<% pageContext.setAttribute(Tractatus.USER, user); %><% user.setPreferredLocale(request.getLocale( )); %>

You probably gather that the user variable in thesecond line comes from the call to <jsp:UseBean>.On the other hand, it is entirely unclear wherethe pageContext variable comes from. A JSP pagedefines several page-level variables to which youhave access. The two you will most commonlyuse are pageContext and request. The pageContextvariable represents information about thecontext of the page execution. In this example, Iam setting an attribute that can be used by mycustom tags. The Tractatus.USER constant issimply a String constant for "user".[3]

[3] I believe it is a good solid practice never to have literalvalues in your source code, except as constantdefinitions. This line reflects that practice.

The other variable you will commonly need,request, represents the HTTP request coming infrom the browser. It contains information aboutthe requester and the headers of the request. Inthe second line, I am looking forinternationalization information from therequest. Specifically, I am trying to find out whatlocales the browser is set to accept.

The next line is the first custom tag in this JSPpage:

<tractatus:setTarget/>

Behind this tag's simplicity is some complex Javacode for setting a variable named target to acustom Java object of type org.dasein.tractatus.Pagebased on the request sent to the server. For

Page 394: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

example, if the URL washttp://www.imaginary.com/page.jsp?target=5,then the <tractatus:setTarget> tag will go to thedatabase, find the Page with a pageID of 5, andthen set the target variable to that Page instance.

Perhaps you can imagine the level of complexityI would have added to this page had I nothidden everything behind a JSP tag. Now, XHTMLprogrammers do not need to know anythingabout looking up custom objects hidden in adatabase. They simply include this one emptytag and they are all set.

The rest of the code is mostly custom tags witha small mix of Java code. In short, it does thefollowing:

1. Verifies that the user has access to therequested page.

Verifies that the user is disallowed, allowed,or not yet authenticated:

If disallowed, the user is redirected to apage telling him he does not have theproper permissions.

If allowed, the user is shown the actualcontent through the <jsp:include> tags.

If the user has yet to be authenticated andthe web page is not open to the public, theuser is redirected to a login page.

9.3.3 Custom Tags

The power of JavaServer Pages lies in the abilityto build reusable Java components and then hidethem behind custom tags. The creation ofcustom tags is quite simple. You write a class

Page 395: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

that implements a specific API and then mapthat class to a tag name via an XML descriptorfile. A simple custom tag looks like Example 9-5.

Example 9-5. A simple custom tag

package org.dasein.tractatus.jsp;

import java.io.IOException;import java.util.Locale;

import javax.servlet.ServletRequest;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;

import org.dasein.persist.PersistenceException;import org.dasein.security.User;import org.dasein.tractatus.Page;

public class HTMLTitleTag extends TagSupport { public int doEndTag( ) throws JspException { try { Page p = (Page)pageContext.getAttribute(Tractatus.TARGET); User u = (User)pageContext.getAttribute(Tractatus.USER); Locale def = p.getSite( ).getDefaultLocale( ); String ttl;

ttl = "<title>" + p.getTitle(u.getPreferredLocale(def)) + "</title>"; pageContext.getOut( ).println(ttl); } catch( IOException e ) { throw new JspException(e.getMessage( )); } catch ( PersistenceException e ) { throw new JspException(e.getMessage( )); } return EVAL_PAGE; }}

Page 396: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

This custom tag extends the TagSupport classfrom the JSP API and implements a singlemethod, doEndTag( ). This method is triggeredwhen the server reaches the end tag of yourcustom tag. Because this particular tag is anempty tag, the end happens right after the start.In this example, the tag finds the current targetvalue (previously set by <tractatus:setTarget>) aswell as the current user value (previously set by<jsp:useBean>). It then prints out the XHTML forthe page's title translated into the user'spreferred language.

To add this tag to the web site, you need to editthe XML tag library descriptor file to map a tagname to this class. If this tag were the only tagin the tag library, the descriptor file would looklike Example 9-6.

Example 9-6. Sample tagdescriptor

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1/EN""http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

<tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <shortname>tractatus</shortname>

<tag> <name>htmlTitle</name> <tagclass>org.dasein.tractatus.jsp.HTMLTitleTag</tagclass> <bodycontent>empty</bodycontent> </tag>

</taglib>

Page 397: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The code in bold shows the definition of thecustom tag. It maps the name htmlTitle to theclass org.dasein.tractatus.jsp.HTMLTitleTag andestablishes the constraint that the tag should bean empty tag. Consequently, whenever theserver encounters the following in a JSP page:

<tractatus:htmlTitle/>

The server prints out the title of the pagereferenced by the target variable localized for theuser.

Custom tags do get more complicated. Somecontain XHTML code, while others contain othercustom tags. A full description of this API is wellbeyond the scope of this book. For moreinformation, take a look at JavaServer Pages(O'Reilly) by Hans Bergsten.

Page 398: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

9.4 Remote Method Invocation

The object is the center of the Java world.Distributed object technologies provide theinfrastructure that enables two objects runningon two different machines to talk to each otherusing an object-oriented paradigm. Usingtraditional networking, you need to write IPsocket code to let two objects on differentmachines communicate. While the socket-basedapproach works, it is prone to error. The idealsolution is to let the Java virtual machine do thework. You call a method in an object, and thevirtual machine determines where the object islocated. If it is a remote object, it will performall the dirty network work for you.

Several technologies, like the Common ObjectRequest Broker Architecture (CORBA), predateJava. CORBA enables developers to provide aclean, distributed programming architecture.CORBA has a very wide reach and is wroughtwith complexities associated with its grandiosegoals. For example, it supports applicationswhose distributed components are written indifferent languages. In order to supporteverything from writing an object interface in Cto handling more traditional object languagessuch as Java and Smalltalk, it has built up anarchitecture with a very steep learning curve.

CORBA does its job very well, but it does a lotmore than you need in a pure Java environment.This extra functionality has a cost in terms ofprogramming complexity. Unlike otherprogramming languages, Java has distributed

Page 399: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

support built into its core. Borrowing heavilyfrom CORBA, Java supports a simpler, pure Javadistributed object solution called RMI.

9.4.1 The Structure of RMI

RMI is an API that enables you to ignore the factthat you have objects distributed all across thenetwork. You write Java code that calls methodsin remote objects using the same semantics youuse in calling local methods. The biggestproblem with providing this kind of API is thatyou are dealing with two separate virtualmachines existing in two separate memoryaddress spaces. Consider, for example, thesituation in which you have a Bat object thatcalls hit( ) in a Ball instance. Located together onthe same virtual machine, the method call lookslike this:

ball.hit( );

You want RMI to use the exact same syntaxwhen the Bat instance is on one machine and theBall instance is on another. The problem is thatthe Ball instance does not exist inside theclient's memory. How can you possibly trigger anevent in an object to which there is noreference? The first step is to get a reference.

9.4.1.1 Remote object access

I am going to co-opt the term server for aminute and use it to refer to the virtual machine

Page 400: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

that holds the real copies of one or moredistributed objects. In a distributed objectsystem, you can have a single host (generallycalled an application server) act as an objectservera place from which clients get remoteobjects or you can have all systems act as objectservers. Clients simply need to be aware ofwhere the object server(s) is located.[4] Anobject server has a single defining function: tomake objects available to remote clients.

[4] Using JNDI, they do not even need to know where theserver is. Clients just look up objects by name, and thenaming and directory service knows where the server is.You w ill see this in practice later in the chapter when youread about EJB.

A special program called rmiregistry that comeswith the JDK listens to a port on the objectserver's machine. The object server in turn bindsobject instances to that port using a special URLso clients can later find it. The format of the RMIURL is rmi://server/object. A client then usesthat URL to find a desired object. For theprevious bat and ball example, the ball would bebound to rmi://athens.imaginary.com/Ball. Anobject server binds an object to a URL by callingthe static rebind( ) method of java.rmi.Naming:

Naming.rebind("rmi://athens.imaginary.com/Ball", new BallImpl( ));

The rmi://athens.imaginary.com portion of thepreceding URL is self-evident; you cannot bindan object instance to a URL on another machinein a secure environment. Naming allows you torebind an object using only the object name forshort:

Page 401: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Naming.rebind("Ball", new BallImpl( ));

In RMI, binding is the process of associatingan object w ith an RMI URL. The rebind( )method specifically creates this association.At this point, the object is registered w ith thermiregistry application and is available toclient systems. Reference by any system to itsURL is thus specifically a reference to thebound object.

The rebind( ) methods make a specific objectinstance available to remote objects that do alookup on the object's URL. This is where lifegets complicated. When a client connects to theobject URL, it cannot get the object bound tothat URL. That object exists only in the memoryof the server. The client needs a way to foolitself into thinking it has the object while routingall method calls in that object over to the realobject. RMI uses Java interfaces to provide thissort of hocus-pocus.

9.4.1.2 Remote interfaces

All Java objects that you intend to makeavailable as distributed objects must implementan interface that extends the RMI interfacejava.rmi.Remote. You call this step making anobject remote. You might do a quick double takeif you look at the source code for java.rmi.Remote.It looks like this:

Page 402: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

package java.rmi; public interface Remote {}

No, there is no typo there. The interfaceprescribes no methods to be implemented. Itexists so that objects in the virtual machines onboth the local and remote systems have acommon base class they can use for deriving allremote objects. They need this base class sincethe RMI methods look for subclasses of Remoteas arguments.

When you write a remote object, you have tocreate an interface that extends Remote andspecify all methods that can be called remotely.Each of these methods must throw aRemoteException in addition to any application-specific exceptions. In the bat and ball example,you might have had the following interface:

public interface Ball extends java.rmi.Remote { void hit( ) throws java.rmi.RemoteException; int getPosition( ) throws RemoteException;}

The BallImpl class implements Ball. It might looklike:

import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject; public class BallImplextends UnicastRemoteObject implements Ball { private int position = 0;

Page 403: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public Ball( ) throws RemoteException { super( ); } public int getPosition( ) { return position; } public void hit( ) { position += calculateDistance( ); } protected int calculateDistance( ) { return 10; }}

The java.rmi.server.UnicastRemoteObject class thatthe BallImpl extends provides support forexporting the ball; that is, it allows the virtualmachine to make it available to remote systems.This may look like what the Naming class does,but it has a different purpose. Naming ensuresthat the object is bound to a particular URL,while exporting an object enables it to bereferenced across the network. This means thatyou can pass the object as a method argumentor return it as a return value. It also means thatyou can use Naming.rebind( ) to make the objectavailable through a URL lookup. A URL lookuplooks like this:

ball = (Ball)Naming.lookup("rmi://athens.imaginary.com/Ball");

Because you have just read about JNDI, youmight wonder why RMI forces you to knowwhere the object is located instead of using a

Page 404: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

simple JNDI name. The answer is simple: RMIpredates JNDI. JNDI now, however, offers aservice provider supporting RMI lookups.

Because you may not have the option ofextending UnicastRemoteObject, you can exportyour objects another way using this syntax inthe object constructor:

public BallImpl( ) throws RemoteException { super( ); UnicastRemoteObject.exportObject(this);}

Both approaches are equally valid. The onlydifference is the structure of your inheritancetree.

After writing both classes, you compile them justlike any other object. This will, of course,generate two .class files, Ball.class andBallImpl.class.The final step in making theBallImpl class distributed is to run the RMIcompiler, rmic, against it. In this case, run rmicusing the following command line:

rmic BallImpl

Like the java command and unlike the javaccommand rmic takes a fully qualified class nameas an argument. This means that if you had theBall class in a package called baseball, you wouldrun rmic as:

rmic -d classdir baseball.Ball

Page 405: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In this case, classdir represents whatever the rootdirectory for your baseball package class files is.This directory will likely be in your CLASSPATH.The output of rmic will be two classes:Ball_Skel.class (the skeleton) andBall_Stub.class (the stub). These classes will beplaced relative to the classdir you specified on thecommand line.

9.4.1.3 Stubs and skeletons

I have introduced a couple of concepts, stub andskeleton, without any explanation. They are twoobjects you should never have to concernyourself with, but they do all of the heavy liftingthat makes remote method calls work. In Figure9-2, I show where these two objects fit in aremote method call.

Figure 9-2. The process of callinga method in a remote object

Page 406: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The process of translating a remote method callinto network format is called marshaling; thereverse is called unmarshaling. When you runthe rmic command on your remote-enabledclasses, it generates two classes that performthe tasks of marshaling and unmarshaling. Thefirst of these is the stub object, a special objectthat implements all of the remote interfacesimplemented by the remote object. Thedifference is that where the remote objectactually performs the business logic associatedwith a method, the stub takes the arguments tothe method and sends them across the networkto the skeleton object on the server. In otherwords, it marshals the method parameters andsends them to the server. The skeleton object,in turn, unmarshals those parameters; it takesthe raw data from the network, translates it intoJava objects, and then calls the proper methodin the remote object.

The skeleton and stub perform the reverse rolesfor return values. The skeleton takes the return

Page 407: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

value from the method and sends it across thenetwork. The client stub then takes the rawsocket data and turns it into Java data, returningthat Java data to the calling method.

9.4.1.4 Remote exceptions

All methods that can be called remotely and allconstructors for remote objects must throw aspecial exception called java.rmi.RemoteException.The methods you write will never explicitly throwthis exception. Instead, the local virtual machinewill throw it when you encounter a network errorduring a remote method call. Examples of suchsituations include one of the machines crashingor a loss of connectivity between the twomachines.

A RemoteException is unlike any other exception.When you write an application to be run on asingle virtual machine, you know that if yourcode is solid, you can predict potentialexceptional situations and where they mightoccur. You can count on no such predictabilitywith a RemoteException. It can happen at any timeduring the course of a remote method call, andyou may have no way of knowing why ithappened. You therefore need to write yourapplication code with the knowledge that at anypoint your code can fail for no discernible reasonand have contingencies to support such failures.

9.4.2 Object Serialization

Page 408: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Not all objects that you pass between virtualmachines are remote. In fact, you need to beable to pass the primitive Java data types aswell as many basic Java objects, such as String orHashMap, that are not remote. When a nonremoteobject is passed across virtual machineboundaries, it gets passed by value using objectserialization instead of the traditional Java RMIway of passing objects, by reference. Objectserialization is a feature that enables you toturn objects into a data stream that you can usethe way you use other Java streams send it to afile, over a network, or to standard output. Whatis important about this method of passingobjects across virtual machines is that changesyou make to the object on one virtual machineare not reflected in the other virtual machine.

Most of the core Java classes are serializable. Ifyou wish to build classes that are not remotebut need to be passed across virtual machines,you need to make those classes serializable. Aserializable class minimally needs to implementjava.io.Serializable. For almost any kind ofnonsensitive data you may want to serialize,just implementing Serializable is enough. You donot even need to write a method; Object alreadyhandles the serialization for you. It will,however, assume that you do not want theobject to be serializable unless you implementSerializable. Example 9-7 provides a simpleexample of how object serialization works. Whenyou run it, you will see the SerialDemo instance inthe second block display the values of the onecreated in the first block.

Page 409: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Example 9-7. A simpledemonstration of objectserialization

import java.io.*; public class SerialDemo implements Serializable { static public void main(String[ ] args) { try { { // Save a SerialDemo object with a value of 5 FileOutputStream f = new FileOutputStream("/tmp/testing.ser"); ObjectOutputStream s = new ObjectOutputStream(f); SerialDemo demo = new SerialDemo(5); s.writeObject(demo); s.flush( ); } { // Now restore it and look at the value FileInputStream f = new FileInputStream("/tmp/testing.ser"); ObjectInputStream s = new ObjectInputStream(f); SerialDemo demo = (SerialDemo)s.readObject( ); System.out.println("SerialDemo.getVal( ) is: " + demo.getVal( )); } } catch( Exception e ) { e.printStackTrace( ); } } int test_val = 7; // value defaults to 7 public SerialDemo( ) { super( );

Page 410: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} public SerialDemo(int x) { super( ); test_val = x; } public int getVal( ) { return test_val; }}

Page 411: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

9.5 Enterprise JavaBeans

RMI is a distributed object API. It specifies howto write objects so that they can talk to oneanother no matter where on the network theyare found. I could write dozens of businessobjects that can, in principal, talk to yourbusiness objects using RMI. At its core, however,RMI is nothing more than an API to which yourdistributed objects must conform. RMI saysnothing about other characteristics normallyrequired of an enterprise-class distributedenvironment. For example, it says nothing abouthow a client might perform a search for RMIobjects matching some criteria. It also saysnothing about how those objects might worktogether to construct a single transaction.

What is missing from the picture is a distributedcomponent model. A component model is astandard that defines how components arewritten so that systems can be built fromcomponents by different authors with little or nocustomization. You may be familiar with theJavaBeans component model. It is a componentmodel that defines how you write user interfacecomponents so that they may be plugged intothird-party applications. The magic thing aboutJavaBeans is that there is very little API behindthe specification you neither implement norextend any special classes and you need call nospecial methods. The force of JavaBeans is

Page 412: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

largely in conformance with an establishednaming convention.

Enterprise JavaBeans is a more complexextension of this concept. While there are APIelements behind Enterprise JavaBeans, it ismuch more than just an API. It is a standardway of writing distributed components so thatthe components I write can be used with thecomponents you write in someone else's system.RMI does not support this ability for severalreasons. Consider all of the following issues RMIdoes not address:

Security

RMI says nothing about security. RMI alonebasically leaves your system wide open.Anybody who has access to your RMIinterfaces can forge access to theunderlying components. Unless you writesome complex security checks toauthenticate clients and verify access, youwill have no security. Your components aretherefore unlikely to interoperate with mycomponents unless we agree to share somesort of security model.

Searching

Page 413: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

RMI provides the ability to do a lookup foronly a specific, registry-bound object. Itsays nothing about how you find unboundobjects or perform searches for a group ofobjects meeting certain requirements.Writing a banking application, you mightwant to support the ability to find allaccounts with negative balances. In order todo this in an RMI environment, you wouldhave to write your own search methods inbound objects. Again, your custom approachto handling searches simply won't work withsomeone else's custom approach tosearching without forcing clients to dealwith both search models.

Transactions

Perhaps the most important piece to adistributed component model is support fortransactions. RMI says absolutely nothingabout transactions. When you build an RMI-based application, you will need to addresshow you will support transactions. In otherwords, you will need to keep track of whena client begins a transaction, what RMIobjects that client changes, and committingand rolling back those changes when theclient is done. This problem is compoundedby the fact that most distributed objectsystems are supporting more than one

Page 414: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

client at a time. Different transactionmodels are even more incompatible thandifferent search or security models. Whileclient coders can get around differences insearch and security models by being awareof those differences, transaction models canalmost never be made to work together.

Persistence

RMI says nothing about how RMI objectspersist across time. Over the course of thisbook, I will introduce several differentpersistence models. EJB is behind three ofthese persistence models.

Enterprise JavaBeans addresses all of thesepoints and more so that you can literally pickand choose the best designed businesscomponents from different vendors and makethem work and play well with one another in thesame environment. EJB is now the standardcomponent model for capturing distributedbusiness components. It hides from you thedetails you might have to worry about yourself ifyou were writing an RMI application.

9.5.1 EJB Roles

One of the benefits of the EJB approach is that it

Page 415: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

separates different application developmentroles into distinct parts so that everything onerole does is usable by any possible player of anyof the other roles. EJB specifically defines thefollowing roles:[5]

[5] Any given role may be played by multiple players on aproject. Similarly, one person may play multiple roles.

The EJB provider

The EJB provider is an expert in the problemdomain in question and develops Javaobjects that capture the business conceptsthat make up the problem domain. The EJBprovider worries about nothing other thanbusiness logic programming.

The application assembler

The application assembler is an expert inthe processes that make up a business andin building user interfaces that employ theEJB provider's business components.

The deployer

The deployer is an expert in a specific

Page 416: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

operating environment. The deployer takesan assembled application and configures itfor deployment in the runtime environment.

The EJB server provider

A server provider supports one or moreservices, such as a JDBC driver supportingdatabase access.

The EJB container provider

The container is where EJB components live.It is the runtime environment in which thebeans operate. The container provider is avendor that builds the EJB container.

The system administrator

The system administrator manages theruntime environment in which EJBcomponents operate.

An EJB provider captures each of the businesscomponents that model a business in Java code.The EJB specification breaks down each of thesebusiness components into three pieces: thehome interface, the remote interface, and the

Page 417: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

bean implementation. Your job as the EJBprovider is thus to write these three classes foreach business component in your system.

9.5.2 Kinds of Beans

EJB specifies two kinds of beans: entity beansand session beans. The distinction between thetwo is that entity beans are persistent andsession beans are transient. In other words,entity beans save their states across time whilesession beans do not. Most business conceptswill work best as entity beans they are theentities that make up your business. Entitybeans are shared by all clients.[6]

[6] This is not necessarily true of all environments.Specifically, EJB allows for a clustered environment inwhich multiple application servers work together to serveup beans. In such an environment, the same entity mayappear on different servers and serve different clients.The containers are responsible in those situations formaking the system appear as if the clients share thesame entity reference.

Session beans are unique to each client. Theycome to life only when requested by a client.When that client is done with them, they goaway. An example of a session bean might be aRegistration class that represents the registrationof a person for some event. The Registrationexists for a specific client to associate a personwith an event. It manages the business logic

Page 418: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

associated with a registration, but it goes awayonce the registration is complete. The persistentdata is in the Person and Event classes.

The word bean is a heavily overloaded term inJava. Even w ithin the EJB specification, theword bean has different meanings in differentcontexts. It can mean one of the threeclasses called the bean implementation or itcan mean the business concept as a whole. Itake the approach of using the term beanalone to mean the business componentrepresented by the three EJB classes and theterm bean implementation to mean the oneclass that implements the business logic.

The home and remote interfaces for both kindsof beans are RMI remote interfaces. That is, theyare indirectly derived from the java.rmi.Remoteinterface and are exported for remote access.The class extended by a remote interface isEJBObject. If, for example, you wanted to turn theBall object from earlier in the chapter into anentity bean, you would create a BallHomeinterface, a Ball interface, and a BallBeanimplementation. The Ball interface would extendjavax.ejb.EJBObject, which in turn extendsjava.rmi.Remote. The result might be a class thatlooks like this:

public interface Ball extends javax.ejb.EJBObject { void hit( ) throws java.rmi.RemoteException;

Page 419: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

int getPosition( ) throws RemoteException;}

This interface looks a lot like the RMI examplefrom earlier in the chapter. In fact, the onlydifference is that this one extends Remoteindirectly via EJBObject. The interface specifiesonly those methods that should be madeavailable to the rest of the world.

The home interface is where you go to find orcreate instances of the bean. It specifiesdifferent versions of create( ) or findXXX( )[7]

methods that enable a client to create newinstances of the bean or find existing instances.If you think about the problem of a bankingsystem, they might have account beans,customer beans, and teller beans. When thebank attracts a new customer, its enterprisebanking system needs to create a Customer beanto represent that customer. The bank manager'sW indows application that enables theregistration of new customers might have thefollowing code for creating a new Customer bean:

[7] Only entity beans have finder methods.

InitialContext ctx = new InitialContext( );CustomerHome custhome;Customer cust; custhome = (CustomerHome)ctx.lookup("CustomerHome");

Page 420: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

cust = custhome.create(ssn);

This code provides you with your first look atJNDI support in EJB. Using a JNDI initial context,you look up an implementation of the customerbean's home interface. That home interface,CustomerHome, provides a create( ) method thatenables you to create a new Customer bean. Inthe preceding case, the create( ) method acceptsa String representing the customer's SocialSecurity number.[8] The EJB specification requiresthat a home interface specify create( ) signaturesfor each way to create an implementation of thatbean. The CustomerHome interface might look likethis:

[8] A Social Security number is a U.S. federal tax identifier.

public interface CustomerHome extends EJBHome { Customer create( ) throws CreateException, RemoteException; Customer create(String ssn) throws CreateException, RemoteException; Customer findByPrimaryKey(CustomerKey pk) throws FinderException, RemoteException; Customer findBySocialSecurityNumber(String ssn) throws FinderException, RemoteException;}

The finder methods provide ways to look upCustomer objects. All except the findByPrimaryKey( )

Page 421: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

method can be named however you wish toname them, and they should return either aremote reference to the bean in question or aCollection.

The findByPrimaryKey( ) method is a special finderfor EJBs. Each entity bean instance has a primarykey that uniquely identifies it. The primary keycan be any serializable Java class you write. Theonly requirement is that the class mustimplement the equals( ) and hashCode( ) in anappropriate fashion. For example, if your beanshave a unique numeric identifier, you mightcreate your own CustomerKey class that stores theidentifier as a long. If you do the latter, yourCustomerKey class should look something like thefollowing:

public class CustomerKey implements Serializable { private long objectID = -1L; public CustomerKey(long l) { objectID = l; } public boolean equals(Object other) { if( other instanceof CustomerKey ) { return ((CustomerKey)other).objectID = = objectID; } return false; } public int hashCode( ) {

Page 422: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

return (new Long(objectID)).hashCode( ); }}

You can even use primitive wrapper classesinstead of custom primary key classes. Thefollowing example, for instance, could just aseasily have used the Long class for its primarykeys.

You do not actually write the class thatimplements the Customer or CustomerHomeinterfaces that is the task of the EJB container.Generally, the EJB container will have tools thatenable a deployer to automatically create andcompile implementation classes for the homeand remote interfaces. These automaticallygenerated classes handle issues such as securityand then delegate to your bean implementationclass. The bean is where you write your businesslogic.

The bean class must implement the followingmethods:

It must implement every method in theclass it implements: EntityBean for entitybeans and SessionBean for session beans.

It must implement every method in theremote interface using the exact samesignatures found in the remote interface.

Page 423: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

It must implement a variation of themethods in the home interface.[9] For create() methods, it must implement counterpartscalled ejbCreate( ) that each takes the samearguments but returns a primary key object.Similarly, the findXXX( ) counterparts forentities are ejbFindXXX( ) methods that eachtakes the same arguments and returnseither a primary key object or a collection ofprimary keys.

[9] This applies only to beans using bean-managedpersistence. For container-managed beans, thecreates and finds are implemented by thecontainer.

Consider that the Customer remote interface forthe previous home interface looks like this:

public interface Customer extends EJBObject { String getSocialSecurityNumber( ) throws RemoteException;}

A skeleton of the bean implementation mightlook something like this (minus the methodbodies):

public class CustomerBean implements EntityBean { private transient EntityContext context = null; private String ssn = null; public void ejbActivate( ) throws RemoteException { // you will mostly leave this method empty // activation of resources required by

Page 424: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

// an object of this type independent of the // customer it represents belong here // an example might be opening a file handle // for logging } public CustomerKey ejbCreate( ) throws CreateException { // this method creates a primary key for the // customer and inserts the customer into the // database } public CustomerKey ejbCreate(String ssn) throws CreateException { // this method works the same as ejbCreate( ) } public CustomerKey ejbFindByPrimaryKey(CustomerKey pk) throws FinderException, RemoteException { // this method goes to the database and performs // a SELECT and returns the PK if it is in the // database } public CustomerKey ejbFindBySocialSecurityNumber(String ssn) throws FinderException { // this method goes to the database and performs // a SELECT and returns the PK of the row // with a matching SSN } public void ejbLoad( ) throws RemoteException { // this method goes to the database and selects

Page 425: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

// the row that has this object's primary key // and then populates this object's fields } public void ejbPassivate( ) throws RemoteException { // this method is generally empty // you should release any system resources held // by this object here } public void ejbPostCreate( ) { // this is called to let you do any initialization // for this object after ejbCreate( ) is called and // a primary key is assigned to the object } public void ejbRemove( ) throws RemoteException { // this method goes to the database and deletes // the record with a primary key matching this // object's primary key } public void ejbStore( ) throws RemoteException { // this method goes to the database and saves // the state of this bean } public String getSocialSecurityNumber( ) { // this method is from the Customer remote interface return ssn; } public void setEntityContext(EntityContext ctx)

Page 426: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

throws RemoteException { // this method assigns an EntityContext to the // bean context = ctx; } public void unsetEntityContext( ) throws RemoteException { // this method removes the EntityContext assignment context = null; }}

JDBC comes into play under the bean-managedpersistence model in the ejbCreate( ), ejbFindXXX( ),ejbLoad( ), ejbStore( ), and ejbRemove( ) methods.Chapter 6 describes the details of bean-managedpersistence. Under container-managedpersistence, you do not worry about anypersistence issues. EJB supports two distinctcontainer-managed persistence models. The oldmodel, EJB 1.x persistence, did not work well atall. The newer model, EJB 2.x persistence, isvery promising though not yet widelyimplemented in production systems. Chapter 5covers container-managed persistence.

The book Enterprise JavaBeans (O'Reilly) byRichard Monson-Haefel contains a more completediscussion of EJB development.

Page 427: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 428: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 10. SQLBeing a part of a sentence is a Normalcondition for proper performance of everyelementary sentence part. But it is alsomore than a Normal condition. I t is anecessary condition. For just what eachelement is supposed to do cannot bedefined except in relation to the rest of thesentence .

Ruth Garrett Millikan, Language, Thought,and Other Biological Categories

SQL often apocryphally referred to as theStructured Query Language is the vehicle forcommunication with relational databases. Onceyou learn SQL, you are in command of the basictool for talking to Oracle, DB2, MySQL, SQLServer, Ingres, PostgreSQL, Informix, mSQL,Sybase, Access, and any other relationaldatabase engine. Other query languages likeOQL (Object Query Language) exist, but theytend to support interaction with other kinds (i.e.,not relational) of databases. Even when you areaccessing your database through a GUI tool or ahigher-level abstraction, somewhere under thehood SQL is probably in play.

Page 429: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SQL is a sort of "natural" language. In otherwords, an SQL[1] statement should read at leaston the surface like a sentence of English text.This approach has both benefits and drawbacks,but the end result is a language unliketraditional programming languages such as Javaand C.

[1] SQL is pronounced "ess-que-el." Some people get veryoffended when you mispronounce it. A sufficient numberof people do mispronounce it nevertheless. Consequently,the mispronunciation "sequel" is nearly as valid as theproper pronunciation in spite of the protests of purists

Page 430: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

10.1 Background

SQL is "structured" in the sense that it follows avery specific set of rules. A computer programcan parse a formulated SQL query easily. In fact,the O'Reilly book lex & yacc by John Levine,Tony Mason, and Doug Brown implements anSQL grammar to demonstrate the process ofwriting a program to interpret a programminglanguage! A query is a fully specified commandsent to the database server. The databaseserver then performs the requested action.Here's an example of an SQL query:

SELECT name FROM Person WHERE name LIKE 'Stac%';

This statement reads almost like a form ofbroken English: "Select names from a list ofpersons where the names are like `Stac'." SQLuses few of the formatting and specialcharacters generally associated with computerlanguages.

10.1.1 The SQL Story

IBM invented SQL in the 1970s, shortly after Dr.E. F. Codd invented the concept of a relationaldatabase. From the beginning, SQL was an easy-to-learn yet powerful language. It resembles anatural language, so it is less daunting to anontechnical person. In the 1970s, even morethan today, this advantage was important. There

Page 431: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

were no casual hackers; you were a hardcoreprogrammer or did not program at all. Thepeople who programmed computers kneweverything about how a computer worked. SQLwas aimed at the army of nontechnicalaccountants and business and administrativestaff who would benefit from accessing thepower of a relational database.

SQL was so popular with its target audience, infact, that in the 1980s, the Oracle Corporationlaunched the world's first publicly availablecommercial SQL system. Oracle SQL was a hugehit and it spawned an entire industry builtaround SQL. Sybase, Informix, Microsoft, andseveral other companies have since comeforward with their implementations of SQL-basedrelational database management systems(RDBMSs).

When Oracle and its competitors first hit thescene, SQL was still relatively new and nostandard existed. It was only in 1989 that theANSI standards body issued the first public SQLstandard. These days, that standard is oftenreferred to as SQL89. Unfortunately, thestandard did not go far enough into defining thetechnical structure of the language. Thus, eventhough the various commercial SQL languageswere drawing closer together, differences insyntax still made it nontrivial to switch amongimplementations. It was not until 1992 that theANSI SQL standard came into its own.

People refer to the 1992 standard as both SQL92

Page 432: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

and SQL2. The SQL2 standard expanded thelanguage to accommodate as many of theproprietary extensions added by the commercialvendors as possible. Many cross-DBMStools including JDBC have standardized on SQL2as their mode of communication with relationaldatabases. Due to the extensive nature of theSQL2 standard, however, relational databasesthat implement the full standard are verycomplex beasts.

SQL2 is not the last word on the SQLstandard. W ith the grow ing popularity ofobject-oriented database managementsystems (OODBMS) and object-relationaldatabase management systems (ORDBMS),there has been increasing pressure tocapture support for object-oriented conceptsin relational databases. The recent SQL3(SQL99) standard is the answer to thisproblem.

SQL2 defines several levels of compliance toaddress its complexity. The most importantlevel the one required by JDBC is SQL92, entrylevel. Entry level defines the core SQL syntax. Ifyour goal is to write portable applications, youshould go no further in the SQL specificationthan entry level.

10.1.2 Database Interaction

Page 433: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Any number of methods exists for sending SQLto a database engine and retrieving the resultsof your command. Throughout most of this book,you are using Java's JDBC API to handle thatinteraction. For the purposes of this chapter,however, you will need to use a tool thatinteractively sends SQL to your database. Eachdatabase engine comes with at least one suchtool. In general, there are both command-lineand GUI-interactive SQL tools. MySQL, forexample, provides the mysql commands lineutility. PostgreSQL similarly provides a similartool called psql. Before going any further in thischapter, I recommend you find out the tool thatcomes with your database so you can try theexamples that come later.

When you run a command-line program likemysql, it prompts you for SQL:

[09:04pm] carthage$ mysql -u root -p jtestEnter password: Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 3 to server version: 3.22.29Type 'help' for help.mysql>

The previous mysql command says to connect tothe MySQL server on the database jtest on thelocal machine as the user root (the -u option)with the client prompting you for a password(the -p option). Another option, -h, enables youto connect to MySQL servers on remotemachines:

Page 434: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[09:04pm] carthage$ mysql -u root -h db.imaginary.com -p jtest

Once mysql is running, you can enter your SQLcommands all on a single line or split themacross multiple lines. MySQL waits for asemicolon or the \g sequence before executingthe SQL:

mysql> SELECT book_number -> FROM book -> ;

+-------------+| book_number |+-------------+| 1 || 2 || 3 |+-------------+3 rows in set (0.00 sec)

GUI utilities generally provide you with a textbox into which you can enter SQL. Pressing Enteror clicking a button to send the SQL to thedatabase will execute the SQL for you. The toolthen displays the results in a graphical table. Insome cases, you can even manipulate the tableand the tool will create and send to thedatabase SQL that updates the underlyingdatabase.

10.1.3 Basic Syntax

As I mentioned earlier, SQL resembles a human

Page 435: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

As I mentioned earlier, SQL resembles a humanlanguage more than a computer languagebecause it has a simple, defined imperativestructure. Much like an English sentence,individual SQL commands called queries can bebroken down into language parts. Consider thefollowing examples:

CREATE TABLE Person ( name CHAR(10) );verb direct object adjective phrase INSERT INTO Person ( name ) VALUES ( 'me' );verb indirect object adjective phrase direct object SELECT name FROM people WHERE name like '%e';verb direct object indirect object adjective phrase

Most SQL implementations are case-insensitive.In other words, it does not matter how you typeSQL keywords as long as the spelling is correct.The previous CREATE example is just as validwhen written like this:

cREatE TAblE Person ( name ChAr(10) );

This case-insensitivity extends only to SQLkeywords.[2] In some database engines,identifiers are also case-insensitive. For others,they are case-sensitive. Still, the case-sensitivity of other database engines like MySQLdepends on the underlying operating system.Most MySQL identifiers are case-sensitive;however, table names and database names arecase-sensitive only on operating systems whosefilesystems are case-sensitive. It is thereforegood practice to assume that your identifiers are

Page 436: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

case-sensitive in order to guarantee portabilityof your SQL across all database engines.

[2] For the sake of readability, I capitalize all SQLkeywords in the book. I also recommend this conventionas a solid best-practice technique for all production code.

The first element of an SQL query is always averb. The verb expresses the action you wish thedatabase engine to take. The most commonlyused verbs are:

CREATE

Creates an object in the database

DELETE

Deletes data from a database table

INSERT

Inserts new data into a database table

SELECT

Retrieves data from the database

Page 437: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

UPDATE

Modifies data in a database table

Although what follows the verb varies dependingon the verb used, they all follow the samegeneral format: you name the object upon whichyou are acting and then describe the data youare using for the action. For example, the queryCREATE TABLE people ( name CHAR(10) ) uses theverb CREATE, followed by the object TABLE. Therest of the query describes the table to becreated.

An SQL query originates with a client application.The client constructs a query based on useractions and sends the query to the databaseengine. The database engine must then processthe query and perform the specified action. Oncethe server has done its job, it returns somevalue or set of values to the client.

Because the primary focus of SQL is tocommunicate actions to the database server, itdoes not have the flexibility of a general-purpose language. Most of the functionality ofSQL concerns input to and output from thedatabase: adding, changing, deleting, andreading data. SQL provides other functionality,but always with an eye toward how it can beused to manipulate data within the database.

In order to execute the SQL in this chapter,you w ill need the proper access rights.

Page 438: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Different actions naturally demand differentlevels of access. For example, you shouldhave no problem executing basic queries.Unless you have the DBA password, however,it is unlikely you w ill be able to createdatabase instances.

Page 439: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

10.2 Database Creation

The first thing you do with any database engineis to create a database instance to work with. Itis therefore quite ironic that no standardmechanism for creating database instances issupported. For the most part, you can create adatabase instance in most database enginesusing some variation of the CREATE DATABASEstatement. Its simplest form is common to alldatabase engines:

CREATE DATABASE name

In essence, this statement creates a brand new,blank database instance. It is all you need tocreate a MySQL or PostgreSQL database.PostgreSQL does offer the option of specifyingwhere you place the database files for theinstance:

CREATE DATABASE name WITH LOCATION = 'path'

The more complex database engines requiremore complex database creation statements.Oracle, for example, allows you to specifyoptions such as log file specifications, datafilespecifications, and character set information.

Page 440: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

When in doubt, you can get away with the basicsyntax listed earlier. However, you rarely willfind any default database creation valuessuitable to a production environment. In placeslike this, you will find the help of a good DBA(database administrator) with expertise in yourdatabase engine of choice invaluable.

Once you have a database to work with, you canwork with that database using the CONNECTstatement:

CONNECT [TO]DEFAULT | { [server] [AS name] [USER user] }

For example, to connect to the PostgreSQLdatabase instance library on the server carthage,you would execute the following SQL:

CONNECT TO library@carthage AS libconn USER webuser

In MySQL, this statement is slightly different:

CONNECT dbname [server [AS user]]

Oracle also provides an alternate syntax:

CONNECT [ [user/password] [AS [SYSOPER | SYSDBA] ] ]

You are now set to begin using your new

Page 441: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database instance. In the examples in thischapter, I will be using a database called jtest.

Once you are done with a database and nolonger have use for the data it contains, you canget rid of the instance from your server using theDROP DATABASE command:

DROP DATABASE dname

Dropping databases or anything else for thatmatter from a database is a very destructiveoperation. The only way to recover from anaccidental DROP command is to restore from abackup!

Oracle, however, does not support the DROPDATABASE command. To get rid of a database inOracle, issue the CREATE DATABASE commandwith no parameters using the name of theexisting database that should be dropped.

Page 442: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

10.3 Table Management

Now that you have a clean, new databaseinstance and have connected to it, it is time tocreate the structures that will hold your data.The most basic of these structures is the table.Before adding data to a table, you must firstcreate it in the database.

10.3.1 The Basics of Table Creation

The act of creating a table defines the data thetable holds and any constraints placed on thatdata. The basic elements of the table structureare the names of its columns, their data types,and their constraints. SQL data types are similarto data types in other languages. The full SQLstandard allows for a large range of data types.The general form for creating a table is:

CREATE TABLE tblname ( colname type [modifiers] [, colname type [modifiers]])

A table may have any number of columns, buttoo many columns can render the tableinefficient. Good database design can help youavoid unwieldy table structures. By creatingproperly normalized[3] tables, you can join tablestogether and perform searches for data acrossmultiple tables. We discuss the mechanics of ajoin later in the chapter.

Page 443: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[3] See Chapter 2 for a full discussion of database designand normalization.

Consider, for example, the table structure of theUser table in Table 10-1.

Table 10-1. The structure for a User table

Column name Data type Constraints

userID INT UNSIGNED NOT NULL PRIMARY KEY

name CHAR(10) NOT NULL UNIQUE INDEX

lastName VARCHAR(30)

firstName VARCHAR(30)

office CHAR(2) NOT NULL

You can create the table shown in Table 10-1using the following SQL:

CREATE TABLE User ( userID INT UNSIGNED NOT NULL, name CHAR(10) NOT NULL, lastName VARCHAR(30), firstName VARCHAR(30), office CHAR(2) NOT NULL DEFAULT `NY')

This statement creates a table called User withfive columns: userID, name, lastName, firstName,and office. After each column comes the datatype for the column and some modifiers. In this

Page 444: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

example, we describe only the NOT NULLconstraints as part of the CREATE statement. Wewill define the indexes later.

The NOT NULL modifier indicates that the columnmay not contain any NULL values. If you attemptto assign a NULL value to that column, thedatabase will issue an error. A couple ofexceptions exist for this rule. First, if the columnis some kind of sequence column,[4] thedatabase will automatically generate a uniquevalue for the column. The second exception iswhen you specify a default value for a column aswe did for the office column. When you insert aNULL value into a NOT NULL column with adefault value, the default value is inserted inplace of the NULL.

[4] Sequence columns are columns for which the databaseautomatically generates values. The mechanics ofsequence columns vary from database to database w ithvery little in common between any two.

To get rid of your newly created table (with theexception of Oracle users), use the DROPstatement:

DROP TABLE User

10.3.2 Data Types

In a table, each column has a data type. As Imentioned earlier, SQL data types are similar todata types in other languages. While manylanguages define a bare minimum set of types

Page 445: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

necessary for completeness, SQL goes out of itsway to provide types such as DATE that will beuseful to everyday users. You could store a datevalue in a column with a more basic numerictype, but having a type specifically dedicated tothe nuances of date processing adds to SQL'sease of use one of SQL's primary goals.

In dealing with data types, you really need toknow your database engine of choice. Alldatabases share a small subset of data typesand then extend beyond that core set.Furthermore, two databases may have datatypes of the same name that behave differently.Whatever the database you are using, however,some basic best practices can assist you in yourdatabase programming.

Before you create a table, you should know whatkind of data you intend to store in the table'scolumns. Beyond obvious decisions aboutwhether your data is character-based or numeric,you should also know the approximate size ofthe data you wish to store. If it is a numericfield, what is the maximum possible value thatcould make sense? What is the minimumpossible value? Could that range change in thefuture? Answering these questions will enableyou to choose a data type sufficient for storingyour data without wasting disk space or RAM.

You should always strive for the smallestpossible type capable of storing your valuerange. If, for example, you have a field thatrepresents the population of a state, use anunsigned numeric type if your database supports

Page 446: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

unsigned types. As long as no state has anegative population, your database will operatewell. Furthermore, a 32-bit numeric type will besufficient for a state's population. It would takea state population roughly the size of the currentpopulation of Earth to get you in trouble withthis choice of data type.

10.3.2.1 Numeric types

Numeric data types store uninterpreted numbervalues. Such values can range from simpleintegers to complex, high-precision decimals.Your choice of numeric data type depends onwhat you expect the largest possible value tobe, what you expect the smallest value to be,and how precise you expect that value to be.Table 10-2 shows the major numeric types forMySQL and Oracle.

Table 10-2. Numeric types in MySQL andOracle

Database Type Description

MySQL TINYINT Whole 7-bit numbers in the range -128to 127.

SMALLINT Whole 8-bit numbers in the range -32758 to 32,757.

MEDIUMINT Whole 16-bit numbers in the range -8,388,608 to 8,388,607.

Page 447: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

INT Whole 32-bit numbers in the range -2,147,483,548 to 2,147,483,547.

BIGINTWhole 64-bit numbers in the range -9,223,372,036,854,775,808 to9,223,372,036,854,775,807.

DECIMAL(p,s) Decimal values w ith s as the scale and pas the precision.

DOUBLE(p,s) Double-precision values w ith s as thescale and p as the precision.

FLOAT(p) Floating point numbers w ith a precisionof 8 or less.

Oracle INTEGER(n) Whole numbers capable of storing up ton digits.

NUMBER(p,s)

Any number where p specifies theprecision and s the scale. The precisionmay be between 1 and 38 and the scalebetween -84 and 127.

FLOAT(p) Floating point numbers w ith a precisionup to 126.

10.3.2.2 Character types

Managing character types is much morecomplicated that managing numeric types. Notonly do you have to worry about minimum andmaximum lengths, but you have to worry aboutthe average size, variation, and character set ofthe strings. Indexing, which I will cover in the

Page 448: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

next section, also complicates the choice ofcharacter type. It generally works best when youchoose a fixed-length data type for indexedcharacter columns. If your column has little or novariation in the length of its strings, the fixed-length CHAR data type is probably your best bet.An example of a solid candidate for the CHARdata type is a column holding a country code.The International Standards Organization (ISO)provides a comprehensive list of standard two-character codes for countries (e.g., US for theUnited States, FR for France, etc.). Because thecodes are always two characters, a CHAR(2) isthe best way to maintain a column holdingcountry codes.

A value does not have to have a constant lengthto be held in a CHAR column. It should, however,have very little variance. Phone numbers, forexample, will fit in a CHAR(13) column eventhough phone number lengths vary from nationto nation. The variance is small enough thatthere is no point in making the string variablelength. The problem with a CHAR field, however,is that it always takes up the exact sameamount of storage no matter what you store init. In a CHAR(20) column, the strings "A" and"ABCDEFGHIJKLMNO" all occupy the sameamount of storage space. Anything under 20characters is padded with spaces. Though theminimal potential waste for phone numbervalues is an acceptable trade-off for theefficiency of fixed-length searches, it is notacceptable for strings with greater variance.

Variable-length fields address the needs of

Page 449: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

strings that have a significant variance betweentheir minimum and maximum lengths. A good,common example of such a value is a web URL.A URL can be as simple ashttp://www.imaginary.com or as long ashttp://code.law.harvard.edu/filtering/test.asp?URL=http%3A%2F%2Fwww.slashdot.org. If youcreate a column with a fixed-width field largeenough to hold the latter URL, you will waste alot of space with the majority of values that lookmore like the former.

Most character types require you to specify amaximum length for the string. In mostdatabases, the database truncates any stringsthat exceed the maximum length. If, forexample, you insert the string "happy birthday"into a CHAR(4) field, the database will store only"happ".

Table 10-3 contains the most common charactertypes for MySQL and Oracle.

Table 10-3. Character types for MySQL andOracle

Database Type Description

MySQL CHAR(n)Fixed-length character type that holdsexactly n characters. Shorter strings arepadded w ith spaces to n characters.

NCHAR(n) Same as CHAR, except for Unicodestrings.

VARCHAR(n)Variable-length strings that may storeup to n characters. Any excess

Page 450: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

characters are discarded.

NVARCHAR(n) Same as VARCHAR, except for Unicodestrings.

Oracle CHAR(n)Fixed-length character type that holdsexactly n characters. Shorter strings arepadded w ith spaces to n characters.

NCHAR(n) Same as CHAR, except for Unicodestrings.

VARCHAR2 Variable-length strings up to 4000characters in length.

NVARCHAR2 Same as VARCHAR2, except for Unicodestrings.

10.3.2.3 Other types

SQL supports many other types, from dates andtimes to binary data and more. The most recentANSI SQL, SQL99, adds support for user-defineddata types in the mold of object-orientedprogramming languages. You should check thedocumentation for your database of choice tounderstand the full range of data types availableto you.

10.3.3 Indexing

Indexes assist the database in identifyingspecific rows in a table. W ithout an index, a

Page 451: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

search for a specific row in a table containing amillion rows would require the engine to walkthrough every single row. An index provides thedatabase with hints about the location of therow and how many possible matches might existfor your search criteria.

The cost of an index is storage space. The mostefficient use of indexes is therefore to createindexes for the columns you intend to search on.You can create an index using the followingbasic syntax:

CREATE [UNIQUE] INDEX idxname ON tblname ( colname [, colname] )

As with just about any other SQL statement,each database carries its own variations on thissyntax. Nevertheless, you can create the uniqueindex for the name column in the User tablereferenced earlier in any database engine usingthe following syntax:

CREATE UNIQUE INDEX userName ON User ( name )

Some databases also let you create an indexwhile creating the table:

CREATE TABLE User ( userID INT UNSIGNED NOT NULL, name CHAR(10) NOT NULL, lastName VARCHAR(30), firstName VARCHAR(30), office CHAR(2) NOT NULL DEFAULT 'NY', UNIQUE INDEX ( name )

)

Page 452: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

When the database now searches for a rowhaving a specific name value, it knows how tonarrow its search to a subset of the table.Furthermore, because the index is unique, itknows to stop the search when it finds thematching value.

ANSI SQL also supports a special kind of indexcalled a primary key. A relational table can haveat most a single primary key. The primary key isa unique index that signifies the preferredmechanism for uniquely identifying a row in thattable. In all technical respects, the primary keyis indistinguishable from a unique index. You areallowed to specify single-column primary keys onthe same line as the column definition in a tableCREATE statement:

CREATE TABLE cities (id INT NOT NULL PRIMARY KEY, name VARCHAR(100), pop INT, founded DATE)

Before you create a table, determine whichfields, if any, should be keys. As I mentionedearlier, any fields that support joins are goodcandidates for primary keys.

You will commonly want to specify multicolumnindexes and primary keys. For example, atranslation table for book titles requires thebook ID and language to uniquely identify a titletranslation:

CREATE TABLE BookTitleTrans ( bookID INTEGER(9) NOT NULL,

Page 453: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

language CHAR(2) NOT NULL, title VARCHAR2(255) NOT NULL, PRIMARY KEY ( bookID, language ));

Page 454: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

10.4 Data Management

The first thing you will probably want to do witha newly created table is add data to it. Once thedata is in place, you need to maintain it add toit, modify it, and perhaps even delete it.

10.4.1 Inserts

Creating a row in a table is one of the morestraightforward concepts in SQL. The standardform of the INSERT statement is:

INSERT [INTO] table_or_view_name (column1, column2, ..., columnN){ [DEFAULT] VALUES | VALUES (value1, value2, ..., valueN)| select_statement }

You specify the columns followed by the valuesto populate those columns for the new row.When inserting data into numeric fields, you caninsert the value as is; for all other fields, youmust wrap them in single quotes. For example,to insert a row of data into a table of addresses,you might issue the following command:

INSERT INTO Address (name, address, city, state, phone, age)VALUES('Robert Smith', '123 Fascination St.', 'New London', 'CT', '(800) 555-1234', 43)

In addition to the direct specification of thevalues to add, you can populate the table with anew row containing default values or even fromthe results of some other query. For example, toinsert the results from a query as new rows in atable, you might execute the following SQL:

INSERT INTO FavoriteSong ( id, name, album, artist )

Page 455: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SELECT Song.id, Song.name, Album.title, Artist.nameFROM Song, Album, ArtistWHERE Song.ranking > 4AND Song.album = Album.idAND Album.artist = Artist.id

You should note that the number of columns inthe INSERT call matches the number of columnsin the SELECT call. In addition, the data types forthe INSERT columns must match the data typesfor the corresponding SELECT columns. Finally,the SELECT clause in an INSERT statement cannotcontain an ORDER BY modifier and cannot beselected from the same table in which theINSERT occurs.

10.4.2 Primary Keys

The best kind of primary key is one that hasabsolutely no meaning in the database except toact as a primary key. When you use informationsuch as a username or an email address as aprimary key, you are in effect saying that theusername or email address is somehow anintrinsic part of who that person is. If thatperson ever changes the username or emailaddress, you will have to go to great lengths toensure the integrity of the data in the database.Consequently, it is a better design principle touse meaningless numbers as primary keys.

You thus need a mechanism for generatingmeaningless, yet unique, numbers every timeyou insert a new row. Every database providessome kind of extremely proprietary tool forgenerating unique identifiers. They differ sovastly that I cannot even begin to provide ageneric description of unique identifier

Page 456: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

generation as I can with most SQL elements.Because of how greatly they differ, it is a goodidea to simply avoid the proprietary databasetools. Chapter 4 provides a database-independent approach to sequence generation.

10.4.3 Updates

The insertion of new rows into a database is justthe start of data management. Unless yourdatabase is read-only, you will probably alsoneed to make periodic changes to the data. Thestandard SQL modification statement looks likethis:

UPDATE table_or_view_nameSET column1={DEFAULT |value} [, ... ][WHERE clause]

You specifically name the table you want toupdate and the values you want to assign in theSET clause and then identify the rows to beaffected in the WHERE clause. If you fail tospecify a WHERE clause, the database will updateevery row in the table.

In addition to assigning literal values to acolumn, you can also calculate the values. Youcan even calculate the value based on a value inanother column:

UPDATE ProjectSET end_year = begin_year+5

This command sets the value in the end_yearcolumn equal to the value in the begin_yearcolumn, plus 5, for each row in that table.

Page 457: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

10.4.4 The WHERE Clause

The previous section introduced one of the mostimportant SQL concepts, the WHERE clause. InSQL, a WHERE clause enables you to pick outspecific rows in a table by specifying a value(like a primary key) that must be matched by thecolumn in question. For example:

UPDATE BandSET leadSinger = 'Ian Anderson'WHERE id = 8

This UPDATE specifies that you should changeonly the leadSinger column for the row where id is8. If the specified column is not a unique index,the WHERE clause may match multiple rows.Many SQL commands employ WHERE clauses tohelp pick out the rows on which you wish tooperate. Because the columns in the WHEREclause are columns on which you search, youshould generally have indexes created aroundwhatever combinations you commonly use. Wediscuss the kinds of comparisons you canperform in the WHERE clause later in the chapter.

10.4.5 Deletes

Deleting data is a straightforward operation. Yousimply specify the table followed by a WHEREclause that identifies the rows you want todelete:

DELETE FROM table_name [WHERE clause]

As with other commands that accept a WHEREclause, the WHERE clause is optional. If you omitit, you will delete all of the records in the table!

Page 458: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Of all the destructive commands in SQL, this isthe easiest one to issue by mistake.

10.4.6 Queries

The last common SQL command, SELECT, enablesyou to view the data in the database. Thisaction is by far the most common actionperformed in SQL. While data entry andmodifications do happen on occasion, mostdatabases spend the vast majority of their livesserving up data for reading. The general form ofthe SELECT statement is as follows:

SELECT [ALL | DISTINCT] column1 [, column2, ..., columnN ]FROM table1 [, table2, ..., tableN ][JOIN condition][WHERE clause][GROUP BY column_list][HAVING condition][ORDER BY column_list [ASC | DESC]]

The SELECT statement enables you to identifythe columns you want from one or more tables.The WHERE clause identifies the rows with thedata you seek.

10.4.6.1 Basic queries

The variations on this syntax are numerous. Thesimplest form is:

SELECT 1;

This simple, though completely useless queryreturns a result set with a single row containinga single column with the value of 1. A more

Page 459: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

useful version of this query might be the MySQLquery that tells you what database you areusing:

mysql> SELECT DATABASE( );+------------+| DATABASE( ) |+------------+| jtest |+------------+1 row in set (0.01 sec)

The expression DATABASE( ) is a MySQL functionthat returns the name of the current database. Iwill cover functions in more detail later in thechapter. Nevertheless, you can see how simpleSQL can provide a quick-and-dirty way of findingout important information.

Most of the time, however, you should useslightly more complex queries that help you pulldata from a table in the database. The first partof a SELECT statement enumerates the columnsyou wish to retrieve. You may specify a * to saythat you want to select all columns. The FROMclause specifies which tables those columnscome from.

The other optional clauses all determine whatrows you are selecting and how to display theresults. By now, you should feel comfortablewith the WHERE clause. In the case of a SELECTstatement, the WHERE clause tells the databaseto return only the rows that match the specifiedclause. I will cover the more complex clauseslater in this chapter.

10.4.6.2 Aliasing

Page 460: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

When you use column names that are fullyqualified with their table and column names, thenames can grow to be quite unwieldy. Inaddition, when referencing SQL functions (whichwill be discussed later in the chapter), you willlikely find it cumbersome to refer to the samefunction more than once within a statement. Youcan get around these issues by using aliases. Analias is usually a shorter and more descriptiveway of referring to a cumbersome name. You canuse it anywhere in the same SQL statement inplace of the longer name. For example:

# A column aliasSELECT long_field_names_are_annoying AS myfieldFROM table_nameWHERE myfield = 'Joe' # A table aliasSELECT people.names, tests.score FROM tests, really_long_people_table_name AS people

10.4.6.3 Ordering

The results from a SELECT are, by default,indeterminate in the order they will appear. Youcan tell a database to order any results you seeby a certain column. For example, if you specifythat a query should order the results bylast_name, then the results will appearalphabetized according to the last_name value.Ordering is handled by the ORDER BY clause:

SELECT last_name, first_name, ageFROM peopleORDER BY last_name, first_name

Page 461: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

In this situation, we are ordering by twocolumns. You can order by any number ofcolumns.

If you want to see things in reverse order, addthe DESC (descending) keyword:

ORDER BY last_name DESC

The DESC keyword applies only to the field thatcomes directly before it. If you are sorting onmultiple fields, only the field directly before DESCis reversed; the others are sorted in ascendingorder.

10.4.6.4 Grouping

Grouping lets you group rows with matchingvalues for a specific column into a single row inorder to operate on them together. You usuallydo this to perform aggregate functions on theresults. I will go into functions a little later inthe chapter.

Consider the following:

mysql> SELECT name, rank, salary FROM people;+--------------+----------+--------+| name | rank | salary |+--------------+----------+--------+| Jack Smith | Private | 23000 || Jane Walker | General | 125000 || June Sanders | Private | 22000 || John Barker | Sergeant | 45000 || Jim Castle | Sergeant | 38000 |+--------------+----------+--------+5 rows in set (0.01 sec)

Page 462: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

If you want to get a list of different ranks, youcan use the GROUP BY clause to get a fullaccount of the ranks:

mysql> SELECT rank FROM people GROUP BY rank;+----------+| rank |+----------+| General || Private || Sergeant |+----------+3 rows in set (0.01 sec)

You should not, however, think of these resultsas simply a listing of the different ranks. TheGROUP BY clause actually groups all of the rowsmatching the WHERE clause (in this case, everyrow) based on the GROUP BY clause. The twoprivates are thus grouped together into a singlerow with the rank Private. The two sergeants aresimilarly aggregated. W ith the individualsgrouped according to rank, you can find out theaverage salary for each rank. Again, we willfurther discuss the functions you see in thisexample later in the chapter.

mysql> SELECT rank, AVG(salary) FROM people GROUP BY rank;+----------+-------------+| rank | AVG(salary) |+----------+-------------+| General | 125000.0000 || Private | 22500.0000 || Sergeant | 41500.0000 |+----------+-------------+3 rows in set (0.04 sec)

Here you see the true power of grouping. Thisquery uses an aggregate function, AVG( ) tooperate on all of the rows grouped together for

Page 463: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

each row. In this case, the salaries of the twoprivates (23000 and 22000) are grouped togetherin the same row, and the AVG( ) function isapplied to them.

The power of ordering and grouping combinedwith the utility of SQL functions enables you todo a great deal of data manipulation even beforeyou retrieve the data from the server. However,you should take great care not to rely tooheavily on this power. While it may seem moreefficient to place as much processing load aspossible onto the database server, this is notreally the case. Your client application isdedicated to the needs of a particular client,while the server is shared by many clients.Because of the greater amount of work a serveralready has to do, it is almost always moreefficient to place as little load as possible on thedatabase server.

10.4.7 Operators

So far, we have used the = operator for theobvious task of verifying that two values in aWHERE clause equal each other. Other fairly basicoperators include <>, >, <, <=, and >=. Notethat though ANSI SQL requires the use of <> tocheck for inequality, most database engines alsosupport !=. Table 10-4 contains a full set of ANSISQL operators.

Not all databases support all operators. Inaddition, MySQL and SQL Server supportvarious bitw ise operators, including &, |, ^,<<, and >>.

Page 464: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Table 10-4. ANSI SQL Operators

Operator Context Description

+ Arithmetic Addition (also works for date addition onsome database engines)

- Arithmetic Subtraction

* Arithmetic Multiplication

/ Arithmetic Division

= Comparison Equal

<> Comparison Not equal

< Comparison Less than

> Comparison Greater than

<= Comparison Less than or equal to

>= Comparison Greater than or equal to

BETWEEN Comparison Between two values

IN Comparison Membership in a list

LIKE Comparison Similarity

AND Logical And

OR Logical Or

Page 465: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

NOT Logical Negation

+ Unary Positive

- Unary Negative

~ Unary Complement

ANSI SQL operators have the following order ofprecedence:

1. + - ~ (unary)

NOT

* / %

+ - (arithmetic)

< <= > >= = <> IN LIKE

BETWEEN IN

AND

OR

Precedence moves from left to right for operatorsof equal precedence. You can override the rulesof precedence through the use of parentheses, inwhich case elements within the parentheseshave higher precedence. For expressions withnested parentheses, the innermost parenthesesare evaluated first.

10.4.7.1 Logical operators

Page 466: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SQL's logical operators AND, OR, and NOTlet youbuild more dynamic WHERE clauses. The AND andOR operators specifically let you add multiplecriteria to a query:

SELECT nameFROM UserWHERE age > 18 AND status = 'RESIDENT';

This sample query provides a list of all userswho are residents and are old enough to vote. Inother words, it finds every resident 18 years orolder.

You can build increasingly complex queries andoverride SQL's order of precedence withparentheses. The parentheses tell the databasewhich comparisons to evaluate first:

SELECT name FROM UserWHERE (age > 18 AND status = 'RESIDENT')OR (age > 18 AND status = 'APPLICANT');

In this more complex query, we are looking foranyone currently eligible to vote as well aspeople who might be eligible in the near future.You can also use the NOT operator to negate anentire expression:

SELECT nameFROM UserWHERE NOT (age > 18 AND status = 'RESIDENT');

In this case, negation provides all the users whoare not eligible to vote.

10.4.7.2 Comparisons with NULL

Page 467: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

NULL is a tricky concept for most people new todatabases to understand. As in otherprogramming languages, NULL is not a value, butthe absence of a value. This concept is useful,for example, if you have a customer-profilingdatabase that gradually gathers informationabout your customers as they offer it.

When you first create a record, for example, youmay not know how many pets the customer has.You want that column to hold NULL instead of 0so you can tell the difference between customerswith no pets and customers whose petownership is unknown.

The concept of NULL gets a little funny when youuse it in SQL calculations. Many programminglanguages use NULL as simply another kind ofvalue. In Java, the following syntax evaluates totrue when the variable is NULL and false when it isnot:

str = = NULL

The similar expression in SQL, col = NULL, isneither true nor false it is always NULL, no matterwhat the value of the COL column. The followingquery will therefore not act as you might expect:

SELECT title FROM Book WHERE author = NULL;

Because the WHERE clause will never evaluate totrue no matter what value is in the database forthe author column, this query always provides anempty result set even when you have authorcolumns with NULL values. To test for "nullness,"use the IS NULL and IS NOT NULL operators:

Page 468: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SELECT title FROM Book WHERE author IS NULL;

10.4.7.3 Membership tests

Sometimes applications need to check whether avalue is a member of a set of values or within aparticular range. The IN operator helps with theformer:

SELECT title FROM Book WHERE author IN ('Stephen King', 'Richard Bachman');

This query will return the titles of all bookswritten by Stephen King.[5] Similarly, you cancheck for all books by authors other thanStephen King with the NOT IN operator.

[5] Richard Bachman is a pseudonym used by StephenKing for some of his books.

To determine whether a value is in a particularrange, use the BETWEEN operator:

SELECT title FROM Book WHERE bookID BETWEEN 1 AND 100;

Both of these simple examples could, of course,be replicated with the basic operators. TheStephen King check, for example, could havebeen done by using the = operator and an OR:

SELECT title FROM BookWHERE author = 'Stephen King' OR author = 'Richard Bachman';

The check on book IDs could also have beendone with an OR clause using the >= and <= or> and < operators. As your queries get morecomplex, however, membership tests can helpyou build both readable and better-performing

Page 469: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

queries than those you might create with thebasic operators.

10.4.8 Functions

Functions in SQL are similar to functions in otherprogramming languages such as C and Perl. Afunction takes zero or more arguments andreturns some value. For example, the functionSQRT(16) returns 4. W ithin an SQL SELECTstatement, functions may be used in one of twoways:

As a value to be retrieved

This form involves a function in the place ofa column in the list of columns to beretrieved. The return value of the function,evaluated for each selected row, is part ofthe returned result set as if it were acolumn in the database.[6]

[6] You can use aliasing, covered earlier in thechapter, to give the resulting columns "friendly"names.

This query selects the name of each eventand today's date for all events more recentthan the given time:

SELECT name, CURRENT_DATE( ) FROM EventWHERE time > 90534323

This query selects the title of a paper, thefull text of the paper, and the length of thetext in bytes for all of the papers authoredby Douglas Adams. The LENGTH( ) function

Page 470: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

by Douglas Adams. The LENGTH( ) functionreturns the character length of a givenstring:

# The LENGTH( ) function returns the character length of# a given string.SELECT title, text, LENGTH(text)FROM PaperWHERE author = 'Douglas Adams'

As part of a WHERE clause

This form involves a function used in placeof a constant when evaluating a WHEREclause. The value of the function is used forcomparison for each row of the table.

This query randomly selects the name of anentry from a pool of 35 entries. The RAND()function generates a random numberbetween 0 and 1. This random value is thenmultiplied by 34 to turn the value into anumber between 0 and 34. Incrementing thevalue by 1 provides a number between 1and 35. The ROUND( ) function rounds theresult to the nearest integer. The result is awhole number between 1 and 35 and willtherefore match one of the ID numbers inthe table:

SELECT name FROM EntryWHERE id = ROUND( (RAND( )*34) + 1 )

You may use functions in both the value listand the WHERE clause. This query selectsthe name and date of each event less thana day old:

Page 471: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SELECT nameFROM EventWHERE time > (CURRENT_TIMESTAMP( ) - (60 * 60 * 24) )

You may also use the value of a table fieldwithin a function. This example returns thenames of people who used their names aspasswords. The ENCRYPT( ) function fromMySQL returns a Unix password-styleencryption of the specified string using thesupplied two-character salt. The LEFT( )function returns the left-most n charactersof the specified string:

SELECT nameFROM PeopleWHERE password = ENCRYPT(name, LEFT(name, 2))

Though there is a basic set of ANSI SQLfunctions, the number of non-ANSI functions inany database engine likely outnumbers theirANSI counterparts. When programming in SQL, itis therefore always a good idea to have areference specific to your database at your side.

10.4.9 Joins

Joins put the "relational" in relational databasesby enabling you to relate the data in one tablewith data in other tables. The basic form of ajoin is sometimes described as an inner join.Joining tables is a matter of specifying equalityin columns from two tables:

SELECT Book.title, Author.name FROM Author, BookWHERE Book.author = Author.id

This query pulls columns from two different

Page 472: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

tables when a relationship exists between rowsin the two tables. Specifically, this query looksfor situations in which the value of the Authorcolumn in the Book table matches the id value inthe Author table. Consider a database in whichthe Book table looks like Table 10-5, and theAuthor table looks like Table 10-6.

Table 10-5. A Book table

ID Title Author

1 Slaughterhouse 5 4

2 Last Rites 2

3 The Vampire Lestat 3

4 The Shining 1

Table 10-6. An Author table

ID Name

1 Stephen King

2 Terry Pratchett

3 Anne Rice

4 Kurt Vonnegut

5 Douglas Adams

An inner join creates a virtual table by combiningthe fields of both tables for rows that satisfy thequery in both tables. In our example, the query

Page 473: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

specifies that the author field of the Book tablemust be identical to the id field of the Authortable. The query's result would look like Table10-7.

Table 10-7. Query results based on an innerjoin

Book title Author name

The Shining Stephen King

Last Rites Terry Pratchet

Slaughterhouse 5 Kurt Vonnegut

The Vampire Lestat Anne Rice

Douglas Adams is nowhere to be found in theseresults. He is left out because there is no valuefor his Author.id value found in the author columnof the Book table. In other words, he did notwrite any of the books in our database! An innerjoin contains only those rows that match thequery exactly.

Just about every database supports inner joinsvia the WHERE clause. Nevertheless, thisapproach violates the ANSI standard. ANSI-compliant joins inner and otherwise occur in theJOIN clause of your SELECT statement. The bookquery is properly written in ANSI SQL as:

SELECT Book.title, Author.nameFROM AuthorJOIN Book ON Author.id = Book.author

What you get in your result set involving a joindepends on the join type. You have already seen

Page 474: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

depends on the join type. You have already seenhow an inner join fails to show Douglas Adamssince he has no books listed in the Book table.ANSI SQL supports the following kinds of joins:

Inner join

An inner join is the default kind of join.Under an inner join, any rows that do notmatch from either table are discarded fromthe result set.

Left join

A left join enables us to see that we haveDouglas Adams in the database with nobooks. In short, all rows from the left sideof the join are included in the resultsregardless of whether they match a rowfrom the right side of the join. Where nomatch exists, NULL values are shown forfields from the table on the right side of thejoin.

Right join

Right and left joins are variations of asingle kind of join known as an outer join.As a left join provides all the rows from theleft side of the join, a right join provides allthe rows from the right side.

Because these two joins are only semanticallydifferent, MySQL has chosen not to supportright joins. If you need a right join, you can

Page 475: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

simply restate your SQL as a left join in orderto achieve the same results.

Full join

A full join is a combination of a right andleft join. In other words, all rows from bothtables appear in the result set. If no matchexists for each side, NULL values appear inthe result set.

Natural join

A natural join looks for columns in thejoined tables having identical names, datatypes, and values. For example, the innerjoin we performed on the Book and Authortables could be made a natural join if theauthor column in the Book table wererenamed authorID and the id column in theAuthor table renamed authorID:

SELECT Book.title, Author.nameFROM AuthorNATURAL JOIN Book;

Cross join

A cross join provides the full data from thejoined two tables and is the same asspecifying no JOIN or WHERE clause at all. Icannot think of any reason why you would

Page 476: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

want to perform a cross join.

The left outer join that gives us Douglas Adamsin our results looks like:

SELECT Book.title, Author.name FROM AuthorLEFT JOIN Book ON Book.author = Author.id

The results of the outer join would therefore looklike this:

+--------------------+----------------+| Book.title | Author.name |+--------------------+----------------+| The Shining | Stephen King || Last Rites | Terry Pratchett|| The Vampire Lestat | Anne Rice || Slaughterhouse 5 | Kurt Vonnegut || NULL | Douglas Adams |+--------------------+----------------+

Page 477: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 478: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 11. JDBCThese common thoughts are expressed in ashared public language, consisting ofshared signs... a sign has a "sense" thatfixes the reference and is "grasped byeverybody" who knows the language...

Noam Chomsky, Language and Thought

JDBC is one of the oldest programming APIs inthe Java platform. In fact, it is the first of theenterprise APIs that eventually became the J2EEplatform. Its goal is to create a shared publiclanguage for Java access to any databaseengine.

SQL lies at the heart of the JDBC API. I thereforeassume a basic knowledge of SQL in thischapter. Chapter 10 contains a SQL tutorial ifyou need some background.

Page 479: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.1 Architecture

Working with leaders in the database field, Sundeveloped JDBC as a unified API for databaseaccess. As part of the JDBC design process, theykept in mind three main goals:

JDBC should be an SQL-level API.

JDBC should capitalize on the experience ofexisting database APIs.

JDBC should be relatively simple.

As an SQL-level API, JDBC enables you toconstruct SQL statements and embed theminside API calls. You are essentially using JDBCto make a smooth transition between the SQLand Java. Your application sends a query to thedatabase as SQL and gets the results backthrough a Java object. Any database error youencounter is thrown to your application as a Javaexception.

Database programming in most languages todayis very different from what it was just sevenyears ago. It used to be that each databaseengine had its own proprietary C API. If you wereprogramming against Sybase, you had to learnSybase's API. On the other hand, you had to

Page 480: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

learn a very different Oracle API if you needed totalk to Oracle. For programming in languagesother than C, you had to write a bridge to the CAPI.

JDBC leverages several attempts to provideunified database APIs, including ODBC andX/OPEN SQL. ODBC (Open DatabaseConnectivity) was initially created as a W indowsAPI for open database access. Although theindustry has accepted ODBC as a standard, itdoes not translate well into the Java world:

ODBC is primarily a W indows API and bestsuited for applications on the W indowsplatform.

ODBC has an overly complex design with asteep learning curve.

In addition to ODBC, the X/OPEN SQL Call LevelInterface (CLI) heavily influenced JDBC. Sunwanted to reuse the key abstractions from bothODBC and X/OPEN in order to ease acceptance ofthe API by database vendors and thus capitalizeon the existing knowledge capital in theincumbent APIs. In addition, Sun realized thatderiving an API from existing ones can providequick development of solutions for databaseengines supporting only the old protocols.Specifically, Sun worked in parallel with Intersolvto create an ODBC bridge that maps JDBC calls

Page 481: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

to ODBC calls. Consequently, every Java VM hasthe ability to talk to any ODBC-supporteddatabase using this bridge.

The JDBC-ODBC bridge is a great tool fordevelopers who are interested in learningJDBC but may not want to invest in anythingbeyond the Microsoft Access database thatcomes w ith Microsoft Office. When developingfor production sites, however, you almostcertainly want to move to a JDBC driver thatis native to your deployment databaseengine.

JDBC attempts to remain as simple as possiblewhile providing developers with maximumflexibility. A key criterion employed by Sun issimply asking whether database applicationsread well. The simple and common tasks usesimple interfaces, while more uncommon orbizarre tasks are enabled through specializedinterfaces. For example, a handful of methodcalls in three interfaces manage the vastmajority of database access. This list of keymethods and interfaces has changed very littlesince the first JDBC specification in March 1996.JDBC nevertheless provides many otherinterfaces for handling more complex andunusual tasks.

Page 482: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.1.1 The Core Interfaces

JDBC accomplishes its goals through a set ofJava interfaces, each implemented differently byindividual vendors. The set of classes thatimplements the JDBC interfaces for a particulardatabase engine combine into a tool called aJDBC driver. In building a database application,you do not have to think about theimplementation of these underlying classes atall; the whole point of JDBC is to hide thespecifics of each database and enable you tofocus on your application logic. Figure 11-1illustrates the JDBC architecture.

Figure 11-1. The JDBCarchitecture

If you think about a database query for any

Page 483: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database engine, it requires you to connect tothe database, issue your SELECT statement, andprocess any results. Example 11-1 is the JSPcode for a very simple SELECT call that pulls allrows from a table in a MySQL database. It gets aconnection from a data source configured in aJNDI directory service and then uses thatconnection to execute the query. The values ineach row then appear in the generated HTML.

Example 11-1. A simple JSP pagedisplaying the data in a table

<%@ page info="Table Results Page""%> <%@ page import="java.sql.*""%><%@ page import="java.naming.*""%><%@ pagge import="javax.sql.DataSource""%> <html> <head> <title>Table Results Page</title> </head> <body> <table> <tr> <th>ID</th> <th>Value</th> </tr> <%

Page 484: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

InitialContext ctx = new InitialContext( ); DataSource ds = ctx.lookup("jdbc/ora"); Connection conn = ds.getConnection( ); Statement stmt = conn.createStatement( ); ResultSet rs; rs = stmt.executeQuery("SELECT id, val FROM test"); while( rs.next( ) ) { %> <tr> <td><%=rs.getint(1)%></td> <td><%=rs.getString(2)%></td> </tr> <% } conn.close( ); %> </table> </body></html>

If you are an experienced JSP programmer, youshould be able to follow the flow of this JSPpage without knowing any JDBC. No referencesto any vendor-specific procedures exist in thesample code. Instead, this page uses only JDBCinterfaces to provide an abstraction of the DBMS-specific implementation. The JDBCimplementation, in turn, performs the actualdatabase access somewhere behind the scenes.Figure 11-2 is a UML class diagram of the basicJDBC classes and interfaces.

Page 485: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 11-2. The basic classes andinterfaces of the JDBC API

In the simple JSP page of Example 11-1, the JSPcode asks JNDI for a DataSource object stored inthe directory service under the name jdbc/ora.Someone should have configured your directoryservice to hold the information JDBC needs tomake a database connection. We will talk moreabout this configuration later in the chapter.

The JSP page then gets a Connection instancefrom the DataSource. This Connection is the JDBCrepresentation of a physical connection to your

Page 486: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database. You can use it to execute all the SQLyou like.

11.1.2 Databases and Drivers

Before you can get a connection from JNDI, youneed to have a database to connect to.Whatever database you have the mostimmediate access to will work. If you do nothave access to a database, I recommend usingan open source database like MySQL(www.mysql.com) or PostgreSQL(www.postgresql.org). Both are free and willenable you to learn JDBC and develop soliddatabase applications. PostgreSQL has theadvantage of supporting a fuller range of JDBCfeatures, whereas MySQL has the advantage ofbeing easier to install and set up.

Once your database engine is installed and yourdatabase is all set up, you will need a JDBCdriver to connect to that database engine.Whatever your database of choice, it should bevery simple to find a driver free of charge. Mostcommercial databases ship with a JDBC driver.Other database engines allow you to download adriver from their web site. In addition, you canopt for a commercially developed driver thatprobably performs better than the vendor-supported driver.

Page 487: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

JDBC drivers come in four distinct categories.Sun has named the categories types 1-4.

Type 1

A type 1 driver is a bridge between JDBCand another database-independent API likeODBC. The JDBC-ODBC driver that comeswith the Java SDK is the primary example ofa type 1 driver.

Type 2

A type 2 driver translates JDBC calls into anative API provided by the database vendor.

Type 3

Type 3 drivers are network bridges thatenable an application to take advantage ofthe WORA (Write Once, Run Anywhere)capabilities of type 4 drivers even whenyour database of choice supports only type2 drivers.

Type 4

Page 488: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

A type 4 driver talks directly to a databaseusing a network protocol. Because it makesno native calls, it can run on any JVM.

For a list of all currently known drivers, theirtypes, and the version of JDBC they support,visithttp://industry.java.sun.com/products/jdbc/drivers.

Page 489: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.2 Simple Database Access

At this point, you have the basics for connectingto a database. Example 11-1, however, did notreally do much. It showed you how to make adatabase connection and perform simplisticresult set management. You are unlikely to everhave such basic functionality in yourapplications. The basic database behaviorcommon to most applications, however, does notrequire significantly more complex code.

11.2.1 The Connection

JDBC represents a connection to a databasethrough the Connection interface. Thus,connecting to a database requires you to get aninstance of the Connection interface from yourJDBC driver. JDBC supports two ways of gettingaccess to a database connection:

Through the JDBC DataSource (as shown inExample 11-1)

Using the JDBC DriverManager

Page 490: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The data source method is the preferredapproach to database connectivity. Data sources,however, tend to be usable only in applicationserver contexts. You should therefore understandboth forms of connectivity since you can rely onDriverManager connectivity no matter whatenvironment you are working in.

Page 491: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 492: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Connection TroublesThe JDBC connection process is the most difficult part ofJDBC to get right. The API itself is very straightforward,but many "gotchas" hide right beneath the surface inthe configuration of your environment. If you used thedata source approach, you are less likely to run intoconfiguration problems. Unfortunately, this approach isonly commonly available to applications running inside aJ2EE application server. If you do run into problemsmaking a connection, check whether these problemsmatch the follow ing:

Connection fails with the message "Class not found"

This message usually results from not having the JDBCdriver in your CLASSPATH. You should remember to enter.zip and .jar files explicitly in your CLASSPATH. If you putall of your application .class files and your driver .jar file(for this example, driver.jar) in C:\lib, your CLASSPATHshould read C:\lib;C:\lib\driver.jar.

Connection fails with the message "Driver notfound"

You did not register your JDBC driver w ith theDriverManager class. This chapter describes several waysto register your JDBC driver.

11.2.1.1 DataSource connectivity

Data source connectivity is very simple. In fact,the following code makes a connection to anydatabase for any application:

Context ctx = new InitialContext( );DataSource ds = (DataSource)ctx.lookup("jdbc/dsn");Connection conn = ds.getConnection( );

The only requirement is that you have a JNDI-supported directory service containing aDataSource configured with the name jdbc/dsn.

Page 493: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The first line gets an InitialContext object inaccordance with the JNDI[1] specification. If yourenvironment isn't set up properly, you catch ajavax.naming.NoInitialContextException. TheInitialContext enables you to navigate a directoryservice. You use it in your database applicationsto look up a JDBC DataSource instance. Finally,once you have found that DataSource, you use itto make a connection.

[1] You should not be too concerned if you are not familiarw ith JNDI. For the purposes of basic JDBC connectivity,the preceding three lines of JNDI code are all you need toknow. The only thing that changes from application toapplication is the name of the data source.

Technically, DataSource connectivity does notrequire a directory service. Instead, you canserialize a configured DataSource instance out toa filesystem or load one in some other fashion.You will nevertheless find that the most commonsituation you will encounter is looking one up ina directory service via JNDI.

You may be wondering how the DataSource getsinto the directory service so you can look it up.JNDI does provide a process for binding objectsinto a directory service:

SomeDataSourceClass ds = new SomeDataSourceClass( );Context ctx = new InitialContext( ); // configure the data source through various setter methodsctx.bind("jdbc/dsn", ds);

I have two bits of magic in this code. First, theclass SomeDataSourceClass is an implementation ofjavax.sql.DataSourcegenerally written by yourdatabase or application server vendor. Next, theconfiguration of your data source the step I

Page 494: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

commented out is highly dependent on theDataSource implementation you are using. Insome cases, you may configure a user ID,password, database name, and server name. Youwill likely specify much more.

Fortunately, few programmers actually write codeto bind data sources to JNDI directory services.You will mostly encounter the need to configurea data source via XML or some other means. Asample data-sources.xml file from the Orionapplication server looks like this:

<?xml version="1.0"?><!DOCTYPE data-sources PUBLIC "Orion data-sources" "http://www.orionserver.com/dtds/data-sources.dtd"> <data-sources> <data-source class="com.evermind.sql.DriverManagerDataSource" name="dsn" location="jdbc/dsn" xa-location="jdbc/xa/HypersonicXADS" ejb-location="jdbc/HypersonicDS" connection-driver="org.gjt.mm.mysql.Driver" username="dvl" password="dvl" url="jdbc:mysql://localhost/dvl" inactivity-timeout="30"/></data-sources>

This configuration file places a DataSourceinstance in the application server's directoryservice that enables me to connect to a MySQLdatabase named "dvl" on the localhost using theuser ID "dvl" and password "dvl".

11.2.1.2 DriverManager

Page 495: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

connectivity

One of the few implementation classes in thejava.sql package is the class DriverManager. Itmaintains a list of implementations of thejava.sql.Driver interface and provides you withconnections based on a JDBC URL that youprovide. This JDBC URL comes in the formjdbc:protocol:subprotocol. This URL tells aDriverManager which database engine you wish toconnect to and provides the DriverManager withenough information to make a connection.

JDBC uses the word "driver" in multiplecontexts. When lowercase, a JDBC driver isthe collection of classes that togetherimplement the JDBC specification. Whenuppercase, the Driver is the class thatimplements java.sql.Driver. Finally, JDBCprovides a DriverManager that can be used tokeep track of all the different Driverimplementations.

The protocol part of the URL refers to a givenJDBC driver. The protocol for the GNU MySQLdriver, for example, is mysql. The subprotocolprovides the implementation-specific connectioninformation. Most drivers minimally require thename of a database to connect to. It is alsocommon to specify a host and even a portnumber in the subprotocol.

Each driver's JDBC URL is different, and so Icannot say anything more explicit that will tellyou what the proper URL is for your driver. Yourdriver documentation, however, should have

Page 496: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

easy-to-find documentation describing the exactform of its JDBC URL. Whatever the format ofthe URL, the primary function of the URL is touniquely identify the driver needed by theapplication and pass that driver any informationit needs to make a connection to the properdatabase.

Before you can use a URL to get a connectionfrom the DriverManager, you first need to registeryour Driver implementation with the DriverManager.You have two main options for registering aDriver:

Specify the names of the Driverimplementation classes you want to registeron the command line of your applicationusing the jdbc.drivers property:

java -Djdbc.drivers=com.caucho.jdbc.mysql.Driver MyAppClass

Explicitly load the class in your programusing a new statement or a Class.forName( ):

Class.forName("com.caucho.jdbc.mysql.Driver").newInstance( );

For portability's sake, I recommend that you putall configuration information in some sort ofconfiguration file, such as a properties file, thenload the configuration data at runtime. By takingthis approach, your application will not rely on aparticular database or JDBC driver. You cansimply change the values in the configuration fileto move from one driver to another or onedatabase to another.

Once you register a driver, you can ask theDriverManager for a Connection by calling thegetConnection( ) method in the driver with the

Page 497: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

information identifying the desired connection.This information minimally includes a JDBC URL,a user ID, and a password:

Connection conn = DriverManager.getConnection("jdbc:mysql:/localhost/Web", "userID", "password");

This code returns a connection to the MySQLdatabase named Web using the GNU MySQLdriver. This connection occurs under thepermissions of the user "userID" identified by thepassword "password".

An alternative signature to this method enablesyou to specify a Properties object that maycontain values beyond the basic user ID andpassword:

Properties p = new Properties( );Connection conn; p.put("user", "userID");p.put("password", "password");p.put("encoding"", "UTF-8");conn = DriverManager.getConnection("jdbc:mysql:/localhost/Web", p);

Example 11-2 provides a full example thatconnects to a MySQL database.

Example 11-2. Using theDriverManager to make aconnection

import java.sql.*;import java.util.Properties;

Page 498: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

public class Connect { static public void main(String[ ] args) { Connection conn = null; try { String url = "jdbc:mysql:/localhost/Web"; Properties p = new Properties( ); Class.forName("org.gjt.mm.mysql.Driver"). newInstance( ); p.put("user", "dvl"); p.put("password", "password"); conn = DriverManager.getConnection(url, p); } catch( SQLException e ) { e.printStackTrace( ); } finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } } }}

In this example, I have hardcoded the drivername and connection information in theapplication. The only reason this is acceptable isbecause it is an example showing all of theelements of making a connection. In practice,you will always want to follow the best practicesin the next section that avoid hardcoding thesevalues.

11.2.1.3 Portability throughproperties

Page 499: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Java is a language based on the concept ofportability. To most people, portability meansthat you do not write code that will run on onlyone platform. In the Java world, however,portability means no proprietarydependencies and that means no databasedependencies.

I touched earlier on how the JDBC URL and Driverimplementation classes are driver-specific.Because both values are simple strings, you canpass them as command-line arguments or appletparameters. Unfortunately, this approach ishardly elegant since it requires users toremember long command lines or to passauthentication credentials as HTML to an applettag.

You could, of course, prompt the user for thisinformation. However, this approach demandsthat the user know a JDBC URL and driver name.The elegant approach is the use of propertiesfiles. Java supports the concept of properties-based application configuration throughjava.util.ResourceBundle and its subclasses.

Using a properties file, you can store allconfiguration information like the JDBC URL,driver class, user ID, and password and change itas the runtime environment changes. Example11-3 is a sample properties file.

Example 11-3. A properties filecontaining driver configurationdata

Page 500: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

url=jdbc:mysql:/localhost/Webdriver=org.gjt.mm.mysql.Driveruser=dvlpassword=dvl

You can now turn Example 11-2 into a portableexample of making a connection as shown inExample 11-4.

Example 11-4. Using a propertiesfile to achieve portability

import java.sql.*;import java.util.* public class Connect { static public void main(String[ ] args) { Connection conn = null; try { ResourceBundle bdl = ResourceBundle.getBundle("connect");String url = bdl.getString("url");Properties p = new Propertes( );;Enumeration keys = bdl.keys( );while( keys.hasMoreElements( ) ) {String prop = (String)keys.nextElement( );String val = bdl.getString(prop);p.setProperty(prop, val);} Class.forName(bld.getString("driver")).newInstance( ); conn = DriverManager.getConnection(url, p); } catch( SQLException e ) { e.printStackTrace( ); } finally { if( conn != null ) {

Page 501: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

try { conn.close( ); } catch( SQLException e ) { } } } }}

We no longer have any code specific to MySQL orthe GNU driver. This code will now work againstany database engine using any JDBC driver,simply through changing the properties file.

11.2.2 Query Execution

The most basic element of communication over aConnection is the Statement. Your applicationencapsulates SQL queries into a Statement or oneof its subclasses and processes the results. AnSQL query can be an INSERT, UPDATE, DELETE, orany other valid SQL statement.

11.2.2.1 Simple queries

The Connection class enables you to createStatement instances via the createStatement( )method:

Statement stmt = conn.createStatement( );

You can then use that statement to send SQL tothe database:

stmt.executeUpdate("UPDATE test SET val = 'cheese' WHERE id = 1");

In this case, we are sending SQL that modifiesthe database. If the SQL returned results,

Page 502: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

however, we would use the executeQuery( )method and get back an instance of ResultSet:

ResultSet rs = stmt.executeQuery("SELECT id, val FROM test");

Example 11-5 shows a query returning resultsand the processing of those results.

Example 11-5. A query thatreturns results for processing

Connection conn = null; try { Statement stmt = conn.createStatement( ); ResultSet rs = stmt.executeQuery("SELECT id, val FROM test"); while( rs.next( ) ) { System.out.println("ID: " + rs.getInt(1) + ", rs.getString(2)); }}

The query in Example 11-5 retrieves every rowfrom the table test. The JDBC code loopsthrough those rows and displays the values foreach row's columns.

Page 503: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 504: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

SQL NULL Versus Java nullSQL and Java do not match up the way they treat theabsence of value null. Specifically, any SQL value can beNULL. In Java, however, only object types can have nullvalues. After retrieving a value from a ResultSet, yourJava application needs to ask the ResultSet if the valueretrieved is a driver representation of NULL. Forexample, a call to rs.getInt( ) might return 0 even thoughthe underlying database value for the column is NULL. Tofind out if the value is actually 0 or NULL, you should callrs.wasNull( ).

Until the first call to next( ), the result set doesnot point to any row returned by the query. Thefirst call makes the result set point to the firstrow. Until the next call to next( ), any operationsyou perform on the result set act on that row.Subsequent calls to next( ) move the result setforward through the rows in the result set. Inthis example, I move through each row until thenext( ) method returns false. A return value of falseindicates that there is no next row to move theresult set to.

Dealing with a row means retrieving the valuesfor its columns. Whatever the value in thedatabase, you can retrieve it using a gettermethod in the ResultSet interface. In Example 11-5, I used getInt( ) to retrieve the id column andgetString( ) to retrieve the val column. Thesegetter methods can accept either the number ofthe column starting with 1 or the column name.You should, however, avoid retrieving columnsby name because it is generally much slowerthan retrieving them by number.

11.2.2.2 Scrollable result sets

Page 505: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

By default, you are limited to simple forwardnavigation through a result set. JDBC does,however, provide a tool for navigating backwardand forward through a result set; it is called ascrollable result set. You can get scrollableresult sets back from your queries if you indicatethat you want a scrollable result set when youcreate your statement:

Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);

The first argument indicates that you want ascrollable result set. The second argumentindicates that you want a read-only result set.Non-read-only result sets are an advanced topicbeyond the scope of this chapter.

W ith a scrollable result set, you can make callsto:

previous( )

To navigate backward through the resultset. previous( ) moves the result set overone row except it moves the result set tothe row before the current row. It will returnfalse if there is no previous row to move to.

absolute( )

To move to an arbitrary row (similar to next()). absolute( ) requires the number of the rowto which you want to navigate,

Page 506: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

relative( )

To move to an arbitrary row (similar to next()). relative( ) moves the number of rows youspecify forward or backward. A negativenumber moves the result set backward, anda positive number forward. Thus, relative(1)is like next( ), and relative(-1) is like previous().

11.2.3 Transactions

Chapter 3 covered the role of transactions indatabase programming. The critical job of atransaction is to take the database from oneconsistent state to another. Your databasehandles many of the complexities of transactionmanagement. When you modify a table, theunderlying database acquires the appropriatelocks and guarantees that your changes do notconflict with those of another client.

In order for the database to properly manageyour transactions, your application needs to tellit what operations constitute a singletransaction. By default, JDBC treats everydistinct SQL execution as a transaction. Thisdefault is called auto-commit. In other words,each statement is committed the minute itcompletes unless there is application logic to thecontrary. The following code updates the balanceof a bank account in the default auto-commitmode:

float ob = account.getBalance( );Connection conn = null;

Page 507: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

account.calculateInterest( );try { Statement stmt = null; conn = ds.getConnection( ); stmt = conn.createStatement( ); stmt.executeUpdate("UPDATE account SET balance = " + account.getBalance( ) +" WHERE id = " + account.getId( ));}catch( SQLException e ) { account.resetBalance(ob);}catch( Error e ) { account.resetBalance(ob); throw e;}catch( RuntimException e ) { account.resetBalance(ob); throw e;}finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } }}

From a JDBC perspective, nothing in this samplecode differs from what you have done so far.What differs is the exception handling so thatyour application returns to a state consistentwith the database. In this case, when anexception occurs, the account object gets itsbalance set back to the value prior to calculatinginterest.

Page 508: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.2.3.1 Basic transactionmanagement

Rarely are transactions as simplistic as theprevious one. A given transaction can makenumerous modifications that need to occurtogether or not at all. The classic example ofsuch a transaction is a transfer of funds fromyour savings account to your checking account.This transaction includes the following steps:

1. Debit the savings account.

Credit the checking account.

If the credit to the checking account fails forwhatever reason, you as the account holdercertainly want that money recredited to thesavings account. In JDBC's default auto-commitmode, there is no sure way to achieve thisconsistency. You therefore need to turn auto-commit off and manually tell JDBC where tocommit the transaction. You also need to handleerrors so that it will get rolled back inexceptional conditions. The following code showsthis account transfer:

float sb = savings.getBalance( );float cb = checking.getBalance( );Connection conn = null;boolean success = false; savings.transfer(checking, 10.00);try { Statement stmt = null; conn = ds.getConnection( );

Page 509: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

conn.setAutoCommit(false); stmt = conn.createStatement( ); stmt.executeUpdate("UPDATE account SET balance = " + savings.getBalance( ) + " WHERE id = " + asavings.getId( )); stmt.executeUpdate("UPDATE account SET balance = " + checking.getBalance( ) + " WHERE id = " + achecking.getId( )); success = true;}catch( SQLException e ) { e.printStackTrace( );}finally { if( conn != null ) { if( success ) {try { conn.commit( ); }catch( SQLException e ) {savings.resetBalance(sb);checking.resetBalance(cb);try { conn.rollback( ); }catch( SQLException e ) { }}}else {savings.resetBalance(sb);checking.resetBalance(cb);try { conn.rollback( ); }catch( SQLException e ) { }} try { conn.close( ); } catch( SQLException e ) { } }}

The bold sections illustrate what changes formulti-statement transactions. First, you need toturn off auto-commit using setAutoCommit(false).

Page 510: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

You then execute transactions as you alwayswould. When done, you either commit thetransaction (using commit( )) or roll it back (usingrollback( )). In this sample, I have tracked thesuccess or failure of the transaction and Iperform the commit and rollback in the finallyblock.

11.2.3.2 Savepoints

As described earlier, transactions work well whenyou have a very straightforward beginning statewith only one possible consistent end state. Inother words, the database starts with one set ofvalues and should end up with another specificset of values when the transaction completes.Some situations, however, allow for multiplepossible consistent end states dependent on theevents that occur during the course of thetransaction. Such transactions require a muchmore fine grained approach to transactionmanagement than the commit/rollback schemeallows. JDBC manages these transactionsthrough savepoints.

A savepoint is a JDBC tool for marking adatabase state as a possible final consistentstate for a transaction. Specifically, you canexecute a statement and then establish asavepoint with the connection. Depending onwhat happens in the transaction, you can committhe transaction, roll it back, or roll it back to thesavepoint. If you roll back to the savepoint, youcan chose to commit that work or execute analternative flow for the transaction.

The mechanics of savepoints are simple:

Page 511: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Connection conn = ds.getConnection( );Statement stmt = conn.createStatement( );Savepoint sp; stmt.executeUpdate( "INSERT INTO test ( id, val ) VALUES ( 1, 'test')");sp = conn.setSavepoint("safety");stmt.executeUpdate( "INSERT INTO other ( id, name ) VALUES ( 32, 'sample')");try { stmt.executeUpdate("UPDATE test SET other = 32 WHERE id = 1");}catch( SQLException e ) { conn.rollback(sp);}conn.commit( );

The application sets the savepoint after the firstSQL. It can now guarantee that no matter whatelse happens, it can return the database to astate in which a new row is in the test tablewithout missing references or unreferencedvalues in the other table. If an error occurs in theSQL updating the test table so that the new testvalue points to the new other value, then thetransaction is rolled back so that the test valueexists alone in the database.

This example begs the question: why not simplycommit after the first statement? One reason isperformance. You do not need to release andreacquire any locks to execute the transaction.The other reason, however, would be in morecomplex transactions in which some branches oflogic after the savepoint is set need to roll backcompletely while others need to roll back only tothe savepoint.

Page 512: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

To illustrate the kind of logic to whichsavepoints apply, consider a game in which youtoss marbles into a jar. The goal of the game isto end up with the most marbles in the jar. Youstart the game with no marbles and continuetossing marbles into the jar until your fourthmiss or you call it quits. Your score is thenumber of marbles in the jar after your fourthmiss.

The trick behind scoring, however, is thatmissing two in a row returns your marble countto its number after your first miss. If you missthree in a row, the jar is emptied and your finalscore is whatever you can get in the jar beforeyour next miss.

In transactional terms, the following eventsoccur:

First miss: set a savepoint.

Second consecutive miss: roll back to thesavepoint.

Third consecutive miss: roll back the entiretransaction.

Fourth miss: commit.

11.2.4 Error Handling and Cleanup

All JDBC method calls can throw SQLException orone of its subclasses if something happensduring a database call. Your code should be setup to catch this exception, deal with it, andclean up any database resources that have been

Page 513: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

allocated. The basic skeleton of any JDBC code Iwrite looks like this:

Connection conn = null; try { // create the connection and execute your transaction}catch( SQLException e ) { // handle the exception}finally { if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } }}

Each of the major JDBC interfaces you haveencountered Connection, Statement, and ResultSethasa close( ) method. Practically speaking, however,you need only make sure you close yourconnection instances because closing aconnection closes all associated statements. Theclosing of a statement, in turn, closes allassociated result sets. By closing the connectionin the finally clause, you guarantee that theconnection will be closed even when an erroroccurs.

11.2.5 Prepared SQL

JDBC Statement instances illustrate basicdatabase programming well, but you rarely wantto use them in practice. Unfortunately, Statementsends your SQL to the database each time youexecute it. It provides the database with very

Page 514: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

little opportunity to optimize repeated SQL calls.

Consider the following SQL:

UPDATE account SET balance = 5.00 WHERE id = 2

If you use a Statement to support updating manyaccounts with a similar SQL call, the databasehas to process the SQL and determine how it willexecute the query every single time you send itto the database. You can avoid this overhead,however, through prepared SQL.

Databases support two kinds of prepared SQL:prepared statements and stored procedures.Prepared SQL provides an advantage over thesimple SQL statements you have covered so far;a database can get the SQL ahead of time andcreate a query plan while you are doing otherapplication logic. Your SQL should thereforeexecute faster. Furthermore, you have a genericreference to the statement for later reuseinstead of repeatedly re-creating similar SQLstatements.

Page 515: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 516: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

What Kind of Statement to UseThis tutorial introduces three kinds of JDBC statements.Each kind of statement even java.sql.Statement providesperformance benefits under certain situations.Unfortunately, you can rarely be certain which kind ofstatement w ill definitely provide you w ith the bestperformance for a given SQL call w ithout knowingdetails about the underlying database. I recommend theuse of java.sql.PreparedStatement except in a fewsituations in which stored procedures are demanded. Inother words, you should always avoid java.sql.Statement.It almost never is the best choice for optimalperformance. Even in the few situations in which itprovides the optimal performance, it is uglier code, moreerror-prone, and more difficult to maintain. I recommendthe use of stored procedures only for complex SQL callsthat are known to be bottlenecks as preparedstatements.

The optimization factor comes from the databaseknowing what you are about to do. When youcreate a Java instance of a prepared statementor stored procedure, you notify the database ofwhat SQL you intend to be calling withoutproviding any specific values. For example, theSQL to update account balances looks like thisas a prepared statement:

UPDATE account SET balance = ? WHERE id = ?

Instead of sending this SQL as an argument toexecuteUpdate( ), you pass it to the connectionwhen you create the statement. You then assignvalues to the two placeholders and finish bycalling executeUpdate( ). If you want to makefurther calls to update other accounts, you canreassign the statement new values and callexecuteUpdate( ) again.

Page 517: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.2.5.1 Prepared statements

The PreparedStatement interface extends theStatement interface we used earlier in the chapter.It enables a SQL statement to containparameters like a function call. You can executea single statement repeatedly with differentvalues. The act of assigning values toparameters is called binding parameters. Youmight want to use a prepared statement whenupdating a group of objects stored in the sametable. For example, if you update many bankaccounts as described earlier, you might have aloop like this:

Statement stmt = conn.createStatement( ); for(int i=0; i<accounts.length; i++) { stmt.executeUpdate("UPDATE account " + "SET balance = " + accounts[i].getBalance( ) + " " + "WHERE id = " + accounts[i].getId( ));}conn.commit( );

This statement keeps sending slightly differentSQL to the database each time it goes throughthe loop. Instead of calling this statementrepeatedly with different inputs, you can insteaduse a PreparedStatement:

PreparedStatement stmt = conn.prepareStatement("UPDATE account " + "SET balance = ? " + "WHERE id = ?");

Page 518: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

for(int i=0; i<accounts.length; i++) { stmt.setFloat(1, accounts[i].getBalance( )); stmt.setInt(2, accounts[i].getId( )); stmt.executeUpdate( ); stmt.clearParameters( );}conn.commit( );

With a prepared statement, you send the actualSQL to the database when you get thePreparedStatement object through theprepareStatement( ) method in java.sql.Connection.Keep in mind that you have not yet actuallyexecuted any SQL. You execute that preparedSQL statement multiple times inside the for( )loop, but you build the query plan only a singletime.

Before each execution of the preparedstatement, you tell JDBC which values to use asinput for that execution of the statement. Inorder to bind the input parameters,PreparedStatement provides setter methods likesetFloat( ) and setInt( )that mirror the gettermethods you saw in ResultSet. Just as the gettermethods read results according to the order inwhich you constructed your SQL, the settermethods bind parameters from left to right inthe order you placed them in the preparedstatement. In the previous example, I boundparameter 1 as a float to the account balancethat I retrieved from the account object. Thefirst ? was thus associated with parameter 1.

Page 519: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.2.5.2 Stored procedures

While prepared statements enable you to accesssimilar database queries through a singlePreparedStatement object, stored proceduresattempt to take the "black box" concept fordatabase access one step further. A storedprocedure is built inside the database before yourun your application. You access that storedprocedure by name at runtime. In other words, astored procedure is almost like a method you callin the database. Stored procedures have thefollowing advantages:

Because the procedure is precompiled in thedatabase for most database engines, itexecutes much faster than dynamic SQL.Even if your database does not compile thestored procedure before it runs, it will beprecompiled for subsequent runs just likeprepared statements.

Syntax errors in the stored procedure can becaught at compile time rather than runtime.

Java developers need to know only thename of the procedure and its inputs andoutputs. The way in which the procedure isimplemented is totally irrelevant.

The downside to stored procedures, however, isthat every database has its own storedprocedure language. If you use storedprocedures heavily, you can go to great lengths

Page 520: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

to make sure your Java application is database-independent yet still be tied to a specificdatabase because of the stored procedures.Worse, different databases do not even sharebasic semantics that would facilitate portingbetween database engines. For example, youcan retrieve results from a Sybase storedprocedure using a plain ResultSet. W ith Oracle,however, retrieving results from a storedprocedure is much more complex.

Using stored procedures, we can revise thebalance updating code to the following:

CallableStatement stmt = conn.prepareCall("{call sp_balance(?,?)}"); for(int i=0; i<accounts.length; i++) { stmt.setInt(1, accounts[i].getId( )); stmt.setFloat(2, accounts[i].getBalance( )); stmt.executeUpdate( );;}conn.commit( );

This example illustrates how close storedprocedures are to prepared statements from aJDBC perspective. The difference is that you arereferencing the stored procedure by name ratherthan spelling out the SQL you are calling. Theresult is simply increased performance at theexpense of portability.

Some stored procedures may have outputparameters. For those stored procedures, youneed to register the output parameter before youexecute the SQL:

CallableStatement stmt =

Page 521: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

CallableStatement stmt = conn.prepareCall("{call sp_interest(?, ?)}"); stmt.registerOutParameter(2, java.sql.Types.FLOAT);for(int i=0; i<accounts.length; i++) { stmt.setInt(1, accounts[i].getId( )); stmt.executeUpdate( ); accounts[i].setBalancce(stmt.getFloat(2));}conn.commit( );

The prepareCall( ) method creates a storedprocedure object that will make a call to aspecific stored procedure. This syntax sets upthe order you will use in binding parameters. Bycalling registerOutParameter( ), you tell theCallableStatement instance to expect the secondparameter as output of type float. Once thisprocedure is set up, you can bind the ID usingsetInt( ) and then get the output using getFloat( ).

Page 522: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.3 Advanced JDBC

You can develop entire applications using onlythe JDBC I have presented so far in this chapter.What you have seen, however, is not the end ofdatabase programming. JDBC provides manymore interfaces to support a variety of lesscommon, yet very important databaseprogramming needs.

11.3.1 Batch Processing

Complex systems often require both online andbatch processing. Each kind of processing hasvery different requirements. Because onlineprocessing involves a user waiting on applicationprocessing, the timing and performance of eachstatement execution in a process is important.Batch processing, on the other hand, occurswhen a bunch of distinct transactions need tooccur independent from user interaction. Abank's ATM machine is an example of a systemof online processes. The monthly process thatcalculates and adds interest to your savingsaccount is an example of a batch process.

JDBC enables you to assign a series of SQLstatements to a JDBC Statement (or one of itssubclasses) to be submitted together forexecution by the database. Using the techniquesyou have learned so far in this book, accountinterest calculation processing occurs roughly inthe following fashion:

Page 523: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

1. Prepare statement.

Bind parameters.

Execute.

Repeat steps 2 and 3 for each account.

This style of processing requires a lot of backand forth between the Java application and thedatabase. JDBC batch processing provides asimpler, more efficient approach to this kind ofprocessing:

1. Prepare statement.

Bind parameters.

Add to batch.

Repeat steps 2 and 3 until interest has beenassigned for each account.

Execute.

Under batch processing, there is no back andforth to the database for each account. Instead,all Java-level processing the binding ofparameters occurs before you send thestatements to the database. Communicationwith the database occurs in one huge burst; thehuge bottleneck of stop-and-go communicationwith the database is gone.

Statement and its children all support batch

Page 524: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

processing through an addBatch( ) method. ForStatement, addBatch( ) accepts a String that is theSQL to be executed as part of the batch. Thefollowing code shows how to use a Statementobject to batch process interest calculation:

Statement stmt = conn.createStatement( );int[ ] rows; for(int i=0; i<accts.length; i++) { accts[i].calculateInterest( ); stmt.addBatch("UPDATE account SET balance = " + accts[i].getBalance( ) + " WHERE id = " + accts[i].getId( ));}rows = stmt.executeBatch( );

The addBatch( ) method is basically nothing morethan a tool for assigning a bunch of SQLstatements to a single JDBC Statement. Becauseit makes no sense to manage results in batchprocessing, the statements you pass to addBatch() should be some form of an update: a CREATE,INSERT, DELETE, or UPDATE statement. Once youare done assigning statements, your applicationcalls executeBatch( ). This method returns an arrayof rows affected by each statement in the batch.For example, the first element contains thenumber of rows affected by the first statement.Upon completion, the list of SQL calls associatedwith the Statement instance is cleared.

Using prepared statements and callablestatements works very much like regularstatements, except you are assigning batches ofparameters instead of batches of individual

Page 525: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

statements. Interest calculation with a preparedstatement looks like this:

PreparedStatement stmt = conn.prepareStatement("UPDATE account " + "SET balance = ? " + "WHERE id = ?");int[ ] rows; for(int i=0; i<accts.length; i++) { accts[i].calculateInterest( ); stmt.setDouble(1, accts[i].getBalance( )); stmt.setInt(2, accts[i].getId( )); stmt.addBatch( );}rows = stmt.executeBatch( );

11.3.2 Metadata

The term metadata sounds officious, but it isreally nothing more than extra data about someobject that would otherwise waste resources if itwere actually kept in the object. For example,simple applications do not need the name of thecolumns associated with a ResultSettheprogrammer probably knew that when the codewas written. Embedding this extra information inthe ResultSet class is thus not considered byJDBC's designers to be part of the core ResultSetfunctionality. Data such as column names,however, is very important to some dataprogrammers especially to those writing dynamicdatabase access. The JDBC designers provideaccess to this extra information the metadata viathe ResultSetMetaData interface. For example, thisclass can tell you:

Page 526: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

The number of columns in a result set

Whether NULL is a valid value for a column

The label to use for a column header

The name for a column

The source table for a column

The data type of a column

Example 11-6 shows some of the source codefrom a command-line tool that accepts arbitraryuser input and sends it to a database forexecution.

Example 11-6. An application forexecuting dynamic SQL

import java.sql.*; public class Exec { static public void main(String[ ] args) { Connection conn = null; String sql = ""; for(int i=0; i<args.length; i++) { sql = sql + args[i]; if( i < args.length - 1 ) { sql = sql + " "; }

Page 527: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

} System.out.println("Executing: " + sql); try { Class.forName("org.gjt.mm.mysql.Driver") .newInstance( ); String url = "jdbc:mysql://localhost/Web"; Statement stmt; conn = DriverManager.getConnection(url, "dvl", "dvl"); stmt = conn.createStatement( ); if( stmt.execute(sql) ) { ResultSet rs = stmt.getResultSet( ); ResultSetMetaData meta = rs.getMetaData( ); int cols = meta.getColumnCount( ); int row = 0; while( rs.next( ) ) { row++; System.out.println("Row: " + row); for(int i=0; i<cols; i++) { System.out.print(meta.getColumnLabel(i+1) + ": " + rs.getObject(i+1) + ", "); } System.out.println(""); } } else { System.out.println(stmt.getUpdateCount( ) + " rows affected."); } stmt.close( ); } catch( Exception e ) { e.printStackTrace( ); } finally {

Page 528: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

if( conn != null ) { try { conn.close( ); } catch( SQLException e ) { } } } }}

This code introduces a few new features. Thefirst is the introduction of the execute( ) method.As you might guess from this code, execute( )enables you to send arbitrary SQL to thedatabase when you may not know whether it isan update or a query. It returns true if the SQLyou sent it returned results.

When the SQL sent to execute( ) does returnresults, you can retrieve them through a call togetResultSet( ). On the other hand, you can get thenumber of rows touched by an update throughgetUpdateCount( ).

The point of this example, however, is toillustrate the use of ResultSetMetaData. When thisapplication executes SQL that returns results, itneeds to find out about those results. It does soby getting the metadata through a call togetMetaData( ). The metadata tells the applicationhow many columns are in the result set so theapplication can loop through all of the columnsand get the column values.

JDBC supports other kinds of metadata. You willmost often be interested in DatabaseMetaDataoneof the most massive interfaces in the entire J2EEplatform. DatabaseMetaData provides information

Page 529: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

about your database connection and thedatabase to which it is connected. Finally, youcan retrieve information on statementparameters through the new ParameterMetaDatainterface.

11.3.3 Hidden Features

Some of JDBC's best features are things younever see as a programmeryour JDBC driverhandles all the details. You turn them onthrough configuration parameters in your datasource.

11.3.3.1 Connection pooling

The most important hidden feature is JDBCconnection pooling. Up to this point, you havecreated a connection, done your databasebusiness, and closed the connection. Thisprocess clearly works fine for the examples Ihave presented to this point in the book.Unfortunately, it does not work in real worldserver applications. It does not work becausethe act of creating a database connection is avery expensive operation for most databaseengines. If you have a server application such asa Java servlet or middle-tier application server,that application is likely going back and forthbetween the database many times per minute.Suddenly, the "open connection, talk to thedatabase, close the connection" model of JDBCprogramming becomes a huge bottleneck.

Page 530: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Through specialized data sources, JDBC supportsthe concept of connection pooling. Connectionpooling is a mechanism through which opendatabase connections are held in a cache for useand reuse by different parts of an application. Ina Java servlet, for example, each user initiatesthe execution of the servlet's doGet( ) method,which grabs a Connection instance from theconnection pool. When it is done serving thatuser, it returns the Connection instance to thepool. The Connection is never closed until the webserver shuts down.

Unlike the parts of the JDBC API you haveencountered so far, driver vendors do notnecessarily implement connection pooling. As Inoted earlier, connection pooling requires theuse of specialized data sources. It can thereforebe a function of your application server, yourdriver, or even your own custom data source.Consequently, you can take advantage ofconnection pooling even if your JDBC driver hasno support for it.

Because connection pooling occurs in the datasource, JDBC code using connection pools looksjust like the JDBC code we have covered to thispoint. Your data source that supports connectionpools provides you with a special, logicalconnection implementation that returns thephysical connection to the pool when you callclose( ). Figure 11-3 shows an activity diagramillustrating JDBC connection pooling.

Page 531: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Figure 11-3. An activity diagramshowing how connection pooling

works

The same as with all other JDBC code, yourapplication grabs a Connection from a DataSourceusing the getConnection( ) method. Internally, theDataSource talks to a ConnectionPoolDataSource thatholds pooled database connections. ThisConnectionPoolDataSource enables connectionpooling. When you close the connection in yourapplication, it returns to the connection pool.Any subsequent attempts to close thatconnection by your application will cause an error.

11.3.3.2 Prepared statement

Page 532: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

pooling

Prepared statement pooling is to preparedstatements as connection pooling is toconnections. In other words, prepared statementpooling enables you to keep a preparedstatement open so you can avoid the potentialoverhead of re-creating the same preparedstatement multiple times.

Prepared statement pooling rides on top ofconnection pooling and looks exactly like allother JDBC code from an application perspective.The only difference is that some data sourcesthat support connection pooling keep anyprepared statements associated with theirconnections open for later reuse. As withconnection pooling, when you close a pooledprepared statement, the close( ) method returnsthe prepared statement to the pool.

Connection pooling is naturally a trade-offbetween storing a number of connections inmemory and the cost of making connections. Younearly always want to opt to take the memoryhit. Prepared statement pooling, on the otherhand, does not involve such an obvious trade-off. If you pool all of your prepared statements,you will eat up memory and database resources.You should therefore plan your preparedstatement pooling to pool only those statementsfor which pooling will provide an obviousadvantage.

Page 533: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

11.3.3.3 Distributed transactions

All database access so far in this chapter hasinvolved transactions against a single database.In this environment, your DBMS manages thedetails of each transaction. This support is goodenough for most database applications. Ascompanies move increasingly toward anenterprise model of systems development,however, the need for supporting transactionsacross multiple databases grows. Where singledata source transactions are the rule today, theywill likely prove the exception in large-scaleprogramming in the future.

Distributed transactions are transactions thatspan two or more data sources. For example, youmay have an Informix database containing yourcorporate digital media assets and an Oracledatabase holding product data. When you deletea product from Oracle, you probably want todelete the commercials and pictures for thatproduct from Informix. W ithout support fordistributed transactions, you run the risk of onetransaction succeeding and the other failing yourdata thus ends up in an inconsistent state.

You could avoid the issue by picking onedatabase to hold everything. If you choose anice supercomputer with terabytes of storagespace and RAM, such a solution might work. Amore practical alternative, however, is to choosedatabase engines that are well suited for thetype of data being stored and split the dataacross multiple databases.

Page 534: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

As with prepared statement pooling, distributedtransactions ride on top of JDBC connectionpooling. From the application's point of view,programming with distributed transactions looksnearly like single data source transactions.Behind the scenes, your one data source actuallyhides many data sources. When you get aconnection from it, you are actually getting aconnection that manages two-phase commitsthrough a midtier transaction monitor.

I say that your application code is nearly thesame as code against a single data sourcebecause there are some small differences. Inshort, your code should not call commit( ),rollback( ), or setAutoCommit(true). Any attempt todo so will result in an SQLException. You do nothave to add any special code.

The application server's transaction monitorhandles the details of your distributedtransaction. The two-phase commit that itmanages is a standard protocol for handling acommit across two data stores. Under asimplistic description, the following events takeplace in a two-phase commit:

1. The transaction monitor (TM) asks datasource A if it can commit the pendingtransaction.

If data source A cannot commit, thetransaction rolls back and ends.

The TM asks data source B if it can commit.

Page 535: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

If data source B cannot commit, thetransaction rolls back and ends.

The TM logs the transaction to a distributedtransaction log.

The TM tells data source A to commit.

The TM tells data source B to commit.

The only reason either of the actual commits canfail is due to a server crash or some otherterrible event. Fortunately, the transaction logprevents those events from placing the systemin an inconsistent state. The transaction monitormaintains a consistent state by having theindividual data sources re-execute their portionof the transaction when they come back up.

Page 536: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 537: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Chapter 12. JDOWe say that error is appearance. This isfalse. On the contrary, appearance isalways true if we confine ourselves to it.Appearance is being.

Jean-Paul Sartre, Truth and Existence

Java Data Objects (JDO) is one of the first APIsto run through the Java Community Process(JCP). JDO enables application developers tobuild applications without worrying aboutpersistence issues. In other words, it does foryour application the same thing EJB container-managed persistence does for EJB applications.Where EJB seeks to deliver all the features ofenterprise systems development such as adistributed component model and full anddistributed transaction management JDO seeks toprovide developers with a more streamlined setof features.

JDO seeks to give applications with persistenceneeds the following capabilities:

Simplicity

Page 538: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Database independence

Performance

In other words, JDO is a database-independentpersistence API that has a simple programmingmodel designed to support the performanceneeds of common applications. Though EJB isdatabase-independent, it does not have a simpleprogramming model and performs poorly forsmall- to medium-scale applications.

Page 539: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 540: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Software RequirementsJDO is not a standard part of any Java platform. Youtherefore need a host of tools to support JDOdevelopment. Naturally, you need a data store. You alsoneed a JDO implementation. Depending on the nature ofthe implementation, you may need a JDBC driver or anyother of a number of third-party components.

The best way to get started is to download Sun'sreference JDO implementation athttp://java.sun.com/products/jdo. It uses yourfilesystem as a data store and frees you from needinganything else while you are learning JDO.

Page 541: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.1 Architecture

JDO is based on the concept of persistencetransparency. In other words, you write regularJava classes without worrying about conformanceto any particular contract. An application usespersistent business components in a JDOenvironment supplied by a JDO implementation.Figure 12-1 illustrates this high-levelarchitecture.

Figure 12-1. The JDO architecture

12.1.1 Business Objects

In JDO parlance, business objects are referred toas JDO instances. Because of JDO'stransparency, JDO instances can be regular user-defined Java classes or collections, JavaBeans,or even Enterprise JavaBeans. When youintroduce such a class into a JDO environment, itbecomes a persistence-capable class. Example12-1 shows a simple, persistence-capable Bookclass.

Page 542: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Example 12-1. A persistence-capable book class

package com.imaginary.ora; public class Book { String author; String isbn; String title; public Book( ) { super( ); } public Book(String auth, String num, String ttl) { super( ); author = auth; isbn = num; title = ttl; } public String getAuthor( ) { return author; } public String getIsbn( ) { return isbn; } public String getTitle( ) { return title; } public void setAuthor(String auth) {

Page 543: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

author = auth; } public void setIsbn(String num) { isbn = num; } public void setTitle(String ttl) { title = ttl; }}

You should not strain yourself looking foranything unfamiliar. This is the exact same Bookclass you would write in a nonpersistentapplication. The only aspect that relates to JDOis that you must have the default constructor.W ithout it, some enhancers may fail during theenhancing process. I will cover the enhancingprocess later in the chapter.

12.1.2 Applications

Your application uses persistent businessobjects and is responsible for interacting withJDO to make those objects persistent. Example12-2 creates a book in the data store using JDO.

Example 12-2. Persisting newbooks using JDO

package com.imaginary.ora;

Page 544: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

import java.util.Properties; import javax.jdo.*; public class Librarian { static public void main(String[ ] args) { PersistenceManagerFactory factory; Properties props = new Properties( ); PersistenceManager mgr; Transaction trans; // load JDO properties factory = JDOHelper.getPersistenceManagerFactory(props);mgr = factory.getPersistenceManager( );trans = mgr.currentTransaction( ); try { Book book = new Book("Daniel C. Dennett", "0-262-54053-3", "The Intentional Stance"); trans.begin( );mgr.makePersistent(book);trans.commit( ); } catch( Exception e ) { e.printStackTrace( ); } finally { if( trans.isActive( ) ) {trans.rollback( );}mgr.close( );

} }}

This sample method is the agent that makes

Page 545: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

your plain Book class a persistent JDO instance.It finds a persistence manager, creates atransaction, associates your new Book instancewith the transaction, and finally commits thetransaction. In the event of an exception, thecode rolls back the transaction. The only hocus-pocus I left out is something you should befamiliar with as a J2EE developer. Namely, I leftout setting up the properties that help theapplication interact with the JDO implementationit is using.

You have seen this use of properties in JDBCwith the calls to DriverManager and you have seenthis in JNDI with initial context properties. Whatis interesting about JDO properties is that manyof them exist to tell the persistence managerwhat properties to pass to the JDBC driver thatthe JDO implementation is using behind thescenes. Naturally, these properties are highlydependent on your runtime environment. Inaddition to telling JDO how to find a JDBC driver,they tell JDO what implementation class to usefor a PersistenceManagerFactory class.

12.1.3 Implementations

A JDO implementation is to JDO as a JDBC driveris to JDBC. In other words, it is the set ofconcrete classes that implements the interfacesof the JDO specification. The JDOimplementation performs the operations thatmake your business objects persist against adata store.

As with JDBC drivers, some JDO implementations

Page 546: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

cost money while others are free. Sun provides areference implementation on the JDO web site athttp://java.sun.com/products/jdo. Whichimplementation you use depends on the runtimeenvironment in which you intend to deploy.

The entry point into a JDO implementation is thePersistenceManagerFactory. Example 12-2 showedthe Librarian application using thePersistenceManagerFactory to get a PersistenceManagerclass. This task is in fact thePersistenceManagerFactory's raison d'être. You getaccess to a PersistenceManagerFactory by callinggetPersistenceManagerFactory( ) in the JDO JDOHelperclass.

Just about all other interaction between anapplication and a JDO implementation occursthrough the PersistenceManager you got from thefactory. Example 12-2 used thatPersistenceManager to manage a transaction inwhich a new Book was added to the library.

12.1.4 Data Stores

A data store is where you store your data. JDOdoes not require the data store to be a relationaldatabase. While it most commonly is a relationaldatabase, it can be an object database, a CRMsystem, a filesystem, or something completelydifferent.

Page 547: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.2 Enhancement

The JDO specification requires every persistentbusiness object to implement thePersistenceCapable interface. Though this seems tocontradict what I have been saying abouttransparency, it does not. JDO leverages aconcept called enhancement to enable yourbusiness objects to implement PersistenceCapableafter the fact.

Before deployment of a JDO application, you usea tool on your compiled Java classes to changetheir bytecode. Your JDO vendor generallysupplies the enhancement tool. No matter whatenhancement tool you use, the JDO specificationrequires that all vendors be able to support thereference JDO contract for enhancement. In otherwords, you can enhance with Vendor A's toolsand deploy in an environment using a JDOimplementation from Vendor B.

In truth, bytecode enhancement is not a requiredaspect of JDO. Your vendor, for example, canprovide tools to modify the source code. What isessential to JDO is:

You are not required to code your businessobjects to any particular specificationdictated by JDO.[1]

[1] If you intend to use JDO to support a bean-managed EJB, you need to conform to the EJBspecification.

Any bytecode that exists after enhancementcan run against any JDO implementation.

12.2.1 Class Metadata

For enhancement to work, you need to tell yourenhancement tool about the business object tobe made persistent. You accomplish this taskthrough the creation of an XML file that

Page 548: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

describes the business object class. Example 12-3 is the metadata description for the Book class.

Example 12-3. The Book metadata

<?xml version="1.0" ?><!DOCTYPE jdo SYSTEM "jdo.dtd"> <jdo> <package name="com.imaginary.ora"> <class name="Book"> <field name="author"/> <field name="isbn"/> <field name="title"/> </class> </package></jdo>

This file enables you to identify all persistentbusiness objects and their persistent fields. Thisexample shows only the most basic metadatadescription. We can make it more complex bypulling in some design elements from previouschapters.

<class name="Book"> <field name="bookID" primary-key="true"/> <field name="author"/> <field name="isbn"/> <field name="title"/></class>

This code adds a persistent field for bookIDa fieldthat happens to be a unique value across allBook instances. We can also add an Author classthat has a collection of books:

<class name="Author"> <field name="authorID" primary-key="true"/> <field name="books"><collection element-type="com.imaginary.ora.Book"/></field> <field name="firstName"/> <field name="lastName"/></class>

Page 549: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

This sample code shows how you can specify apersistent field that is a collection. In this case,it happens to be a collection of other persistentobjects.

12.2.2 Running the Enhancer

Once you have written metadata files to describeeach persistent object, you run the enhancer onit. The exact syntax of the enhancer dependsgreatly on what JDO implementation you areusing. To run the reference implementation'senhancer, you execute the following commandline:

Prompt$ java -classpath jdo.jar;jdori.jar;xerces.jar options com.sun.jdori.enhancer.Main classes and metadata

12.2.3 The Database

At some point, you need to create the tables inyour database to support your persistentobjects. In general, the JDO vendor you areusing will provide tools that reuse the metadatafor your objects to build relational tables. TheJDO specification, however, says nothing abouthow a relational structure should be created.

Page 550: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.3 Queries

Before you do anything else to your data store ofbooks, you need a way to get them out of thedata store. JDO provides a unique combinationof a query API combined with a simplistic querylanguage to enable access to objects in yourdata store.

12.3.1 The JDO Extent

JDO makes heavy use of a concept called anextent. An extent is like a virtual collection ofpersistent objects. By virtual, I mean that all theobjects represented by the extent are probablynot loaded into memory. A regular Javacollection, on the other hand, has all elementsof the collection in memory. The abstraction ofthe extent is critical to JDO programming since itperforms important optimization tasks like lazy-loading while hiding these complexities fromyour application.

The simplest use of an extent is as arepresentation for all instances of a particularpersistent class. The following code providesyour application with all books in the data store:

Extent ext = mgr.getExtent(Book.class, true);Iterator books = ext.iterator( ); while( books.hasNext( ) ) {

Page 551: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Book b = (Book)books.next( ); System.out.println("Got: " + b.getTitle( ));}ext.closeAll( );

Just as the application worked through thePersistenceManager to create new books, it alsoworks through the PersistenceManager to get anextent representing existing books. The secondparametera boolean value indicates whethersubclasses should be included in the extent. Inthis example, we indicated that we wantsubclasses even though we know Book has nosubclasses. The application takes an Iterator fromthe extent and goes through each one, printingits title.

12.3.2 The JDO Query

It is rare that you will want the whole list ofobjects of a certain class. For most applications,you will want to filter that list based on someset of criteria. The JDO query API provides a keyobject to enable complex queries, the Query. Thefollowing code provides all books by Anne Rice:

Extent ext = mgr.getExtent(Book.class, true);Query query = mgr.newQuery(ext, "author= =name");Collection results; query.declareParameters("String name");results = (Collection)query.execute("Anne Rice");

Page 552: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Using your PersistenceManager, you create a querybased on an Extent representing all books and afilter for elements in that Extent. In this case, thefilter is based on the author field. It tells thequery to look for all books for which the authorequals name. The name token is just aplaceholder. In the call to declareParameters( ), wetell the query that name is a parameter to bepassed in and that it will be a String. Finally, weget all matching books by calling execute( ) in thequery with a specific author name in this case,Anne Rice.

You can specify up to three parameters to anyquery execution using the preceding syntax.They will be matched to your parameterdeclarations in declareParameters( ) based on order.If you need more than three parameters, you canuse the executeWithArray( ) method instead ofexecute( ):

Extent ext = mgr.getExtent(Person.class, true);Query query = mgr.newQuery(ext, "lastName= =last & city= =cty &state= =st & birthCity = = bc");Object[ ] params = { "Allen", "Boston", "MA", "Miami" };Collection results; query.declareParameters("String last, String cty, " + "String st, String bc");results = (Collection)query.executeWithArray(params);

This uninteresting query returns all people inyour data store with the last name Allen wholive in Boston but were born in Miami.

Page 553: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Whatever syntax you use, the parameter passedshould be an object type the JDO implementationwill unwrap into primitives when appropriate.The best way to execute a multiparameterstatement, however, is through theexecuteWithMap( ) method:

Extent ext = mgr.getExtent(Person.class, true);Query query = mgr.newQuery(ext, "lastName= =last & city= =cty &state= =st & birthCity = = bc");Collection results;HashMap params; query.declareParameters("String last, String cty, " + "String st, String bc");params = new HashMap( );params.put("last", "Allen");params.put("cty", "Boston");params.put("st", "MA");pparams.put("bc", "Miami");results = (Collection)query.executeWithMap(params);

When you use a map, you make your Java codeindependent of the order specified in your query.You can therefore make changes to the order ofthe parameters in the query without having tomake any changes to the Java code. If you hadused an array, you would have to make sure theparameters were placed into the array in theproper order.

12.3.3 Complex Queries

JDO supports many different ways for performing

Page 554: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

queries depending on your application needs. Inan application context, for example, it iscommon to ask which objects in a subset ofobjects meet certain criteria. To facilitate thesekinds of queries, JDO enables you to operate oncollections as well as extents. The followingquery provides all of the books by a particularauthor published in 1991:

Query query = mgr.newQuery(Book.class, author.getBooks( ), "year= =yr");Collection results; query.declareParameters("int yr");results = (Collection)query.execute(new Integer(1991));

The code is nearly identical to everything youhave seen so far. The key difference is the useof a collection in constructing the query insteadof an extent. In this case, author.getBooks( ) is acall to get all associated books from an instanceof the Author class representing a specific author.Those books form the set of objects on whichthe query operates.

In addition to parameters, JDO also enables youto declare variables to be used in filtering. Thisfeature is useful when you want to operate onindividual elements in a collection field. If, forexample, we wanted all authors who had writtenfor a particular genre, we might execute againstthe database using the following SQL join:

SELECT Author.authorIDFROM Author, Book

Page 555: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

WHERE Author.authorID = Book.bookIDAND Book.genre = "some genre";

JDO does things differently. As before, you startwith the Author extent. This time, however, youcreate a variable that will represent each of anauthor's books and compare that book's genre tothe target genre:

Extent ext = mgr.getExtent(Author.class, true);Query query = mgr.newQuery(ext, "books.contains(book) & book.genre = =genre");Collection results; query.declareParameters("String genre");query.declareVariables("com.imaginary.ora.Book book");results = (Collection)query.execute("HORROR");

This critical aspect of variable usage is thecontains( ) call. In truth, it is a rather unintuitivesyntactic construct. It is saying that for eachbook found in the author's list of books (books),that book will be assigned to the book variableand used in the comparison book.genre = = genre.

Unlike parameters, multiple variabledeclarations are separated by semicolons (;).

The JDO specification requires that your contains() clause be on the lefthand side of any &expression. Furthermore, each part of a |

Page 556: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

expression must have a contains( ) clause.

Finally, you can order your results using thesetOrdering( ) method in query:

query.setOrdering("lastName descending, firstName descending");

As you would probably expect, this call tells thequery to sort on lastName followed by firstName.You can sort on fields of any primitive typeexcept boolean. In addition, you can sort on fieldsof a wrapper type (except Boolean), BigDecimal,BigInteger, String, and Date.

12.3.4 The Filter Language

I have danced around the issue of describing thefiltering syntax until now. In general, it is fairlystraightforward. It looks and acts a lot like Java.In fact, the only oddity so far has been the useof a single & for "and". As a whole, the filterlanguage follows Java syntaxes with somelargely natural exceptions. The exceptionsinclude:

The filter syntax provides the ability tocompare and operate on primitives andwrappers together.

Objects provide access to only a fewmethods such as String.startsWith( ),String.endsWith( ), Collection.contains( ), andCollection.isEmpty( ).

Page 557: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Operations on NULL values do not throw aNullPointerException. Instead, they evaluateto false.

You use variable declarations to navigatethrough collections within the filter.

You cannot make assignments in yourfilters.

& is a logical "and"; && is a conditional"and".

Page 558: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.4 Changes

You can now create new persistent objects andread them from the underlying data store. Thenext task is to modify your persistent objects.JDO does not require any special work forchanges to an object the changes areautomatically reflected in the data store.Deletion, however, requires some work.

Just as the PersistenceManager enables you tocreate persistent objects through makePersistent(), it enables you to delete them throughdeletePersistent( ):

mgr.deletePersietent(book);

The book is now gone from the data store!

From a technical perspective, deletion is thissimple. In reality, JDO does you no favors whenit comes to managing object relationships. Thepreceding call would, in fact, delete the bookfrom the data store. But it would also leave itsAuthor object with a NULL value in its list ofbooks. You are responsible for maintaining theintegrity of the object relationships:

Page 559: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Collections books = author.getBooks( );Book book; // loop through the list, find the one you do not wantbooks.remove(book);author.setBooks(books);mgr.deletePersistent(book);

The integrity of your object relationships and theunderlying data store integrity are nowprotected.

Page 560: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.5 Transactions

Early in the chapter, I introduced some basictransactional semantics in the form of a JDOtransaction object that enables you to begin,commit, and roll back a transaction. In reality,JDO does not require you to operate in atransactional context. If your environmentsupports transactions, however, it is a good ideato leverage this functionality since transactionsare ultimately the key factor in long-term dataintegrity.

12.5.1 The Transaction Class

Each PersistenceManager provides exactly oneTransaction to manage transactions. In otherwords, for operations against a givenPersistenceManager, you can execute at most onetransaction at a time.

JDO supports two transaction types:

Data store transaction management

Optimistic transaction management

Page 561: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Data store transaction management is whereJDO lets the underlying data store manage yourtransactions. From the time you begin thetransaction until the time you commit or rollback, JDO has an open transaction and alloverhead such as locks associated with it in thedata store. The data store performs and commitsor roll backs.

Under optimistic transaction management, a JDOimplementation manages transactional integritylocally until a commit or rollback is issued. For acommit, the implementation verifies the dataintegrity, opens a transaction with the datastore, and sends all changes at once.

Telling a transaction to use optimistic or datastore transaction management is a singlemethod call:

trans.setOptimistic(true);

Passing in true turns on optimistic transactionmanagement, whereas passing in false turns ondata store transaction management. Some JDOimplementations will not support optimistictransaction management. In those cases, thismethod will throw a

Page 562: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

JDOUnsupportedOptionException.

12.5.2 Managed Versus NonmanagedEnvironments

JDO applications can run either in managed ornonmanaged environments. So far in thischapter, the examples have assumed anonmanaged environment. Managed ornonmanaged simply refers to whether the JDOenvironment leverages some kind of externaltransaction management system to manage itstransactions. The most common managedenvironment you will encounter is using JDO in aJ2EE application server to provide bean-managedpersistence to Enterprise JavaBeans.

In a managed environment, your applicationcannot make calls to commit and roll backtransactions. Any attempt to do so will result ina JDOUserException. Beginning, committing, androlling back transactions are the job of theapplication server.

Page 563: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

12.6 Inheritance

In object-relational systems, inheritance can bea tricky beast. The problem with inheritance isthe lack of support for inheritance in relationaldatabases. In other words, you need to persist aconcept from your application that a relationalsystem has no way of modeling. Fortunately,JDO handles this beast for you. Figure 12-2shows a Person class with many Role instances.Role, however, is an abstract class. Itssubclasses include Admin, Employee, Manager, andContractor.

Figure 12-2. An abstract Role withmany implementation classes

We can build this class model using the normalJava approach. The next step is to build ametadata descriptor for the Person class asshown in Example 12-4.

Example 12-4. A metadata

Page 564: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

descriptor with abstractpersistent fields

<?xml version="1.0" ?><!DOCTYPE jdo SYSTEM "jdo.dtd"> <jdo> <package name="com.imaginary.ora"> <class name="Person"> <field name="personID" primary-key="true"/> <field name="lastName"/> <field name="firstName"/> <field name="title"/> <field name="roles"> <collection element-type="com.imaginary.ora.Role"/> </field> </class> <class name="Role"> <field name="code"/> <field name="name"/> </class> <class name="Employee" persistence-capable-superclass="com.imaginary.ora.Role"></class> ... </package></jdo>

This code tells the JDO implementation thatEmployee is a persistent object and that itderives some or all of its persistence from theRole class.

Page 565: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Earlier in the chapter, I mentioned how thesecond argument to getExtent( ) inPersistenceManager is a boolean indicating whethersubclasses may be counted in the extent. If youtell it not to count subclasses, it will return onlyexact instances of the class in question. Thisfeature enables you to limit queries to a specificclass or to the class and its subclasses.

Page 566: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Colophon

Our look is the result of reader comments, ourown experimentation, and feedback fromdistribution channels. Distinctive coverscomplement our distinctive approach to technicaltopics, breathing personality and life intopotentially dry subjects.

The animal on the cover of Java Database BestPractices is a taguan. The taguan (Petauristapetaurista) is giant flying squirrel. It lives indense, tropical rainforests, ranging from theeastern regions of Afghanistan to Java, and fromKashmir, Taiwan, and southern China to SriLanka. It is most often found in the Pakistan'stemperate forests.

The squirrel conceals its nest in the cavity of atree, raising 2-3 young at a time. It has alifespan of approximately 16 years. It is anocturnal animal, recognizable by its big eyesand reddish color. The taguan consumes a dietof pine cones, fruit, leaves, and nuts.

The taguan is an excellent climber. Additionally,it is referred to as a "flying" squirrel because ofthe muscular membrane that extends from itswrists to its hind legs, enabling it to glide long

Page 567: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

distances. It leaps from high tree branches andthe tops of trees, controlling the direction of itsflight by flexing and relaxing the muscles of themembrane.

Colleen Gorman was the production editor, andNorma Emory was the copyeditor for JavaDatabase Best Practices . Linley Dolby and JaneEllin provided quality control. Angela Howardwrote the index.

Emma Colby designed the cover of this book,based on a series design by Edie Freedman. Thecover image is a 19th-century engraving fromAnimate Creation, Volume II. Emma Colbyproduced the cover layout with QuarkXPress 4.1using Adobe's ITC Garamond font.

David Futato designed the interior layout. Thisbook was converted by Joe W izda to FrameMaker5.5.6 with a format conversion tool created byErik Ray, Jason McIntosh, Neil Walls, and MikeSierra that uses Perl and XML technologies. Thetext font is Linotype Birka; the heading font isAdobe Myriad Condensed; and the code font isLucasFont's TheSans Mono Condensed. Theillustrations that appear in the book wereproduced by Robert Romano and Jessamyn Readusing Macromedia FreeHand 9 and Adobe

Page 568: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Photoshop 6. The tip and warning icons weredrawn by Christopher Bing. This colophon waswritten by Colleen Gorman.

The online edition of this book was created bythe Safari production group (John Chodacki, BeckiMaisch, and Madeleine Newell) using a set ofFrame-to-XML conversion and cleanup toolswritten and maintained by Erik Ray, Benn Salter,John Chodacki, and Jeff Liggett.

Page 569: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

[ Team LiB ]

Page 570: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

! (negation, JNDI search filter) "Denormalization Guidelines" (Mullins) & (conjunction, JNDI search filter) & (logical and, JDO filters) && (conditional and, JDO filters) <array> tag <bag> tag <cascade-delete> tag <container-transaction> tag <ejb-name> tag <jsp:include> tag <jsp:useBean> tag <list> tag <map> tag <method> tag <primitive-array> tag <query> tag <relationships> tag <set> tag <trans-attribute> tag * (w ildcard, JNDI search filter) * (multiplication, SQL) + (addition, SQL) - (subtraction, SQL) / (division, SQL) < (less than, SQL) <%...%> (Java code in JSP) 2nd <%=...%> (values to print in JSP) 2nd <%@...%> (directives in JSP) <= (less than, JNDI search filter) <= (less than or equal to, SQL) <> (not equal, SQL) = (equality, JNDI search filter) = (equal, SQL)

Page 571: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

=* (presence, JNDI search filter) > (greater than, SQL) >= (greater than, JNDI search filter) >= (greater than or equal to, SQL) \ (escape, JNDI search filter)[\] | (disjunction, JNDI search filter) ~ (complement, SQL) ~= (approximate equality, JNDI search filter) 1NF [See first normal form]2NF [See second normal form]3NF [See third normal form]4NF [See fourth normal form]5NF [See fifth normal form]

[ Team LiB ]

Page 572: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

absolute( ) method (JDBC) abstract schema name abstraction accessor methods [See getter methods setter methods]ACID properties Active Directory Service [See ADS]addBatch( ) method (JDBC) addition (+), SQL ADS (Active Directory Service) aliasing, in SQL Also Sprach Zarathustra (Nietzsche) AND operator, SQL anomalies, database 2nd application (business) logic client/server architecture and design patterns supporting distributed architectures and separation of application assembler, EJB application exceptions applications database, architectures for developers for separate layers of Guest Book example [See Guest Book application] JDO 2nd persistence against relational database 2nd [See alsopersistence] persistence models for types of simple approximate equality (~=), JNDI search filter architectures database network principles for

Page 573: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

software 2nd system 2nd relational data arithmetic operators, in SQL articles [See publications]assigned algorithm (Hibernate) atomicity of transaction attribute domain [See data types]Attributes class (JNDI) 2nd attributes, entity 2nd attributes, object JNDI lookups of multivalued, mapping of attributes, table [See columns]auto-commit transactions 2nd

[ Team LiB ]

Page 574: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

bandwidth for database servers batch processing, w ith JDBC batch transactions BCNF [See Boyce-Codd normal form]bean-managed persistence [See BMP]beans, types of 2nd begin( ) method, Database session beginTransaction( ) method behavioral view, software architecture Being and Time (Heidegger) BETWEEN operator, SQL BIGINT datatype (SQL) binary data, storing in database BMP (bean-managed persistence) 2nd data access objects for exception handling w ith state management for using w ith JDO persistence value objects for books [See publications]Boyce-Codd normal form (BCNF) business logic [See also application logic] as part of application logic for Guest Book application business logic layer, distributed architectures business objects, JDO 2nd modifying querying business patterns

[ Team LiB ]

Page 575: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Cache class 2nd 3rd cache( ) method caching objects 2nd Call Level Interface [See CLI, X/OPEN SQL]CallableStatement interface (JDBC) candidate key Castor field mapping in XML persistence methods persistence w ith searches software requirements for web site for CHAR datatype (SQL) 2nd character data types, in SQL Chomsky, Noam (philosopher) 2nd ClassCastException CLASSPATH environment variable CLI (Call Level Interface), X/OPEN SQL client, fat client/server architecture close( ) method, Database session CMP (container-managed persistence) model choosing EJB 1.x CMP 2nd 3rd EJB 2.x CMP 2nd CMR (container-managed relationships) Codd, E. F. (relational principles) columns (attributes) Comment class 2nd CommentDAO class 2nd commit( ) method (JDBC) 2nd commit( ) method, Database session Common Object Request Broker Architecture [See CORBA]

Page 576: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

comparison operators, in SQL complement (~), SQL complex value objects component models 2nd [See also EJB; JavaBeans]3rd 4th composite entities [See join tables]composite pattern concurrency optimistic pessimistic conditional and (&&), JDO filters conjunction (&), JNDI search filter CONNECT statement (SQL) Connection interface (JDBC) 2nd 3rd 4th connection pooling ConnectionPoolDataSource class (JDBC) consistency of transaction constraints 2nd contact information, O'Reilly & Associates, Inc. container provider, EJB container-managed persistence model [See CMP model]container-managed relationships [See CMR]contains( ) method (JDO) content generation layer, distributed architectures content management layer, distributed architectures control logic as part of application logic for Guest Book application conventions used in this book CORBA (Common Object Request Broker Architecture) CREATE DATABASE statement (SQL) CREATE INDEX statement (SQL) CREATE statement (SQL) CREATE TABLE statement (SQL) create( ) method, Comment class create( ) method, Database session createDatastore( ) method createStatement( ) method (JDBC) The Critique of Pure Modernity (Kolb) cross join, in SQL

Page 577: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

cross-reference tables [See join tables]

[ Team LiB ]

Page 578: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Darw in's Dangerous Idea (Dennett) data access logic data access object pattern data access objects for Guest Book application mementos used w ith data architecture [See relational data architecture]data integrity, transactions used to ensure data models 2nd [See also relational model]data storage layer, distributed architectures data storage logic data stores, JDO data types (attribute domain) 2nd data types (SQL) data, dividing among disks database 2nd 3rd anomalies of 2nd binary data in connecting to, w ith JDBC connection pooling creating w ith SQL deleting in SQL JDO locking by metadata about object-oriented [See OODBMS ORDBMS] persistence using 2nd [See also persistence] querying, in SQL 2nd 3rd transaction log database application architectures network principles of software 2nd system 2nd

Page 579: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

database engine Database Programming w ith JDBC and Java (Reese) database servers bandwidth for processing load placed on database software DatabaseMetaData interface (JDBC) DataSource class (JDBC) 2nd DataSource connectivity (JDBC) Davidson, Donald (philosopher) 2nd DECIMAL datatype (SQL) declarative transaction management declareParameters( ) method (JDO) DELETE statement (SQL) 2nd deletePersistent( ) method (JDO) deletion anomalies 2nd Dennett, Daniel (philosopher) 2nd denormalization 2nd [See also normalization]deployer, EJB Descartes, René (philosopher) 2nd design patterns 2nd Design Patterns (Gamma, Helm, Johnson, Vlissides) development EJB roles for for separate application layers diagram [See ERD]DirContext class (JNDI) directives, in JSP page directory service 2nd [See also JNDI]dirty read Discourse on the Method (Descartes) disjunction (|), JNDI search filter disks 2nd 3rd distributed architectures distributed component management distributed objects, accessing [See RMI]distributed transactions 2nd division (/), SQL DKNF (domain/key normal form) [See seventh normal form]

Page 580: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

DNS (Internet Domain Name Service) doEndTag( ) method (JSP) domain [See data types]Domain Name Service [See DNS]domain/key normal form [See seventh normal form]DOUBLE datatype (SQL) Driver class (JDBC) 2nd 3rd DriverManager class (JDBC) DriverManager connectivity (JDBC) 2nd drivers, JDBC DROP DATABASE statement (SQL) durability of transaction

[ Team LiB ]

Page 581: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

EJB (Enterprise JavaBeans) 2nd accessing from JNDI 2nd compared to JDO component model 2nd development roles for distributed architecture used w ith persistence models BMP and 2nd BMP w ith JDO EJB 1.x CMP 2nd 3rd EJB 2.x CMP 2nd 3rd transactions 2nd when to use 2nd 3rd ejbCreate( ) method 2nd 3rd EJBException ejbFindXXX( ) methods 2nd ejbLoad( ) method 2nd EJBObject class ejbPostCreate( ) method EJBQL (Enterprise JavaBeans Query Language) ejbRemove( ) method ejbStore( ) method 2nd encapsulation ENCRYPT( ) function (SQL) enhancer, JDO An Enquiry Concerning Human Understanding (Hume) Enterprise JavaBeans [See EJB]Enterprise JavaBeans (Monson-Haefel) 2nd 3rd enterprise platforms, types of entities entity beans 2nd 3rd as JDO PersistenceCapable class handling persistence for [See CMP data access objects] sharing data w ith client [See value objects]

Page 582: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

entity relationship diagram [See ERD]EntityBean class equal (=), SQL equality (=), JNDI search filter ERD (entity relationship diagram) 2nd error handling [See exception handling]escape (\), JNDI search filter event management 2nd [See also transactions]exception handling EJB BMP JDBC 2nd RMI execute( ) method (JDBC) execute( ) method (JDO) executeBatch( ) method (JDBC) executeQuery( ) method (JDBC) executeUpdate( ) method (JDBC) executeWithArray( ) method (JDO) executeWithMap( ) method (JDO) 2nd EXPLAIN command (SQL) Extent class (JDO) extents, JDO

[ Team LiB ]

Page 583: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

factory pattern fat client fat server field mapping [See object-relational mapping]fields, table [See columns]fifth normal form (5NF) filter language, JDO findByPrimaryKey( ) method finder methods BMP EJB 1.x CMP 2nd EJB 2.x CMP first normal form (1NF) FK, indicating foreign key FLOAT datatype (SQL) 2nd flush( ) method fonts used in this book foreign key 2nd fourth normal form (4NF) 2nd 3rd full join, in SQL functional dependencies functions, in SQL

[ Team LiB ]

Page 584: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Gamma, Erich (Design Patterns) Garrett Millikan, Ruth (philosopher) getApproved( ) method, Comment class getComment( ) method, Comment class getConnection( ) method (JDBC) getDatabase( ) method getExtent( ) method (JDO) getMetaData( ) method (JDBC) getOQLQuery( ) method getPending( ) method, Comment class getPersistenceManagerFactory( ) method (JDO) getReference( ) method (JNDI) getResultSet( ) method (JDBC) getter methods for CMR fields in JavaBeans in ResultSet interface getUpdateCount( ) method (JDBC) 2nd greater than (>), SQL greater than (>=), JNDI search filter greater than or equal to (>=), SQL GROUP BY clause (SQL) Guest Book application business logic for cache for control logic for data access objects for design of mementos sequence generation view logic for

[ Team LiB ]

Page 585: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

hardware HashMap class 2nd 3rd Heidegger, Martin (philosopher) 2nd Helm, Richard (Design Patterns) Hibernate field mapping in XML persistence methods persistence w ith 2nd searches software requirements for web site for hierarchical data model HIGH-LOW algorithm (Castor) hilo.hex algorithm (Hibernate) hilo.long algorithm (Hibernate) history of Java database programming 2nd of SQL home for business objects (EJB) home interface, for beans hostility of network segment HTML generating dynamically [See JSP] MVC pattern used for Hume, David (philosopher) 2nd

[ Team LiB ]

Page 586: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

IDE disks identifying attributes IDENTITY algorithm (Castor) IN operator, SQL indexes creating in SQL disk assignments for unique The Individuation of Events (Davidson) inheritance JDO modeling for mapping to relational database InitialContext class (JNDI) 2nd 3rd inner join, in SQL 2nd INSERT statement (SQL) 2nd insertion anomalies 2nd instance, of entity INT datatype (SQL) INTEGER datatype (SQL) integration services layer, distributed architectures integrity [See data integrity]internationalization, factory pattern used by Internet Domain Name Service [See DNS]isEmpty( ) method isolation levels isolation of transaction 2nd

[ Team LiB ]

Page 587: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

J2EE (Java 2 Enterprise Edition) 2nd J2SE (Java 2 Standard Edition) Java 2 Enterprise Edition [See J2EE]Java 2 Standard Edition [See J2SE]Java applications [See applications]Java Data Objects [See JDO]Java Message Service API [See JMS API]Java Naming and Directory Interface [See JNDI]Java Swing 2nd JavaBeans component model 2nd 3rd JavaServer Pages [See JSP]JDBC accessing from JNDI batch processing batch transactions classes and interfaces for connecting to database distributed transactions drivers for exception handling 2nd history of 2nd limitations of metadata ODBC bridge for 2nd prepared statements batch processing of pooling of properties file for database connection queries, executing 2nd savepoints SQL standard used by stored procedures 2nd transaction isolation levels transactions 2nd 3rd

Page 588: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

transactions paradigm URL 2nd when to use JDO (Java Data Objects) applications 2nd compared to EJB CMP data stores database for EJB BMP and enhancement extents filter language implementations inheritance instances (business objects) 2nd modifying querying managed and nonmanaged environments metadata for business object persistence model 2nd 3rd properties software requirements for transactions 2nd when to use 2nd JDOHelper class (JDO) 2nd JDOUnsupportedOptionException JDOUserException JMS (Java Message Service) API JNDI (Java Naming and Directory Interface) architecture of component access from EJB using 2nd programming w ith RMI and SPI (Server Provider Interface) for Johnson, Ralph (Design Patterns) join tables joins, in SQL 2nd JSP (JavaServer Pages)

Page 589: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

custom tags for page structure for programming w ith tag libraries developed w ith JavaBeans

[ Team LiB ]

Page 590: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Kant, Immanuel (philosopher) 2nd key generation [See sequence generation]Kolb, David (philosopher) 2nd

[ Team LiB ]

Page 591: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Language and Thought (Chomsky) Language, Thought, and other Biological Categories (GarrettMillikan) lazy-loading 2nd 3rd left join, in SQL LEFT( ) function (SQL) LENGTH( ) function (SQL) less than (<), SQL less than (<=), JNDI search filter less than or equal to (<=), SQL LIKE operator, SQL listener pattern load( ) method, Comment class locking log files disk assignments for transactions logical and (&), JDO filters logical data model logical operators, in SQL 2nd lookup tables lookups, naming and directory service lossless decomposition

[ Team LiB ]

Page 592: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

makePersistent( ) method (JDO) managed environment, JDO Mandatory transactional attribute many-to-many relationships 2nd mapping [See object-relational mapping]marshaling MAX algorithm (Castor) MEDIUMINT datatype (SQL) memento design pattern 2nd 3rd memory object caching RAM 2nd message-driven beans metadata in JDBC in JDO Microsoft Active Directory Service [See ADS]Millikan, Ruth Garrett (philosopher) missing value [See NULL]model-delegate pattern model-view-controller pattern [See MVC pattern]models [See component models data models persistence,models relational model]Monson-Haefel, Richard (Enterprise JavaBeans) 2nd 3rd Mullins, Craig ("Denormalization Guidelines") multiplication (*), SQL multivalued attributes MVC (model-view-controller) pattern mysql command

[ Team LiB ]

Page 593: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Name class (JNDI) Naming class (RMI) naming service 2nd [See also JNDI]native algorithm (Hibernate) natural join, in SQL NCHAR datatype (SQL) 2nd negation (!), JNDI search filter network architecture network data model network segmentation Never transactional attribute next( ) method (JDBC) Nietzsche, Friedrich (philosopher) 2nd NoInitialContextException nonmanaged environment, JDO nonrepeatable read normal forms normalization 2nd [See also denormalization] Boyce-Codd normal form (BCNF) fifth normal form (5NF) first normal form (1NF) fourth normal form (4NF) 2nd 3rd goals of preparing for second normal form (2NF) seventh normal form (DKNF) third normal form (3NF) 2nd NoSuchElementException not equal (<>), SQL NOT NULL constraint (SQL) NOT operator, SQL NotSupported transactional attribute NULL comparisons w ith, in SQL

Page 594: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Java treatment of NOT NULL constraint, in SQL NullPointerException NUMBER datatype (SQL) numeric data types, in SQL NVARCHAR datatype (SQL) NVARCHAR2 datatype (SQL)

[ Team LiB ]

Page 595: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

O'Reilly & Associates, Inc., contact information for object data model Object Query Language [See OQL]object reuse 2nd object serialization object-oriented database management system [See OODBMS]object-oriented principles object-relational database management systems [SeeORDBMS]object-relational mapping Castor EJB CMP Hibernate objects attributes of, multivalued caching home for (EJB) lazy-loading attributes of mapping to relational database remote, accessing [See RMI] sharing state between [See memento design pattern] soft references to strong references to ODBC (Open Database Connectivity) 2nd one-to-many relationships 2nd one-to-one relationships 2nd OODBMS (object-oriented database management system) Open Database Connectivity [See ODBC]open source software 2nd [See also Castor; Hibernate]operators, in SQL optimistic concurrency optimistic transaction management, JDO 2nd OQL (Object Query Language) OQLQuery class

Page 596: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

OR operator, SQL ORDBMS (object-relational database management system) ORDER BY clause (SQL)

[ Team LiB ]

Page 597: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

P2P (peer-to-peer) architecture patterns, software design [See design patterns]peer-to-peer architecture [See P2P architecture]performance bandwidth denormalization affecting disk access speed locking affecting RAM transactions affecting 2nd persistence design patterns 2nd JavaBeans not supporting models BMP 2nd Castor 2nd 3rd choosing 2nd EJB 1.x CMP 2nd 3rd EJB 2.x CMP 2nd Hibernate 2nd 3rd 4th 5th history of JDO 2nd 3rd 4th JDO w ith EJB BMP standards and transparency of RMI not supporting persistence delegate pattern [See data access object pattern]persistence-capable class, JDO PersistenceCapable interface (JDO) 2nd PersistenceException PersistenceManager class (JDO) PersistenceManagerFactory class (JDO) 2nd pessimistic concurrency phantom read

Page 598: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

philosophers quoted in this book physical data model PK, indicating primary key polymorphism prepareCall( ) method (JDBC) prepared statements batch processing pooling PreparedStatement interface (JDBC) 2nd 3rd 4th prepareStatement( ) method (JDBC) presence (=*), JNDI search filter previous( ) method (JDBC) primary key 2nd [See also unique index]3rd candidate keys for data types for foreign keys and indicating in ERD SQL 2nd unique identifiers for [See sequence generation]properties file, for JDBC database connection provider, EJB psql command publications about denormalization about design patterns about EJB 2nd 3rd about JDBC about philosophy web site listing

[ Team LiB ]

Page 599: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

queries [See EJBQL OQL searches SQL]Query class (JDO) QueryResults class

[ Team LiB ]

Page 600: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

RAID of IDE disks RAM for database engine requirements for batch transactions RAND( ) function (SQL) read committed transactions, isolation level read uncommitted transactions, isolation level read-heavy data rebind( ) method (RMI) 2nd recovery, from batch transactions Reese, George (Database Programming w ith JDBC and Java) Reference class (JNDI) 2nd Referenceable interface (JNDI) referential integrity, managed by CMR registerOutParameter( ) method (JDBC) Registration class relational data architecture denormalization modeling w ith ERD 2nd normalization relational database [See database]relational model constraints entities normalization protecting NULL value relationships in relative( ) method (JDBC) Remote interface (RMI) 2nd Remote Method Invocation [See RMI]RemoteException 2nd 3rd remove( ) method, Comment class repeatable read transactions, isolation level Required transactional attribute

Page 601: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

RequiresNew transactional attribute ResourceBundle class (JDBC) resources [See publications web sites]ResultSet interface (JDBC) 2nd ResultSetMetaData interface (JDBC) right join, in SQL RMI (Remote Method Invocation) bean interfaces using exceptions JNDI and limitations of object serialization remote interfaces remote object access rmic command (RMI) rmiregistry (RMI) rollback( ) method (JDBC) 2nd ROUND( ) function (SQL) rows

[ Team LiB ]

Page 602: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

Sartre, Jean-Paul (philosopher) 2nd save( ) method, Comment class saveOrUpdate( ) method savepoints 2nd scrollable result set, in JDBC SCSI disks searches BMP Castor EJB 1.x CMP EJB 2.x CMP Hibernate JavaBeans not supporting JDO data store 2nd JNDI objects RMI not supporting SearchResult class (JNDI) second normal form (2NF) security JavaBeans not supporting network segmentation and RMI not supporting seeds, for sequence generation segmentation [See network segmentation]SELECT statement (SQL) 2nd selector methods, EJB 2.x CMP sensitivity of network segment seqhilo.long algorithm (Hibernate) SEQUENCE algorithm (Castor) sequence algorithm (Hibernate) sequence generation Castor for Guest Book application Hibernate

Page 603: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Serializable interface (RMI) serializable transactions, isolation level serialization persistence model serialization, object Server Provider Interface for JNDI [See SPI for JNDI]server provider, EJB server, fat session beans 2nd 3rd SessionBean class SessionFactory class setOrdering( ) method (JDO) setter methods for CMR fields in JavaBeans in PreparedStatement interface setTransactionIsolation( ) method seventh normal form (DKNF) simple applications simple value objects SMALLINT datatype (SQL) SoftReference object software architecture 2nd SPI (Server Provider Interface) for JNDI SQL (Structured Query Language) batch processing for creating database w ith creating indexes creating tables data types deleting database w ith deleting rows functions history of inserting rows in tables interactive tools for joins operators queries 2nd 3rd 4th 5th standards for

Page 604: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

syntax for updating rows in tables SQLException 2nd 3rd SQRT( ) function (SQL) state management, BMP state of application, saving to database [See persistence]Statement interface (JDBC) 2nd 3rd 4th 5th static content, in JSP page static view, software architecture stored procedures 2nd 3rd storeFile( ) method strong references Structured Query Language [See SQL]subtraction (-), SQL Supports transactional attribute supportsTransactionIsolationLevel( ) method supportsTransactions( ) method Sw ing (Java) 2nd symbols in ERDs JDO filters JNDI search filters JSP code tags 2nd SQL operators system administrator system architecture 2nd system data, disk assignments for

[ Team LiB ]

Page 605: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

tables creating in SQL deleting rows, in SQL disk assignments for indexes for, in SQL inserting rows, w ith SQL joining, in SQL 2nd lookup tables querying, in SQL updating rows, in SQL tags, in JSP page 2nd TagSupport class (JSP) The Critique of Pure Reason (Kant) third normal form (3NF) 2nd timestamp, used in optimistic concurrency TINYINT datatype (SQL) Tractatus Logico Philosphicus (Wittgenstein) Transaction class (JDO) transaction log, database TRANSACTION_NONE constant TRANSACTION_READ_COMMITTED constant TRANSACTION_READ_UNCOMMITTED constant TRANSACTION_REPEATABLE_READ constant TRANSACTION_SERIALIZABLE constant TransactionAbortedException transactions auto-commit 2nd batch BMP 2nd BMP w ith JDO concurrent corresponding to use cases designing distributed 2nd

Page 606: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

EJB CMP 2nd history of isolation levels for JavaBeans not supporting JDBC 2nd 3rd JDO 2nd locking log file for optimistic 2nd paradigms properties of RMI not supporting rolling back 2nd savepoints 2nd stored procedures two-phase commits transitive dependencies transparency of persistence models Truth and Existence (Sartre) tuples [See rows]two-phase commits two-tier architecture [See client/server architecture]typographical conventions used in this book

[ Team LiB ]

Page 607: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

UI (user interface) patterns view logic for UI (user interface) layer, distributed architectures unary operators, in SQL UnicastRemoteObject class (RMI) unique index 2nd unknown value [See NULL]unmarshaling update anomalies 2nd UPDATE statement (SQL) 2nd URL for JDBC database connection 2nd use cases, corresponding to transactions user actions, control logic for User class (JNDI) user interface [See UI]UserFactory class (JNDI) UUID algorithm (Castor) uuid.hex algorithm (Hibernate) uuid.string algorithm (Hibernate)

[ Team LiB ]

Page 608: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

value objects 2nd VARCHAR datatype (SQL) VARCHAR2 datatype (SQL) view logic as part of application logic for Guest Book application Vlissides, John (Design Patterns) vm.hex algorithm (Hibernate) vm.long algorithm (Hibernate)

[ Team LiB ]

Page 609: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

wasNull( ) method (JDBC) web applications EJB for JDBC for JDO for MVC pattern used for web pages, generating dynamically [See JSP]web services layer, distributed architectures web site architecture web sites Castor for this book Guest Book application Hibernate JDBC drivers JDO reference implementation 2nd JNDI service providers O'Reilly & Associates, Inc. WHERE clause (SQL) 2nd w ildcard (*), JNDI search filter W ittgenstein, Ludwig (philosopher) 2nd WORA (Write Once, Run Anywhere) Write Once, Run Anywhere [See WORA]

[ Team LiB ]

Page 610: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

[ Team LiB ][SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O][P] [Q] [R] [S] [T] [U] [V] [W] [X]

X/OPEN SQL, CLI (Call Level Interface) XHTML, generating dynamically [See JSP]XML Castor field mapping EJB CMP field mapping generating dynamically [See JSP] Hibernate field mapping JDO metadata descriptions JNDI data source configuration JSP class mappings in

[ Team LiB ]

Page 611: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 612: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Brought to You by

Page 613: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different
Page 614: O'Reilly : Java Database Best Practices - doc.lagout.org Database Best... · focus on a single way to do things, Java Database Best Practices takes you through a wide variety of different

Like the book? Buy it!