Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
Web Applications Engineering:Database Access and Object-Relational Mapping
Service Oriented Computing Group, CSE, UNSW
Week 5
References used for the Hibernate Notes:
(Hibernate) Hibernate In Action, Christian Bauer and Gavin King, Manning Publications
(HibernateDOC) http://www.hibernate.org/hib docs/reference/en/html/
Acknowledgement: Some examples are originated from Dr. David Edmond from School of Information Systems, QUT, Brisbane.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 1 / 1
Data is Everywhere
Wal-Mart - 1 mil. transactions an hour - 2.5 PB
Facebook - 40 billion photos
Sloan Digital Sky Survey - 140 TB in 10 years
How do we store and access this data over the web ?
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 2 / 1
Case 1: E-Commerce website
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 3 / 1
Case 1: E-Commerce website
Data operations are mainly transactions (Reads and Writes)
ACID (Atomicity, Consistency, Isolation, Durability) properties areimportant
Operations are mostly on-line
Response time should be quick but important to maintain securityand reliability of transactions
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 4 / 1
Case 2: Image serving website
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 5 / 1
Case 2: Image serving website
Data operations are mainly fetching large files (Reads)
ACID requirements can be relaxed
Operations are mainly on-line
High bandwidth requirement
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 6 / 1
Case 3: Search website
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 7 / 1
Case 3: Search website
Data operations are mainly reading index files for answering queries(Reads)
ACID requirements can be relaxed
Index compilation is performed off-line due to the large size of sourcedata (the entire Web)
Response times must be as fast as possible.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 8 / 1
Persistence
(Hibernate, pp.5-29)
Persistence is a fundamental concept in application development.
In an object-oriented applications, persistence allows an object tooutlive the process that created it
The state of the object may be stored to disk and an object with thesame state re-created at some point in the future
Sometimes entire graphs of interconnected objects may be madepersistent and later re-created in a new process
Not all objects are persistent - some (transient objects) will have alimited lifetime that is bounded by the life of the process thatinstantiated it
Almost all Java applications contain a mix of persistent and transientobjects
This means we need a subsystem that manages our persistent objects
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 9 / 1
Data Persistence
(Hibernate, pp.5-29)
When we talk about persistence in Java, we normally mean storingdata in a relational database using SQL
Relational technology is a common denominator for many disparatesystems and technology platforms.
I Relational technology provides a way of sharing data across differentapplications or technologies that form part of the same application
The relational data model is often the common enterprise widepresentation of business entities
When you work with a relational database in a Java application, theJava code issues SQL statements to the database via the JDBC API.The SQL itself will be embedded in the Java code, or generated onthe fly by Java code.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 10 / 1
Relational Databases
Data is stored as a collection of tuples that groups attributes e.g.(student-id, name, birthdate, courses)
Data is visualized as tables where the tuples are the rows and theattributes form the columns
Tables can be related to each other through specific columns.
Each row in a table has at least one unique attribute.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 11 / 1
Structured Query Language (SQL)
Is a means to query and manipulate data stored in relationaldatabases.
Is a declarative language in which operations are expressed instatements close to English language.e.g. SELECT * FROM students WHERE marks = 50;
Common SQL commands:I SELECT: Get specific rows from the database based on certain
conditionsSELECT * FROM employees WHERE salary > 100000;
I INSERT: Adds rows to a databaseINSERT INTO characters (name,diet,sound) VALUES
(‘zombies’,‘brains‘,‘graagh’), (‘pirates’,‘rum’,‘Arr’);I UPDATE: Update values in a database depending on certain conditions
UPDATE students SET status = ’pass’ WHERE marks > 50;I DELETE: Remove rows based on certain conditions
DELETE FROM characters WHERE diet = ’rum’;
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 12 / 1
Database Concepts
Joins
A join combines rows from two or more tables.
Is a means to traverse the database and create virtual tables on thefly e.g. SELECT * from student, subject WHERE
student.subject id = subject.id AND student.status =
’fail’;
Transactions
A transaction is a group of SQL statements that have to be executedtogether or not at all.
If one of the statements in a transaction fails, then the effects of anyprevious statements in the transaction have to be rolled back
When the statements are carried out successfully and the database ischanged, a COMMIT is said to have occurred
Examples: Updating a bank account.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 13 / 1
Other Kinds of Updates
Creating stored procedures or tables is also considered an update.
Statement stmt = conn.createStatement();
stmt.executeUpdate("DROP TABLE nice names");
stmt.executeUpdate("CREATE OR REPLACE FUNCTION " +
"pretty print names(a first IN VARCHAR2, a last IN VARCHAR2) " +
"RETURN VARCHAR2 AS BEGIN RETURN a last || ’, ’ || a first;
END;");
stmt.executeUpdate("CREATE TABLE nice names AS (" +
"SELECT pretty print names(first name, last name)
name FROM employee)");
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 14 / 1
Accessing DB from an Application
JDBC (Java Database Connectivity) API:
JDBC is a package (java.sql.*) of Java classes that provides access toRDBS (Oracle, PostgreSQL, etc.) via SQL.
JDBC offers simplicity (easy to use) and database independenceI Developers do not need to worry about differences in vendor-specific
database connection instructions
A vendor would have to produce JDBC drivers and build theirproprietary connection management code beneath a common JavaAPI
A JDBC driver is a segment of code designed to enable access to aparticular kind of database.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 15 / 1
Java DataBase Connectivity
import java.sql.*class UseDataBase {......}
Java Code to Access Database
JDBC
OracleDriver
MySQLDriver
MS AccessDriver
Oracle MySQL Access
Java Virtual Machine
SQL QueryResult
Java classes in the JDBC package (java.sql.*) are interfaces
RDBMS vendors implements the interfaces to fit with their ownproducts
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 16 / 1
JDBC Concepts (Barish, p.310)
When developers use JDBC, they construct SQL statements that can beexecuted. A template like query string:
SELECT name FROM employee WHERE age = ?
can be combined with local data structures so that regular Java objectscan be mapped to the bindings in the string (denoted ?). E.g., ajava.lang.Integer object with the value of 42 can be mapped:
SELECT name FROM employee WHERE age = 42
The results of execution, if any, are combined in a set returned to thecaller. For example, the query may return:
Name
--------
Angela
Andrew
Peter
We can browse this result set as necessary.H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 17 / 1
JDBC Interfaces
�•� java.sql.Statement
Represents a SQL statement (select or update) to be sent to DBMS
A statement is sent to DBMS via execute method
Related methods:I Execution: execute, executeQuery, executeUpdateI Creation: Connection.createStatement
�•� java.sql.ResultSet
Hold the result of executing an SQL query (i.e., the result relation)
Handles access both to rows and columns within rows
Related methods:I Iteration: nextI Accessing Data: get{Type}(position|name)
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 18 / 1
Typical JDBC Scenario
1 Load JDBC driver for specific RDBMS (Driver class)
2 Get connection to a named database (Connection class)
3 Set up an SQL query (or update) (Statement class)
4 Execute the query to obtain results (ResultSet class)
5 Iterate over the results in the ResultSet
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 19 / 1
PreparedStatement object
Query processing generally comes down to three phases: query parsing(syntax checking), query plan generation and plan execution. The firstphase is costly, especially if we repeatedly execute the same query.
PreparedStatement object is compiled ahead of time (i.e., precompiled)and can be executed many times as needed. - as opposed to Statement
object which sends a SQL string to the database each time for parsing.
PreparedStatement ps = conn.prepareStatement("SELECT first name FROM employee");
ResultSet rset;
for (int i=0; i<1000; i++) {rset = ps.executeQuery();
/* ... do something more ... */
}
Statement stmt = conn.createStatement();
ResultSet rset;
for (int i=0; i<1000; i++) {rset = preStmt.executeQuery("SELECT first name FROM employee");
/* ... do something more ... */
}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 20 / 1
PreparedStatement object: Dynamic SQL)
A more realistic case is that the same kind of SQL statement is processedover and over (rather than a static SQL statement).
SELECT * FROM employee WHERE id = 3;
SELECT * FROM employee WHERE id = 7;
SELECT * FROM employee WHERE id = 25;
SELECT * FROM employee WHERE id = 21;
...
SELECT * FROM employee WHERE id = ?
In PreparedStatement, a place holder (?) will be bound to an incomingvalue before execution (no recompilation).
PreparedStatement ps = conn.prepareStatement("SELECT * FROM employee where id=?");
ResultSet rset;
for (int i=0; i<1000; i++) {ps.setInt(1,i);
rset = ps.executeQuery();
/* ... do something more ... */
}
This results in more efficient querying.H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 21 / 1
Transaction Management
By default, JDBC commits each update when you call executeUpdate().
Committing after each update can be suboptimal in terms of performance.It is also not suitable if you want to manage a series of operations as alogical single operation (i.e., transaction).
Class.forName(" ... // the driver
Connection conn = DriverManager.getConnection(" ... // the DB url
/* Do not commit each update immediately */
conn.setAutoCommit(false); // configuring connection
Now you could:
conn.setAutoCommit(false); // this marks START TRANSACTION
Statement stmt = conn.createStatement();
try {stmt.executeUpdate("UPDATE ACCOUNTS SET bal=bal - 100 WHERE id = 101");
stmt.executeUpdate("UPDATE ACCOUNTS SET bal=bal + 100 WHERE id = 102");
conn.commit();
} catch (Exception e) {conn.rollback();
}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 22 / 1
Delicious Baking Company Cars Database
Table Cars: Web application for Cars:
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 23 / 1
Data Access Objects (DAO)
JDBC (either via DriverManager or DataSource) lets you access datastored in relational tables
Data access strategies often differ depending on the storagemechanism (eg., accessing relational tables is different from accessingXML files).
DAO pattern provides abstract interface to the retrieval of data froma data resource.
Its aim is to provide a uniform access interface for persistent storages.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 24 / 1
Data Access Objects (DAO)
Advantages:
Changes to persistence access layer do not affect DAO clients as longas the interface remains correctly implemented.
DAO is used to insulate an application from the numerous, complexand varied Java persistence technologies (e.g., JDBC, EJB CMP,TopLink, Hibernate or iBATIS)
Using Data Access Objects means the underlying technology can beupgraded or swapped without changing other parts of the application.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 25 / 1
Delicious Baking Company Cars Database
Table Cars: Web application for Cars:
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 26 / 1
Data Access Objects (DAO) implementation for Cars table
A typical Data Access Object interface is shown below.
Cars----------------------------------- CarNr Make Cost ----------------------------------- YPZ400 Ford 50 YPZ412 Ford 80 YPZ600 Mazda 80 WPZ600 BMW 100 WPZ610 BMW 200 WPZ620 BMW 250 PPZ410 Benz 250 PPZ420 Benz 350 PPZ430 Ford 150 YPZ420 Honda 150 ------------------------------------
CarDTO
carnrmakecost
<<interface>>CarDAO
List findAll()
CarDAOImpl.
List findAll() { JDBC connect select * from cars create CarDTOs return CarDTO list} - Client Code -
CarDAO.findAll()Loop
display individual CarDTO
// plus Setter and Getter methods forthese properties
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 27 / 1
Data Access Objects (DAO) implementation for Cars table
DTO (Data Transfer Object) carries the actual data ...
CarDTO.javapackage com.enterprise.dto;
public class CarDTO {private String carnr;private String make;private String cost;
public CarDTO() {this.carnr = "";this.make = "";this.cost = "";
}public CarDTO(String carnr, String make, String cost) {
this.carnr = carnr;this.make = make;this.cost = cost;
}public String getCarnr() { return carnr; }public void setCarnr(String carnr) { this.carnr = carnr; }public String getMake() { return make; }public void setMake(String make) { this.make = make; }// rest of the get/set methods snipped ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 28 / 1
Data Access Objects (DAO) implementation for Cars table
DAO Interface defines possible access to the data source (from client’sview point)
CarDAO.javapackage com.enterprise.dao;
import java.util.*;
public interface CarDAO
{public List findAll();
}
Of course, you can define more methods here ... e.g., updating Cars, inserting Cars, etc.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 29 / 1
Data Access Objects (DAO) implementation for Cars table
DAO implementation for JDBC ...
JDBCCarDAO.java - showing important bits onlyimport com.enterprise.dto.CarDTO;import com.enterprise.util.DBUtils;import com.enterprise.util.ServiceLocatorException;
public class JDBCCarDAO implements CarDAO {private List carList;
public List findAll() {List carList = new ArrayList();
DBUtils services = DBUtils.getInstance();Connection conn = services.getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("select * from cars");
while(rs.next()) {CarDTO car = new CarDTO();car.setCarnr(rs.getString("CarNr"));car.setMake(rs.getString("Make"));car.setCost(rs.getInt("Cost"));carList.add(car);
}return carList;
}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 30 / 1
Data Access Objects (DAO) implementation for Cars table
DAO client ... (first in a servlet called ControllerServlet)
ControllerServletjava - showing important bits onlyimport com.enterprise.dto.*;import com.enterprise.dao.*;
public class ControllerServlet extends HttpServlet {private static final String ACTION_KEY = "action";private static final String VIEW_CAR_LIST_ACTION = "viewCarList";
// doGet and doPost calls processRequest(request, response)
protected void processRequest(HttpServletRequest request ... {String actionName = request.getParameter(ACTION_KEY);String destinationPage = ERROR_PAGE;
if(VIEW_CAR_LIST_ACTION.equals(actionName)) {CarDAO carDAO = new JDBCCarDAO();request.setAttribute("carList", carDAO.findAll());
destinationPage = "/carList.jsp";}// snipped ...
// Redirect to destination page.RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(destinationPage);
dispatcher.forward(request, response);}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 31 / 1
Data Access Objects (DAO) implementation for Cars table
Displaying carList attribute in a JSP:
carList.jsp<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html><head>
<link rel="stylesheet" type="text/css" href="default.css"></head><body><table><tr><th>CarNr</th><th>Make</th><th>Cost</th></tr>
<c:forEach items=’${carList}’ var=’car’><tr><td>${car.carnr}</td>
<td>${car.make}</td><td>${car.cost}</td>
</tr></c:forEach>
</table></body></html>
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 32 / 1
Object-Relational Impedance Mismatch Problems
For the objects to persists, we need to convert the object values into thevalues that can be stored in the relational tables (and convert them backupon retrieval), while preserving the properties of the objects and theirrelationships.
This means, for example, to go from sql.ResultSet of Cars to CarDTO
objects, we do: car.setMake(resultSet.getString("name")) at atime!
What we want is, probably:
Car car = new Car();
MagicDataSouce ds = MasicDataSource.getInstance();
ds.save(car);
Instead of something like:
Insert into Cars
values (car.getName(), car.getMake, car.getCost());
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 33 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) Consider the following example:
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 34 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of granularity
We want to create a separate Address class as other classes in the systemmay also carry address information.
How would this be represented in relational relational tables?
Should we add an Address table?
Should we add Address columns to User table instead?
Should the address be single String? or multiple columns (street,suburb, postcode, etc.)
Should we great a custom SQL data type to represent addresses anduse it in User table?
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 35 / 1
Impedance (or Paradigm) Mismatch Problem
The most common representation of the given User - Address scenario is:
create table User (
username varchar(15) not null primary key,
name varchar(50) not null,
address street varchar(50),
address city varchar(15),
address state varchar(15),
address postcode varchar(5),
address country varchar(15)
)
Observation:
Classes in your OO-based model come in a range of different levels ofgranularity (coarse-grained entity classes like User, finer-grainedclasses like Address, simple String class like Postcode)
Just two levels of granularity in RDB: Tables and Columns with scalartypes (i.e., not as flexible as Java type system)
Sometimes one ends up forcing the less flexible representation uponthe object model (e.g., User class with properties like postcode, state).
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 36 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of subtypes
We want to create an abstract BillingDetails superclass with severalconcrete classes: CreditCard, DirectDebit, Cheque and so on.
Each of these subclasses will define slightly define data and completelydifferent functionality that acts upon the data.
SQL has no direct support for inheritance ... There are at least three waysto represent the above in tables.H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 37 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of identity
In Java, objects can either be equal or identical.
objectA == objectB;
is different from
objectA.equals(objectB)
identical - same object
equal - same values
In RDB, these two different notions of identity do not exist. The onlyidentity of a database row is expressed as primary key values.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 38 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of identity
While on the subject of identity ... Modern object persistence solutionsrecommend using surrogate keys.
To have something like the USERNAME column as a primary key - (i)difficult to change a username, (ii) not only need to update username inthe User table, but also the foreign keys in Billing Details.
A surrogate key is a primary key column with no meaning to the user. It isnormally system generated values and introduced purely for the benefit ofthe relational data model.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 39 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of associations
User, Address and BillingDetails classes are associated (different kindof associations - represented differently in tables)
Association mapping and the management of the entity associationsare central concept of any object persistence solution.
OO languages represent associations using object references andcollections of object references
Object references are directional; the association is from one object toanother. To be able to navigate ’between’ objects, one needs to define theassociation twice.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 40 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of associations
In RDB, directional association or navigation have less meaning, becauseyou can create arbitrary data associations with joins and projection.
Also, many-to-many associations are possible in Java classes.
Tables associations on the other hand, are always one-to-many orone-to-one. Normally many-to-many associations are represented byintroducing a link table which does not appear anywhere in the objectmodel.
create table user billling details (
user id number foreign key references user,
billing details id number foreign key references billing details,
primary key (user id, billing details id)
)
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 41 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of object graph navigationIn Java, you access objects, so walking through objects likeaUser.getBillingDetails().getAccountNumber() is perfectly natural.
That is, from a user, you access the billing information, from that, youaccess the account number.
However, this is not an efficient way to retrieve data from relational tables.
Every database access is considered I/O cost. The single mostimportant thing to do to improve performance of data access code isto minimise the number of requests to the database
The most obvious way is to utilise joins between the tables ofinterests. The number of tables included in the join determines thedepth of the object graph you can navigate.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 42 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The problem of object graph navigation
To retrieve a User and aren’t interested in BillingDetails, we do:
select * from USER u where u.USER ID = 123
On the other hand, if we need to retrieve the same User and thensubsequently visit each of the associated BillingDetails instances, we use adifferent query:
select *
from USER u, BILLING DETAILS bd
where u.USER ID = bd.USER ID
and u.USER ID = 123
That is, we need to know what portion of the object graph we plan toaccess when we retrieve the initial User, before we start navigating theobject graph.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 43 / 1
Impedance (or Paradigm) Mismatch Problem
1+N selects problem: An object persistence solution/framework likeEJB (old version) will provide you with the functionality for fetching theassociated objects only when they are first accessed. The implementationof this wasn’t so smart !!
For example, to access 1000 line items in an order, the framework willissue 1000 select queries to create 1000 line items plus one for the order.
class Order {private LineItem [n] lineItem;
}
This is crazy as all the data required is stored in (probably) on two tables.Issuing one single query joining the tables and looping through to populateline items is more straight-forward approach in this case.
Modern object persistence solution framework (like Hibernate) seems toprovide a better solution for this.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 44 / 1
Impedance (or Paradigm) Mismatch Problem
(Hibernate, pp.5-29) The cost of mismatch problems
You could resolve the mismatch problems manually through properdesign of database access code through JDBC API.
One of the major costs is in the area of modelling. The relational andobject models both see the same business entities. But an OO puristwill model these entities a very different way than an experiencedrelational data modeler.
The usual solution to this is usually twist and bend the object modeluntil it matches the underlying relational technology – losing some ofthe advantages of object orientation.
The DAO pattern helps isolate the mismatch problems by separating theinterfaces from implementation, but someone (usually applicationdevelopers) still has to provide the implementation classes !!
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 45 / 1
Object-Relational Mapping (ORM)
ORM aims to give you automated (and transparent) persistence of objectsin Java application to the tables in a relational database, using metadatathat describes the mapping between the objects and the database.
There are *many* tools/frameworks in this area.
JDO (Java Data Objects): http://db.apache.org/jdo/impls.html
JPA (Java Persistence API):http://java.sun.com/developer/technicalArticles/J2EE/jpa/
iBATIS: http://ibatis.apache.org/
Hibernate: http://www.hibernate.org/
ORM tools are relatively new in the market. the related specifications aremoving quickly. Hibernate is fast becoming very popular ... (e.g., JBoss4.x has built-in Hibernate support already).
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 46 / 1
Hibernate
This is how you retrieved Car objects using JDBC:
JDBCCarDAO.javaimport com.enterprise.dto.CarDTO;import com.enterprise.util.DBUtils;import com.enterprise.util.ServiceLocatorException;
public class JDBCCarDAO implements CarDAO {private List carList;
public List findAll() {List carList = new ArrayList();
DBUtils services = DBUtils.getInstance();Connection conn = services.getConnection();Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("select * from cars");
while(rs.next()) {CarDTO car = new CarDTO();car.setCarnr(rs.getString("CarNr"));car.setMake(rs.getString("Make"));car.setCost(rs.getInt("Cost"));carList.add(car);
}return carList;
}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 47 / 1
Hibernate
This is how you would retrieve Car objects using Hibernate
HibernateCarDAO.java - showing important bits onlypublic class HibernateCarDAO implements CarDAO {
public List findAll() {List carList = new ArrayList();Session session = null;session = ServiceLocator.getHibernateSession(HIBERNATE_SESSION_FACTORY);Criteria criteria = session.createCriteria(CarDTO.class);carList = criteria.list();return carList;
}}
We replace JDBCCarDAO with HibernateCarDAO in the servlet and willget the same result.
in ControllerServlet.java
if(VIEW_CAR_LIST_ACTION.equals(actionName)) {CarDAO carDAO = new HibernateCarDAO();request.setAttribute("carList", carDAO.findAll());
destinationPage = "/carList.jsp";}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 48 / 1
Hibernate
This is how you would retrieve Car objects using Hibernate
HibernateCarDAO.java - showing important bits onlypublic class HibernateCarDAO implements CarDAO {
public List findAll() {List carList = new ArrayList();Session session = null;session = ServiceLocator.getHibernateSession(HIBERNATE_SESSION_FACTORY);Criteria criteria = session.createCriteria(CarDTO.class);carList = criteria.list();return carList;
}}
Session object is something like a DB connection
The Criteria object does something like “select * from cars”.
ResultSet row unpacking/packing still happens, but the HibernateAPI takes care of it behind the scenes.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 49 / 1
Continuing with the Cars example ...
To add a Car:
In ControllerServlet.javaelse if(ADD_CAR_ACTION.equals(actionName)) {
request.setAttribute("car", new CarDTO());
destinationPage = "/carForm.jsp";
} else if(SAVE_CAR_ACTION.equals(actionName)) {//build the car from the request parameters
CarDTO car = new CarDTO();
car.setMake(request.getParameter("make"));
car.setModel(request.getParameter("model"));
car.setModelYear(request.getParameter("modelYear"));
//save the car
CarDAO carDAO = new HibernateCarDAO(); //or JDBCCarDAO() !
carDAO.create(car);
//prepare the list
request.setAttribute("carList", carDAO.findAll());
destinationPage = "/carList.jsp";
... snip ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 50 / 1
Continuing with the Cars example ...
To add a Car (with JDBC):
In JDBCCarDAO.javapublic void create(CarDTO car) {
DataSource dataSource = null;
Connection conn = null;
PreparedStatement pstmt = null;
String insertSql = "insert into CAR(CARNR, MAKE, COST) values(?,?,?)";
try {dataSource = ServiceLocator.getDataSource(DATA_SOURCE);
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(insertSql);
pstmt.setString(1, car.getCarnr());
pstmt.setString(2, car.getMake());
pstmt.setInteger(3, car.getCost());
pstmt.executeUpdate();
}... snip ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 51 / 1
Continuing with the Cars example ...
To add a Car (with Hibernate):
In HibernateCarDAO.java
public void create(CarDTO car) {Session session = null;
try {session = ServiceLocator.getHibernateSession(HIBERNATE_SESSION_FACTORY);
session.save(car);
}
// catch blocks snipped ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 52 / 1
Continuing with the Cars example ...
To delete a Car:
In ControllerServlet.javaelse if(DELETE_CAR_ACTION.equals(actionName)) {
//get list of ids to delete
String[] ids = request.getParameterValues("id");
//delete the list of ids
CarDAO carDAO = new HibernateCarDAO();
if(ids != null) {carDAO.delete(ids);
}
//prepare the list
request.setAttribute("carList", carDAO.findAll());
destinationPage = "/carList.jsp";
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 53 / 1
Continuing with the Cars example ...
To delete a Car (with JDBC):
In JDBCCarDAO.javapublic void delete(String[] ids) {
// some variable declarations ...
String sql = "delete from CAR where id in(";
try {dataSource = ServiceLocator.getDataSource(DATA_SOURCE);
conn = dataSource.getConnection();
stmt = conn.createStatement();
StringBuffer idList = new StringBuffer();
for(int i = 0; i < ids.length; i++) {idList.append(ids[i]);
if(i < (ids.length - 1)) {idList.append(",");
}}stmt.executeUpdate(sql + idList.toString() + ")");
}// catch blocks snipped ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 54 / 1
Continuing with the Cars example ...
To delete a Car (with Hibernate):
In HibernateCarDAO.javapublic void delete(String[] ids) {
Session session = null;
try {session = ServiceLocator.getHibernateSession(HIBERNATE_SESSION_FACTORY);
for(int i=0; i < ids.length; i++) {CarDTO car =
(CarDTO) session.get(CarDTO.class, new Integer(ids[i]));
session.delete(car);
}}
// catch blocks snipped ...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 55 / 1
To use Hibernate, you need:
Database
JDBC
HibernateMappings Configuration
Client Code
Java Objects
Hibernate packages (hibernate*.jar)
A set of mapping (between a table and an object) files
A Hibernate configuration file (e.g., database connection details)
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 56 / 1
Hello World of Hibernate
(Hibernate pp.31-36)
Assume a POJO (Plain Old Java Object) called Message:
Message.javapackage hello;
public class Message {private Long id;
private String text;
private Message nextMessage;
// getter and setter methods ...
}
the identifier attribute allows the application to access the databaseidentity - primary key - of the persistent object. If two instances ofMessage have the same identifier value, they represent the same rowin the database.
nextMessage is a reference to another Message
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 57 / 1
Hello World of Hibernate
To create a new Message and save to the database:
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Message message = new Message("Hello World");
session.save(message);
tx.commit();
session.close();
Hibernate then creates:
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (1, ’Hello World’, null)
Note the message id is automatically generated.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 58 / 1
Hello World of Hibernate
To create a new Message and save to the database:
Session newSession = getSessionFactory().openSession();
Transaction newTransaction = newSession.beginTransaction();
List messages =
newSession.find("from Message as m order by m.text asc");
System.out.println( messages.size() + " message(s) found:" );
for ( Iterator iter = messages.iterator(); iter.hasNext(); )
Message message = (Message) iter.next();
System.out.println( message.getText() );
newTransaction.commit();
newSession.close();
Hibernate then creates:
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
order by m.MESSAGE_TEXT asc
The code fragment prints
1 message(s) found:
Hello World
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 59 / 1
Hello World of HibernateHibernate needs to know how Message maps to a table.
<?xml version="1.0"?>
<hibernate-mapping>
<class
name="hello.Message"
table="MESSAGES">
<id
name="id"
column="MESSAGE_ID">
<generator class="native"/>
</id>
<property
name="text"
column="MESSAGE_TEXT"/>
<many-to-one
name="nextMessage"
cascade="all"
column="NEXT_MESSAGE_ID"
foreign-key="FK_NEXT_MESSAGE"/>
</class>
</hibernate-mapping>
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 60 / 1
Hello World of Hibernate
Updating a message:
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
// 1 is the generated id of the first message
Message message =
(Message) session.load( Message.class, new Long(1) );
message.setText("Greetings Earthling");
Message nextMessage = new Message("Take me to your leader (please)");
message.setNextMessage( nextMessage );
tx.commit();
session.close();
This generates:select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
from MESSAGES m
where m.MESSAGE_ID = 1
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
values (2, ’Take me to your leader (please)’, null)
update MESSAGES
set MESSAGE_TEXT = ’Greetings Earthling’, NEXT_MESSAGE_ID = 2
where MESSAGE_ID = 1
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 61 / 1
Hello World of HibernateIf we run ”Hello World” again, it prints:
2 message(s) found:
Greetings Earthling
Take me to your leader (please)
Observations:
automatic dirty checking: When we modify the state of an objectinside a transaction, Hibernate automatically update the database(you don’t have to do it yourself explicitly).
cascading save: You can see that the new message was madepersistent when a reference was created from the first mes- sage. Aslong as new object is reachable by already persistent instance, you donot have to explicitly call save()
transactional write-behind: Notice that the ordering of the SQLstatements is not same as the order in which we set property values.Hibernate determines an efficient ordering that avoids databaseforeign key con- straint violations
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 62 / 1
Hello World of Hibernate
Here is an Hibernate configuration file:
hibernate.cfg.xml<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="hibernate.connection.username">sa</property>
<!-- other properties -->
<!-- SQL to stdout logging
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="use_sql_comments">true</property>
-->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<mapping resource="hello/Message.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate “understands” over 20 database dialects (all the major ones!).Hibernate will generate SQL statements specific to the chosen dialect.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 63 / 1
Hibernate Sessions
Database
JDBC
Client Code
SessionSessionSession
SessionFactory
Database
Client Code
SessionSessionJDBC connection
ConnectionPool
Hibernate JDBC
The Session object is used to create new, read in, update and deleteobjects from database (obtained from SessionFactory)
It lets you manage the transaction boundaries of database accesstry {
session.beginTransaction();
// normal database access here ...
session.getTransaction().commit();
} catch (HibernateException e) {Transaction tx = session.getTransaction();
if (tx.isActive()) tx.rollback();
....
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 64 / 1
Mapping - primary key
Hibernate needs a ’good’ primary key: Hibernate is going to representJava objects. Objects are always uniquely identifiable. In RDB-sense,identical objects means ’the same primary key’.
It is better to identify an id (surrogate key) for a table, rather than usingnatural primary key.
Cars----------------------------------- CarNr Make Cost ----------------------------------- YPZ400 Ford 50 YPZ412 Ford 80 YPZ600 Mazda 80 WPZ600 BMW 100 WPZ610 BMW 200 WPZ620 BMW 250 PPZ410 Benz 250 PPZ420 Benz 350 PPZ430 Ford 150 YPZ420 Honda 150 ------------------------------------
CarDTO---------
idcarnrmakecost
<hibernate-mapping> <class name="com.enterprise.dto.CarDTO" table="Cars"> <id name="id" column="id" type="int"> <generator class="native"/> </id> <property name="carnr" type="string" column="CarNr"/> <property name="make" type="string" column="Make"/> <property name="cost" type="integer" column="Make"/> </class></hibernate-mapping>
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 65 / 1
Mapping - components
The User class has a special kind of association (aggregation (part-of))with the Address class. We represented this in one User table.
Hibernate uses the term component for a user-defined class that ispersistent to the same table as the owning entity.
<class name="User" table="USER"
<id name="id" column="USER ID" type="long">
<generator class="native"/>
</id>
<property name="username" column="USERNAME" type="string"/>
<component name="homeAddress" class="Address:>
<property name="street" type="string" column="HOME STREET"/>
<property name="city" type="string" column="HOME CITY"/>
<property name="postcode" type="string" column="HOME POSTCODE"/>
</component>
...
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 66 / 1
Mapping - class inheritance
owner:Stringnumber:Stringcreated:Date
BillingDetails
type:intexpMonth: StringexpYear: String
CreditCardbankName: StringbankSwift: String
BankAccount
Table per concrete class:
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 67 / 1
Mapping - class inheritance
Table per class hierarchy:
<class name="BillingDetails" table="BILLING DETAILS" discriminator-value="BD">
<id name="id" column="BILLING DETAILS ID" type="long">
<generator class="native"/>
</id>
<discriminator column="BILLING DETAILS TYPE" type="string"/>
<property name="name" column="OWNER" type="string" />
...
<subclass name="CreditCard" discriminator-value="CC">
<property name="type" column="CREDIT CARD TYPE"/> // more properties
</subclass>
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 68 / 1
Mapping - class inheritance
Table per subclass:
Use ’joined-subclass’ element to indicate a table-per-subclass mapping.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 69 / 1
Mapping - associations
+Name: String+Manager: String
Department+CarNr: String+Make: String+Cost: int
Car
??
Q1: Can a car belong to more than one department?
Q2: Can a department have more than one car?
Q1 Q2 Relationship Between Depts and CarsNo No one-to-one
Yes No one-to-many
No Yes many-to-one
Yes Yes many-to-many
Each relationship can be represented within the tables in various ways!
http://www.hibernate.org/hib_docs/reference/en/html/associations.html
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 70 / 1
Collection Mapping (HibernateDOC)
http://www.hibernate.org/hib_docs/reference/en/html/collections.html
Hibernate Collection elements are used if you want to include an attributein your class that represent any of the collection classes (e.g., List or Set).
A class with a Set as an attributepackage eg;
import java.util.Set;
public class Parent {private long id;
private Set children;
public long getId() { return id; }private void setId(long id) { this.id=id; }
private Set getChildren() { return children; }private void setChildren(Set children) { this.children=children; }
}
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 71 / 1
Collection Mapping (HibernateDOC)
If each child has at most one parent,the most natural mapping is aone-to-many association:
<hibernate-mapping>
<class name="Parent">
<id name="id">
<generator class="native"/>
</id>
<set name="children">
<key column="parent id"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
</class>
</hibernate-mapping>
This maps to the following tabledefinitions (roughly):
create table parent (
id bigint not null primary key )
create table child (
id bigint not null primary key,
name varchar(255),
parent id bigint )
alter table child add constraint chfk0 (
parent id) references parent
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 72 / 1
Collection Mapping (HibernateDOC)
If the parent is required, use abidirectional one-to-manyassociation:
<hibernate-mapping>
<class name="Parent">
<id name="id">
<generator class="native"/>
</id>
<set name="children" inverse=”true”><key column="parent id"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="parent" class="Parent"
column="parent id" not-null="true"/>
</class>
</hibernate-mapping>
Notice the NOT NULL constraint:
create table parent (
id bigint not null primary key )
create table child (
id bigint not null
primary key,
name varchar(255),
parent id bigint not null )
alter table child add constraint chfk0 (
parent id) references parent
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 73 / 1
More on Parent/Child type relationship: most common
Start with a simple <one-to-many> association from Parent to Child
class Parent {String name;
Set children;
}class Child {
String name;
}
<class name="Parent">
<id name="id" column="parent_id"> ...
<set name="children">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child">
<id name="id"> ...
<property name="name" unique="true"/>
</class>
If we were to execute the following code:
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.getChildren().add(c);
session.save(c);
Hibernate would issue two SQL statements: an INSERT to create therecord for c, an UPDATE to create the link from p to cH. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 74 / 1
Dealing with a Parent/Child type relationship (HibernateDOC)
Running two SQL statements is not only inefficient, but also violates anyNOT NULL constraint on the parent id column. We can fix the nullabilityconstraint violation by specifying not-null=”true” in the collectionmapping:
<class name="Parent">
<id name="id" column="parent id"/>
...
<set name="children">
<key column="parent id" not-null="true"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child">
<id name="id"> ...
<property name="name" unique="true"/>
</class>
However, this is not the recommended solution (last update is redundant).
INSERT INTO Child (name, parent id, id) VALUES (?, ?, NULL)
UPDATE Child SET parent id=? WHERE id=?
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 75 / 1
Dealing with a Parent/Child type relationship (HibernateDOC)
The underlying cause of this behaviour is that the link (the foreign keyparent id) from p to c is not considered part of the state of the Childobject.
Therefore parent id is not created in the INSERT. The solution is to makethe link part of the Child mapping as well (bidirectional/inverse). Thischanges the model, adding an association from Child to Parent.
class Parent {String name;
Set children;
}
class Child {String name;
Parent parent;
}
(adding the parent property to theChild class.)
<class name="Parent">
<id name="id" column="parent id"/> ...
<set name="children" inverse="true">
<key column="parent id"/>
<one-to-many class="Child"/>
</set>
</class>
<class name="Child">
<id name="id"> ...
<property name="name" unique="true"/>
<many-to-one name="parent" column="parent id"
not-null="true"/>
</class>
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 76 / 1
Dealing with a Parent/Child type relationship (HibernateDOC)
Then, the following code would be used to add a new Child
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c);
session.save(c);
And now, only one SQL INSERT would be issued! To tighten things up abit, we could create an addChild() method of Parent.
public void addChild(Child c) {c.setParent(this);
children.add(c);
}
Now, the code to add a Child looks like
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.save(c);
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 77 / 1
Dealing with a Parent/Child type relationship (HibernateDOC)
Cascading: The explicit call to save() may still be annoying. We willaddress this by using cascades.
<class name="Parent">
...
<set name="children" inverse="true" cascade="all">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>
This simplifies the code above to
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c); // no session.save()
Similarly, we don’t need to iterate over the children when saving or deletinga Parent. The following removes p and all its children from the database.
Parent p = (Parent) session.load(Parent.class, pid);
session.delete(p);
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 78 / 1
When to use Hibernate
Although powerful, ORM tool is fundamentally limited by the underlyingdatabase schema.
Hibernate is good when you control the data model (e.g., building an OOapplication from scratch).
For legacy databases, Hibernate could be effective when the schema:
is highly normalised
has primary keys
has foreign key relationships referring to primary keys not columns
Hibernate is great when you control the data model, and you let Hibernatedo most of the work in the persisting of objects. Trying to add Hibernateto an existing data model is possible, just usually not trivial (unless yourmodel is trivial).
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 79 / 1
Problems with directly connecting to DB
Using JDBC directlystatic final String DB_DRIVER_CLASS = "org.hsqldb.jdbcDriver";
static final String DB_URL = "jdbc:hsqldb:/Users/hye-youngpaik/HSQLDB";
try {Class.forName(DB_DRIVER_CLASS); //Load the driver;
// connect to DB
Connection connection = DriverManager.getConnection(DB_URL);
} catch (SQLException se) {...
} catch ...
While the above program works well, there are a few of problems:
Every time you call getConnection()/close(), you incur overhead ofcreating/destroying a database connection
JDBC settings are hard-coded in your application
Transactions management (if needed) is left with you
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 80 / 1
Using DataSource managed by an Application Server
Using javax.sql.DataSource rather than java.sql.DriverManager.
Using DataSourceDataSource ds = null;
Connection conn = null;
try {ds = ServiceLocator.getDataSource("java:comp/env/jdbc/DefaultDS");
conn = ds.getConnection();
} catch (SQLException ex) {...
} catch (ServiceLocatorException e) {...
DataSource is managed by a database Connection Pool – created bythe App server at startup.
When you call getConnection(), you are getting a connection thatalready exists in the pool
Transaction can be managed by the container
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 81 / 1
JNDI Naming Convention
JNDI organises the names using a naming convention called EnvironmentalNaming Convention (ENC). It always begins with java:comp/env.
Resource type JNDI prefixEnvironment Variables java:comp/env/varURL java:comp/env/urlJavaMail Sessions java:comp/env/mailJMS Connection Factories and Destinations java:comp/env/jmsEJB Homes java:comp/env/ejbJDBC Datasources java:comp/env/jdbc
JNDI gives J2EE components a handle to back-end resources.
Since the component (e.g., servlet) uses a name (e.g., DefaultDS) insteadof an actual value (e.g., Hypersonic classes), you can swap back-endresources without changing the component source code.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 82 / 1
Using JNDI to get your datasource
JNDI Lookupimport javax.naming.*;
import javax.sql.*;
public class ServiceLocator {public static DataSource getDataSource(String dataSrcJndiName)
throws ServiceLocatorException {DataSource ds = null;
try {Context ctx = new InitialContext():
ds = (DataSource) ctx.lookup(dataSrcJndiName);
} catch // catch blocks snipped ...
return ds;
}
DataSource ds = ServiceLocator.getDataSource(”jndi name of datasource”);
All JNDI names/values are stored in the InitialContext. From the object, youcan call up a lookup() method.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 83 / 1
Using JNDI to get your datasource
How does the datasource name get into InitialContext in the first palce?
Inside web.xml:<web-app>
<servlet> ...<servlet-mapping> ...<resource-ref>
<res-ref-name>jdbc/DefaultDS</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth>
</resource-ref></web-app>
res-ref-name: JNDI resource name (java:comp/env is assumed)
res-type: fully qualified class name of the resource
res-auth: Container managed pooling.
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 84 / 1
BasicCars.java vs. BasicCarsJNDI.java
BasicCars.java: DriverManagerpublic class BasicCars extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) ... {Class.forName("org.hsqldb.jdbcDriver");Connection connection = DriverManager.getConnection("jdbc:hsqldb: ...
Statement statement = connection.createStatement();String query = "SELECT CarNr, Make, Cost FROM Cars";ResultSet resCar = statement.executeQuery(query);
BasicCarsJNDI.java: DataSourceimport com.enterprise.util.DBUtils;import com.enterprise.util.ServiceLocatorException;
public class BasicCarsJNDI extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response) ... {
DBUtils services = DBUtils.getInstance();Connection con = services.getConnection();
Statement statement = con.createStatement();String query = "SELECT CarNr, Make, Cost FROM Cars";ResultSet resCar = statement.executeQuery(query);
H. Paik, S. Venugopal (CSE, UNSW) COMP9321, 13s2 Week 5 85 / 1