Title: Persistence Layers In An Enterprise Application:
1Persistence Layers In An Enterprise Application
An Evolution From SQL to OJB to Hibernate
- Scott Delap, Amit Gollapudi, Scott GelbDemand
Management, Inc. - www.demandsolutions.com
2Imagine If Your Application
- Instantly supported all relational databases
- Wrote its own SQL
- Modified your database schema to support its
object model
3Presentation Goal
Explore the need for persistence layers and
identify their common features through practical
examples.
4Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
5Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
6The Beginning Entity Beans Are Painful
Early persistence options 2001
- EJBs were marketed as the better way
- Container Managed Persistence
- Bean Managed Persistence
7The Beginning Entity Beans Are Painful
BMP with DAOs and JDBC
- Each object/table had a Data Access Object (DAO)
- Each DAO used JDBC
- Multiple DAO implementations were often needed to
support multiple databases
8The Beginning Entity Beans Are Painful
Sample schema Scott/Tiger
9The Beginning Entity Beans Are Painful
Example DAO JDBC code
- String sqlString insert into emp(ename, mgr,
job) values (?, ?, ?) - PreparedStatement ps connection.prepareStatement
(sqlString) - ps.setString(1, e.getName())
- ps.setString(2, e.getJob())
- ps.setInt(3, e.getManager().getId)
- ps.executeUpdate()
10Id rather go to the dentist
Soon it was discovered that this repetitive
process was less fun than going to the dentist.
11Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
12Practical Persistence Layers
Why a persistence layer?
- Refocus on business logic
- Avoid monotonous SQL coding
- Support for multiple databases
- Object-oriented approach
- Relationships easily defined and maintained
13Practical Persistence Layers
Problem Generated IDs
- Database independence
- External processes inserting data
- Performance
- Clustering
14Practical Persistence Layers
Solution Generated IDs
- Native generation
- Sequence tables
- In-memory sequence
15Practical Persistence Layers
Problem Querying data
- Complex queries
- Aggregate functions
- Multiple table joins
- Arithmetic and string manipulation
- Null value handling
16Practical Persistence Layers
Solution Hand-written SQL
- Write SQL against persistence layernot database
- Reduces SQL changes if objects change
- Leverage persistence layer to handle SQL syntax
differences - Example coalesce() vs. nvl()
- Common rules still apply
- PreparedStatements
- StringBuffers
17Practical Persistence Layers
Problem Caching decisions
- Minimize database access
- Dirty caches
- Clustering
18Practical Persistence Layers
Solution Caching decisions
- No cache
- Local cache
- Distributed cache
- Cacheable object vs. non-cacheable (often
updated)
19Practical Persistence Layers
Problem Manual schema creation
- Complexity in supporting multiple databases
- Maintenance costs
20Practical Persistence Layers
Solution Automate it!
- Multiple database DDLs easy to maintain
- Object changes instantly reflected in the schema
- Saves time
- Reduces logic error
21Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
22OJB The Transition
Why OJB 2002?
- Mature
- Large user base
- Performance
- Most feature-rich API
- Strong project momentum
23OJB The Transition
Lines of code removed
- Greater than 90 for some DAOs
- Almost 20 (6000 lines) in one month
24OJB The Transition
Basic changes
- Domain object refactor
- Added foreign key ID fields
25OJB The Transition
Basic changes (cont.)
- DAOs simplified
- Several obsolete
- Database-dependent code removed
26OJB The Transition
Implementation choices
- PersistenceBroker API
- Flexibility
- Performance
- Database level transactions
- ODMG API
- Built on top of PersistenceBroker
- 3.0 compliant
- Object level transactions
27OJB The Transition
Example changes Before
- String sqlString insert into emp(ename, mgr,
job) values (?, ?, ?) - PreparedStatement ps connection.prepareStatement
(sqlString) - ps.setString(1, e.getName())
- ps.setString(2, e.getJob())
- ps.setInt(3, e.getManager().getId)
- ps.executeUpdate()
28OJB The Transition
Example changes After
- PersistenceBroker broker DSPersistenceBrokerFact
ory.createPersistenceBroker() - broker.store(e)
- --------------------------------------------------
----------- - ltclass-descriptor idemployee
- classjavaone.example.Employee
- tableEmployeegt
- ltfield-descriptor id1
- nameid columnid
- length38 jdbc-typeINTEGER
- java-typeint primarykeytrue/gt
- ltfield-descriptor id2
- namenamecolumnname
- jdbc-typeVARCHAR/gt
29Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
30Practical OJB
Generated IDs
- Store in database table
- Optimize GrabSize
- No nice native concept
- Synchronization with non-OJB insertions
- Clear table
31Practical OJB
Querying data Report query
- String fields new String "name",
"hireDate" - Criteria criteria new Criteria()
- criteria.addEqualTo("departmentId", new
Integer(7)) - Query query QueryFactory.newReportQuery(Employe
e.class, fields, criteria, true) - Iterator it broker.getReportQueryIteratorByQuer
y(query) - while (it.hasNext())
- Object row (Object) it.next()
- System.out.println("Name " row0 "
Hire Date " row1) -
32Practical OJB
Querying data Writing custom SQL
- ClassDescriptor descriptor broker.getClassDescr
iptor(Employee.class) - EmployeeSqlGenerator.employeeTable
descriptor.getFullTableName() - EmployeeSqlGenerator.id descriptor.getF
ieldDescriptorByName(Employee.ID).getColumnName()
- EmployeeSqlGenerator.name descriptor.getFie
ldDescriptorByName(Employee.NAME).getColumnName()
- StringBuffer buffer new StringBuffer()
- buffer.append(select ).append(id)
- buffer.append(, ).append(name)
- buffer.append( from ).append(employeeTable)
33Practical OJB
Caching Choices
- Default (ObjectCacheDefaultImpl)
- SoftReferences
- Timeout
- Optionally transaction aware
- Short-life cache (ObjectCachePerBrokerImpl)
- Flushed upon broker release
- Flushed upon transaction completion
34Practical OJB
Caching Choices (cont.)
- No cache (ObjectCacheEmptyImpl)
- Complex implementations (JCSImpl/OSCacheImpl)
- Clustering
35Practical OJB
Caching Tuning
- CacheFilter
- Cacheable property per class-descriptor
36Practical OJB
Schema creation OJB and Torque
- Leverage Torques DDL generation capabilities
- Repository.xml already contained most of the
needed information - Convert repository.xml to Torque
- Submitted patch
37Practical OJB
Problem OJB?
- Monolithic repository.xml
- Debugging
- All mapped classes are required in classpath
- Custom query support
- Lacking good OQL implementation
38Practical OJB
Problem OJB? (cont.)
- O/R support limitations
- Collections (ex ordered list, maps)
- Redundant field declarations for referential
integrity - Discriminator-less polymorphism
39Practical OJB
Problem OJB? (cont.)
- Project momentum
- Direction
- Doesnt match our organizations needs
- Lacking in cooperation
- Patches
- Mailing list
40Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
41Hibernate The Transition
Why Hibernate 2004?
- Mature API
- Strong development community
- Comprehensive documentation
- Variety of conversion tools (including MiddleGen
support) - Powerful query language (HQL)
- Future JDO implementation
42Hibernate The Transition
Example changes Before (OJB)
- ltclass-descriptor idemployee
- classjavaone.example.Employee
- tableEmployeegt
- ltfield-descriptor id1
- nameid
- columnid
- length38 jdbc-typeINTEGER
- java-typeint primarykeytrue/gt
- ltfield-descriptor id2
- namename
- columnname
- jdbc-typeVARCHAR/gt
43Hibernate The Transition
Example changes After (Hibernate)
- ltclass namejavaone.example.Employee
tableEmpgt - ltid nameid columnEmpNo
- typejava.lang.Integergt
- ltgenerator classnative /gt
- lt/idgt
- ltproperty namename type"java.lang.Stringgt
- ltcolumn nameeName length10
- not-nullfalse /gt
- lt/propertygt
44Hibernate The Transition
Example changes Before/After
- OJB
- PersistenceBroker broker DSPersistenceBrokerFact
ory.createPersistenceBroker() - broker.store(e)
- Hibernate
- Session session configuration.buildSessionFactor
y().openSession() - session.save(e)
45Hibernate The Transition
Using the session
- Implicit database/memory synchronization
- Session-level cache
- Contains(), evict(), clear()
46Hibernate The Transition
Basic changes
- Default (no-argument) constructor required
- Composite IDs require
- equals()
- hashCode()
- Serializable
- Unchecked versus checked exceptions
47Hibernate The Transition
Basic changes (cont.)
- Foreign key fields no longer required
48Hibernate The Transition
Problem hbm generation
- Class to hbm
- Object relationships/relational relationships
- Type conversion
- DDL to hbm (Middlegen support)
- Complex relationships
- Composite keys
- Optimal collection mapping
49Hibernate The Transition
Solution OJB2Hbm
- Convert OJB repository.xml
- Minimize code changes
- Preserve DDL
- Indexes retained
- Optimal collection representation
- Available on SourceForge
- http//ojb2hbm.sf.net
50Agenda
- The Beginning Entity Beans Are Painful
- Practical Persistence Layers
- OJB The Transition
- Practical OJB
- Hibernate The Transition
- Practical Hibernate
51Practical Hibernate
Generate IDs
- Native generation
- Identity column for MS SQL
- Sequences for Oracle/PostgreSQL
- Hi/Lo if database does not provide native
generation - Specify unsaved values for transient objects
52Practical Hibernate
Querying data HQL with query substitution
- ltproperty name"hibernate.query.substitutions"gt
- toLowercase lower
- lt/propertygt
- --------------------------------------------------
---- - select emp.id, emp.name, emp.hireDate from
Employee emp where toLowercase(emp.name) name - select employee0_.EmpNo as x0_0_,
employee0_.eName as x1_0_, employee0_.hireDate as
x2_0_ from Emp employee0_ where
(lower(employee0_.eName)? )
53Practical Hibernate
Querying data Report query
- String sql "select emp.name, emp.hireDate "
- "from Employee emp "
- "where emp.departmentId ?"
- List employees session.find(sql, new
Integer(7), Hibernate.INTEGER) - Iterator it employees.iterator()
- while (it.hasNext())
- Object row (Object) it.next()
- System.out.println("Name " row0 " Hire
Date " row1)
54Practical Hibernate
Caching decisions
- Second level cache
- Specify by class and/or collection
- Multiple usage strategies
- Supported implementations
- EHCache (default)
- HashtableCacheProvider (non-production use)
- JCSCache (deprecated)
- OSCache
- SwarmCache
- JBossTreeCache
- Query cache
55Practical Hibernate
Schema creation
- SchemaExport
- Converts hbm mappings to DDL
- Available as ANT task
- SchemaUpdate
- Incremental updates
- Depends on JDBC metadata
56Summary
What have we learned
- Dont believe the hype
- OJB is a viable option
- Hibernate is a viable option
- Keep an eye on JDO
- Reduce coupling between your application and
persistence layer - Hand-written SQL is often necessary
- Automated schema creation rocks!
57Persistence Layers In An Enterprise Application
An Evolution From SQL to OJB to Hibernate
- Scott Delap, Amit Gollapudi, Scott GelbDemand
Management, Inc. - www.demandsolutions.com