JPA Best Practices
-
Upload
carol-mcdonald -
Category
Technology
-
view
94.430 -
download
0
Transcript of JPA Best Practices
chuk_TD09_JPA_best_practices.odp
Java Persistence API:
Best Practices
Carol McDonaldJava Architect
Agenda
Entity Manager
Persistence Context
Entities
Schema & Queries
Transaction
Persistence Context
EntityManager
persist()remove()refresh()merge()find()createQuery()createNamedQuery()contains()flush()
EntityManager
API for managing entities
set of entities managed by
Entity Manager
ServletsEJBsJava app
Catalog Java EE Application
DBRegistration ApplicationManaged BeanJSF ComponentsSession BeanEntity ClassCatalogItem ManagedBean
EJB EntityManager Example
@Statelesspublic class Catalog implements CatalogService {
@PersistenceContext(unitName=PetCatalogPu) EntityManager em;
@TransactionAttribute(NOT_SUPPORTED) public List getItems(int firstItem,int batchSize) { Query q = em.createQuery("select i from Item as i"); q.setMaxResults(batchSize); q.setFirstResult(firstItem); List items= q.getResultList(); return items; }}
To obtain an container managed EntityManager instance, inject the entity manager into the application component:@PersistenceContextEntityManager em;
you don't need any cm lifecycle methods
With a container-managed entity manager, an EntityManager instance's persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction Architecture (JTA) transaction.
JTA transactions usually involve calls across application components. To complete a JTA transaction, these components usually need access to a single persistence context. This occurs when an EntityManager is injected into the application components via the javax.persistence.PersistenceContext annotation. The persistence context is automatically propagated with the current JTA transaction, and EntityManager references that are mapped to the same persistence unit provide access to the persistence context within that transaction. By automatically propagating the persistence context, application components don't need to pass references to EntityManager instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers.
Catalog Spring JPA Application
DBRegistration ApplicationManaged BeanJSF ComponentsSpring BeanEntity ClassCatalogItem ItemController
Spring Framework
Spring with JPA
@Repository
@Transactional
public class CatalogDAO implements CatalogService {
@PersistenceContext(unitName="PetCatalogPu")
private EntityManager em;
@Transactional(readOnly=true)
public List getItems(int firstItem,int batchSize) {
Query q = em.createQuery("select object(o) from Item as o");
q.setMaxResults(batchSize);
q.setFirstResult(firstItem);
List items= q.getResultList();
return items;
}
Component Stereotype
Spring transactions use aop
To obtain an container managed EntityManager instance, inject the entity manager into the application component:@PersistenceContextEntityManager em;
you don't need any cm lifecycle methods
With a container-managed entity manager, an EntityManager instance's persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction Architecture (JTA) transaction.
JTA transactions usually involve calls across application components. To complete a JTA transaction, these components usually need access to a single persistence context. This occurs when an EntityManager is injected into the application components via the javax.persistence.PersistenceContext annotation. The persistence context is automatically propagated with the current JTA transaction, and EntityManager references that are mapped to the same persistence unit provide access to the persistence context within that transaction. By automatically propagating the persistence context, application components don't need to pass references to EntityManager instances to each other in order to make changes within a single transaction. The Java EE container manages the lifecycle of container-managed entity managers.
Container vs Application Managed
Container managed entity managers (EJB, Spring Bean, Seam component)
Injected into application
Automatically closed
JTA transaction propagated
Application managed entity managers
Used outside of the JavaEE 5 platform
Need to be explicitly created
Persistence.createEntityManagerFactory()
RESOURCE_LOCAL transaction not propagated
Need to explicitly close entity manager
Agenda
Entity Manager
Persistence Context
Entities
Queries
Transaction
Persistence Context
EntityManager
persist()remove()refresh()merge()find()createQuery()createNamedQuery()contains()flush()
Persistence Context
set of entities managed by
Entity Manager
Persistence context acts as a first level cache for entities
Two types of persistence context
Transaction scoped
Extended scoped persistence context
Level1 and Level2 caches
The terms Java Virtual Machine and JVM mean a Virtual Machine for the Java Platform. Source:http://weblogs.java.net/blog/guruwons/archive/2006/09/understanding_t.html
Persistence Context is a Level 1 cache
Transaction
Transaction
Transaction
Persistence Context(EntityManager)
Persistence Context(EntityManager)
Persistence Context(EntityManager)
L2 Cache(Shared Cache)
Entity managers for a specific PersistenceUnit on a given Java Virtual Machine (JVM)
Persistence Context
ManagedEntityManagedEntityNewEntityRemovedEntityDetachedEntity
Transaction commit
new()
persist()
Updates
remove()
Merge()find()
PC ends
Entity Lifecycle
Guaranteed Scope of Object Identity only one manage entity in PC represents a row
ManagedEntity
Entity Lifecycle Illustrated The Code
@Stateless public ShoppingCartBeanimplements ShoppingCart {
@PersistenceContext EntityManager entityManager;
public OrderLine createOrderLine(Product product, Order order) {OrderLine orderLine = new OrderLine(order, product);entityManager.persist(orderLine);return (orderLine);}
}
New entity
Managed entity
Detached entity
Persistence context
Here is how you could do this with a stateless session bean. We inject reference to a container managed EntityManager using the persistence context annotation. We create a new order and the entity has the state of new. We call persist, making this a managed entity. because it is a stateless session bean it is by default using container managed transactions , when this transaction commits , the order is made persistent in the database. When we return the serialiable orderline entity it is a detached entity
Scope of Identity
@Stateless public ShoppingCartBean implements ShoppingCart {
@PersistenceContext EntityManager entityManager;
public OrderLine createOrderLine(Product product,Order order) {OrderLine orderLine = new OrderLine(order, product);entityManager.persist(orderLine); OrderLine orderLine2 =entityManager.find(OrderLine,orderLine.getId())); (orderLine == orderLine2) // TRUEreturn (orderLine);}
}
Persistence context
Multiple retrievals of the same object return references to the same object instance
Here is how you could do this with a stateless session bean. We inject reference to a container managed EntityManager using the persistence context annotation. We create a new order and the entity has the state of new. We call persist, making this a managed entity. because it is a stateless session bean it is by default using container managed transactions , when this transaction commits , the order is made persistent in the database. When we return the serialiable orderline entity it is a detached entity
Persistence Context
Two types of persistence context
Transaction scoped
Used in stateless components
Typically begins/ends at request entry/exit points respectively
Extended scoped persistence context
Persistence Context Propagation
@Stateless public class ShoppingCartBean implements ShoppingCart {
@EJB InventoryService inv;
@EJB OrderService ord;
public void checkout(Item i, Product p) {
inv.createOrder(item);
ord.updateInventory(Product p)
}
}
Persistence context
Persistence Context Propagation
@Stateless public class OrderServiceBean implements OrderService {
@PersistenceContext EntityManager em1;
public void createOrder(Item item) {
em1.persist(new Order(item));
}
}
@Stateless public class InventoryServiceBean implements InventoryService {
@PersistenceContext EntityManager em2;
public void updateInventory(Product p) {
Product product = em2.merge(p);
. . .
}
}
Declarative Transaction Management Example
TX_REQUIRED
TX_REQUIRED
TX_REQUIRED
PC
PC
PC
ShoppingCart
InventoryService
OrderService
Check Out
1. Update Inventory
New PersistenceContext
Persistence Context Propagated
TransactionAttributes
2. Create Order
In a transaction-scoped container managed entity manager (common case in a Java EE environment), the JTA transaction propagation is the same as the persistence context resource propagation. In other words, container-managed transaction-scoped entity managers retrieved within a given JTA transaction all share the same persistence context.
AuditServiceBean
@Statelesspublic class AuditServiceBean implements AuditService { @PersistenceContext private EntityManager em;
@TransactionAttribute(REQUIRES_NEW) public void logTransaction2(int id, String action) { LogRecord lr = new LogRecord(id, action); em.persist(lr); }
NEWPC !
Declarative Transaction Management Example 2
REQUIRED
REQUIRED
REQUIRES_NEW
PC
PC
PC2
ShoppingCart
InventoryService
AuditService
Check Out
1. Update Inventory
New PersistenceContext
Persistence Context Propagated
TransactionAttributes
2. log transaction
NEWPC !
In a transaction-scoped container managed entity manager (common case in a Java EE environment), the JTA transaction propagation is the same as the persistence context resource propagation. In other words, container-managed transaction-scoped entity managers retrieved within a given JTA transaction all share the same persistence context.
Persistence Provider PC Transaction Features
Attribute-level change tracking
Only the minimal updates are sent to the database
Orders INSERT, UPDATE and DELETE statements
Minimizes database interactions
EntityManager flush SQL prior to commit
Persistence Context
ManagedEntityDetachedEntityConversation with detached entity
ManagedEntityManagedEntity
Persistence Context
ManagedEntityManagedEntityManagedEntityDetachedEntity
merge()
transaction-scoped persistence context
request
response
request
response
Conversation
transaction-scoped persistence context
Conversation with detached entity
@Stateless public ShoppingCartBean implements ShoppingCart { @PersistenceContext EntityManager entityManager;
public OrderLine createOrderLine(Product product,Order order) {OrderLine orderLine = new OrderLine(order, product);entityManager.persist(orderLine);return (orderLine);}
public OrderLine updateOrderLine(OrderLine orderLine){ OrderLine orderLine2 =entityManager.merge(orderLine)); return orderLine2;}}
Managed entity
Detached entity
Managed entity
Here is how you could do this with a stateless session bean. We inject reference to a container managed EntityManager using the persistence context annotation. We create a new order and the entity has the state of new. We call persist, making this a managed entity. because it is a stateless session bean it is by default using container managed transactions , when this transaction commits , the order is made persistent in the database. When we return the serialiable orderline entity it is a detached entity
Types of Persistence Context
Persistence Context
lifetime maybe transaction-scoped or extended
Transaction-scoped persistence context
Extended persistence context
spans multiple transactions
A persistence context can be either transaction scoped or extended scope. A transaction scope pc is one that is bound to a jta it starts and ends at transaction boundaries. At the end of the transaction the entities become detached. An extended pc spans multiple transactios, and it exists from the time the em is created until it is closed. An extended pc can be useful in web apps when you have conversations that span multiple requests. So the em can remain open between requests and you can close the em when done. Components like Stateful session can hold references to managed instances. It avoids flushing the database between requests and then re-finding entities so in some cases can improve performance. The type of pc is defined when you create the entity managerPersistence contexts may live as long as a transaction and be closed when a transaction completes. This is called a transaction-scoped persistence context . When the transaction completes, the transaction-scoped persistence context will be destroyed and all managed entity object instances will become detached. Persistence contexts may also be configured to live longer than a transaction. This is called an extended persistence context . Entity object instances that are attached to an extended context remain managed even after a transaction is complete. This feature is extremely useful in situations where you want to have a conversation with your database but not keep a long-running transaction
Persistence Context
ManagedEntityConversation with Exented Persistence Context
ManagedEntityManagedEntity
request
response
request
response
Conversation
extended persistence context
Extended Persistence Context
@Stateful public class OrderMgr {
//Specify that we want an EXTENDED @PersistenceContext(type=PersistenceContextType.EXTENDED)EntityManager em;
//Cached orderprivate Order order;
//create and cache orderpublic void createOrder(String itemId) {//order remains managed for the lifetime of the beanOrder order = new Order(cust);em.persist(order);}
public void addLineItem(OrderLineItem li){ order.lineItems.add(li); }
Managed entity
Managed entity
Extended Persistence Context
@Stateful public class DeptMgr {@PersistenceContext(type=PersistenceContextType.EXTENDED)EntityManager em;
private Department dept;
@TransactionAttribute(NOT_SUPPORTED)public void getDepartment(int deptId) {dept = em.find(Department.class,deptId);}
@TransactionAttribute(NOT_SUPPORTED) public void addEmployee(int empId){ emp = em.find(Employee.class,empId); dept.getEmployees().add(emp); emp.setDepartment(dept); } @Remove @TransactionAttribute(REQUIRES_NEW)public void endUpdate(int deptId) {dept = em.find(Department.class,deptId);}
Persistence Context-Transactional vs. Extended
@Statelesspublic class OrderMgr implements OrderService {
@PersistenceContext EntityManager em; public void addLineItem(OrderLineItem li){ // First, look up the order. Order order = em.find(Order.class, orderID); order.lineItems.add(li);}
@Statefulpublic class OrderMgr implements OrderService {@PersistenceContext(type = PersistenceContextType.EXTENDED))EntityManager em; // Order is cachedOrder orderpublic void addLineItem(OrderLineItem li){ // No em.find invoked for the order object order.lineItems.add(li);}
look up the order
No em.find invoked
Managed entity
In this example the sb looks up an order, adds a line items. The stateless session bean does the workflow with a lookup and merge in each operation as needed, whereas the stateful session bean does the same by caching the references.
Persistence Context Micro Benchmark
Source: Internal benchmarks
Micro benchmark with lots of lookups
Persistence context is caching entities
SEAM Conversations
@Name("shopper")
@Scope(CONVERSATION)
public class BookingManager {
@In EntityManager entityManager;
private Booking booking;
@Begin public void selectHotel(Hotel selectedHotel){
hotel = em.merge(selectedHotel);
}
@End public void confirm() {
em.persist(booking);
}
}
SEAM injected
SEAM conversation
Concurrency and Persistence Context
Persistence Context 1
Entity Manager
Persistence Context 2
Entity Manager
Data source
same entity
Object Identity only one manage entity in PC represents a row
User 2 transaction
User 1 transaction
Optimistic versus Pessimistic Concurrency
Optimistic Concurrency
ProsNo database locks held
ConsRequires a version attribute in schema
user or app must refresh and retry failed updates
Suitable when application has few parallel updates
Pessimistic Concurrency
Lock the row when data is read in
database locks the row upon a select
(SELECT . . . FOR UPDATE [NOWAIT])
ProsSimpler application code
ConsDatabase locks
limits concurrent access to the data = scalability
May cause deadlocks
Not in JPA 1.0 (vendor specific), supported in JPA 2.0
Suitable when application has many parallel updates
Optimistic locking permits all users to read and attempt to update the same data, concurrently. It does not prevent others from changing the same data, but it does guarantee the database will not be updated based on stale data.Pessimistic locking is the most restrictive form of locking but guarantees no changes are performed on the data during your transaction. The database physically locks the row upon a select (SELECT . . . FOR UPDATE [NOWAIT]) and prevents others from altering that row.This reassurance comes at a cost as pessimistic locks cannot be held across transactions and only one user can access the underlying data. Pessimistic locking should be used carefully as it limits concurrent access to the data and may cause deadlocks.
Preventing Parallel Updates
use @Version for optimistic locking
Used by persistence manager , Results in following SQL
UPDATE Employee SET ..., version = version + 1
WHERE id = ? AND version = readVersion
Version Updated when transaction commits, merged or acquiring a write lock
OptimisticLockException if mismatch
Not used by the application!
public class Employee {@ID int id;@Version int version;...
Can be int, Integer, short, Short, long, Long, Timestamp
Preventing Parallel Updates 1
tx1.begin();
//Joe's employee id is 5
//e1.version == 1
e1 = findPartTimeEmp(5);
//Joe's current rate is $9
e1.raise(2);
tx1.commit();
//e1.version == 2 in db
//Joe's rate is $11
tx2.begin();
//Joe's employee id is 5
//e1.version == 1
e1 = findPartTimeEmp(5);
//Joe's current rate is $9
if(e1.getRate() < 10)
e1.raise(5);
//e1.version == 1 in db?
tx2.commit();
//Joe's rate is $14
//OptimisticLockException
Time
Preventing Stale Data JPA 1.0
Perform read or write locks on entities
Prevents non-repeatable reads in JPA
entityManager.lock( entity, READ);
perform a version check on entity before commit
OptimisticLockException if mismatch
entityManager.lock( entity, WRITE);
perform a version check on entity
OptimisticLockException if mismatch
and increment version before commit
Preventing Stale Data
tx1.begin();
d1 = findDepartment(dId);
//d1's original name is
//Engrg
d1.setName(MarketEngrg);
tx1.commit();
tx2.begin();
e1 = findEmp(eId);
d1 = e1.getDepartment();
em.lock(d1, READ);
if(d1's name is Engrg)
e1.raiseByTenPercent();
//Check d1.version in db
tx2.commit();
//e1 gets the raise he does
//not deserve
//Transaction rolls back
Time
Write lock prevents parallel updates
tx1.begin();
d1 = findDepartment(dId);
//d1's original name is
//Engrg
d1.setName(MarketEngrg);
tx1.commit();
//tx rolls back
tx2.begin();
e1 = findEmp(eId);
d1 = e1.getDepartment();
em.lock(d1, WRITE);
//version++ for d1
em.flush();
if(d1's name is Engrg)
e1.raiseByTenPercent();
tx2.commit();
Preventing Parallel Updates 2
Time
The spec mendates that a persistence application operates at read committed level that is no dirty reads (or uncommitted data) is read.
Bulk Updates
Update directly against the database, can be Faster But
By pass EntityManager
@Version will not be updated
Entities in PC not updated
tx.begin();
int id = 5; //Joe's employee id is 5
e1 = findPartTimeEmp(id); //Joe's current rate is $9
//Double every employee's salary
em.createQuery(
Update Employee set rate = rate * 2).executeUpdate();
//Joe's rate is still $9 in this persistence context
if(e1.getRate() < 10)
e1.raiseByFiveDollar();
tx.commit();
//Joe's salary will be $14
JPA 2.0 Locks
JPA1.0 only supported optimistic locking, JPA 2.0 also supports pessimistic locks
JPA 2.0 LockMode values :
OPTIMISTIC (= READ)
OPTIMISTIC_FORCE_INCREMENT (= WRITE)
PESSIMISTIC
PESSIMISTIC_FORCE_INCREMENT
Multiple places to specify lock
database locks the row (SELECT . . . FOR UPDATE )
//Read then lock:
Account acct = em.find(Account.class, acctId);
// Decide to withdraw $100 so lock it for update
em.lock(acct, PESSIMISTIC);
int balance = acct.getBalance();
acct.setBalance(balance - 100);
//Read and lock:
Account acct = em.find(Account.class, acctId,PESSIMISTIC);
// Decide to withdraw $100 (already locked)
int balance = acct.getBalance();
acct.setBalance(balance - 100);
JPA 2.0 Locking
Locks longer,could cause bottlenecks,deadlock
Lock after read, risk stale, could cause OptimisticLockException
The spec mendates that a persistence application operates at read committed level that is no dirty reads (or uncommitted data) is read.
// read then lock and refresh
Account acct = em.find(Account.class, acctId);
// Decide to withdraw $100 - lock and refresh
em.refresh(acct, PESSIMISTIC);
int balance = acct.getBalance();
acct.setBalance(balance - 100);
JPA 2.0 Locking
right approach depends on requirements
Trade-offs:
lock earlier : risk bad scalability, deadlock
Lock later : risk stale data for update, get optimistic lock exception
The spec mendates that a persistence application operates at read committed level that is no dirty reads (or uncommitted data) is read.
L2 cache shared across transactions and users
Putting it all together
User Session
User Session
User Session
Persistence Context(EntityManager)
Persistence Context(EntityManager)
Persistence Context(EntityManager)
L2 Cache(Shared Cache)
Entity managers for a specific PersistenceUnit on a given Java Virtual Machine (JVM)
(EntityManagerFactory)
Second-level Cache
L2 Cache shares entity state across various persistence contexts
If caching is enabled, entities not found in persistence context, will be loaded from L2 cache, if found
Best for read-mostly classes
L2 Cache is Vendor specific
Java Persistence API 1.0 does not specify L2 support
Java Persistence API 2.0 has basic cache operations
Most persistence providers-- Hibernate, EclipseLink, OpenJPA ... provide second-level cache(s)
An application might want to share entity state across various persistence contexts
This is the domain of second level (L2) cache
If caching is enabled, entities not found in persistence context, will be loaded from L2 cache, if found
JPA does not specify support of a second level cache
However, most of the persistence providers provide in-built or integrated support for second level cache(s)
Basic support for second level cache in GlassFish-TopLink Essentials is turned on by default
No extra configuration is needed
L2 Cache
User transaction 1
Persistence Context
User transaction 2
Persistence Context
Data source
same entitynot shared
L2 Cache
EntityEntity
query that looks for a single object based on Id will go 1st to PC then to L2 cache, other queries go to database or query cache
Shared entity
L2 Caching
Pros:
avoids database access for already loaded entities
faster for reading frequently accessed unmodified entities
Cons
memory consumption for large amount of objects
Stale data for updated objects
Concurrency for write (optimistic lock exception, or pessimistic lock)
Bad scalability for frequent or concurrently updated entities
L2 Caching
Configure L2 caching for entities that are
read often
modified infrequently
Not critical if stale
protect any data that can be concurrently modified with a locking strategy
Must handle optimistic lock failures on flush/commit
configure expiration, refresh policy to minimize lock failures
Configure Query cache
Useful for queries that are run frequently with the same parameters, for not modified tables
JPA 2.0 Shared Cache API
entity cache shared across persistence unit
Accessible from EntityManagerFactory
Supports only very basic cache operations
Can be extended by vendors
public class Cache {
//checks if object is in IdentityMap
public boolean contains(Class class, Object pk);
// invalidates object in the IdentityMap
public void evict(Class class, Object pk);
public void evict(Class class); // invalidates the class in the IdentityMap.
public void evictAll(); // Invalidates all classes in the IdentityMap
}
EclipseLink Caching Architecture
EntityManagerEntityManagerFactoryServerL1 Cache
PC CacheL2 Shared Cache
Cache CoordinationJMS (MDB)RMI CORBAIIOP
EclipseLink caches Entities in L2, Hibernate does not
EclipseLink Extensions - L2 Caching
Default: Entities read are L2 cached
Cache Configuration by Entity type or Persistence Unit
You can disable L2 cache
Configuration Parameters
Cache isolation, type, size, expiration, coordination, invalidation,refreshing
Coordination (cluster-messaging)
Messaging: JMS, RMI, RMI-IIOP,
Mode: SYNC, SYNC+NEW, INVALIDATE, NONE
@Entity
@Table(name="EMPLOYEE")
@Cache (
type=CacheType.WEAK,
isolated=false,
expiry=600000,
alwaysRefresh=true,
disableHits=true,
coordinationType=INVALIDATE_CHANGED_OBJECTS
)
public class Employee implements Serializable {
...
}
EclipseLink Mapping Extensions
Type=Full: objects never flushed unless deleted or evictedweak: object will be garbage collected if not referenced
@Cache
type, size,isolated, expiry, refresh, cache usage, coordination
Cache usage and refresh query hints
=truedisables L2 cache
The spec mendates that a persistence application operates at read committed level that is no dirty reads (or uncommitted data) is read.
Hibernate L2 Cache
Hibernate L2 cache is not configured by default
Hibernate L2 does not cache Entities. Hibernate caches Id and state
Hibernate L2 cache is pluggable
EHCache, OSCache, SwarmCacheProvider (JVM)
JBoss TreeCache Cluster
Can plug in others like Terracotta
Cache Concurrency Strategy
Hibernate L2 Cache
net.sf.ehcache.configurationResourceName=/name_of_configuration_resource
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public Class Country {
private String name;
...
}
not configured by default
Cache Concurrency Strategymust be supported by cache provider
OpenJPA L2 Caching
OpenJPA L2 caches object data and JPQL query results
Updated when data is loaded from database and after changes are successfully committed
For cluster caches are notified when changes are made
Can plug in implementations, such as Tangosols Coherence product
several cache eviction strategies:
Time-to-live settings for cache instances
@Entity @DataCache(timeout=5000)
public class Person { ... }
Agenda
Entity Manager
Persistence Context
Entities
Schema and Queries
Transaction
Maintaining Relationship
Application bears the responsibility of maintaining relationship between objects
Department A
Employee1
Employee2
Employee3
Employee1
Employee2
Employee3
Before
After
Inconsistent!
Department B
Department A
Department B
deptA.getEmployees().add(e3);
Example Domain Model
@Entity public class Employee {
@Id private int id;
private String firstName;
private String lastName;
@ManyToOne(fetch=LAZY)
private Department dept;
...
}@Entity public class Department {
@Id private int id;
private String name;
@OneToMany(mappedBy = "dept", fetch=LAZY)
private Collection emps = new ...;
... }
Example Managing Relationship
public int addNewEmployee(...) {Employee e = new Employee(...);Department d = new Department(1, ...);
e.setDepartment(d);//Reverse relationship is not setem.persist(e);em.persist(d); return d.getEmployees().size();}
INCORRECT
Example Managing Relationship
public int addNewEmployee(...) {Employee e = new Employee(...);Department d = new Department(1, ...);
e.setDepartment(d);d.getEmployees().add(e);em.persist(e);em.persist(d); return d.getEmployees().size();}
CORRECT
Navigating Relationships
Data fetching strategy
EAGER immediate
LAZY loaded only when needed
LAZY is good for large objects and/or with relationships with deep hierarchies
Lazy loading and JPA
Default FetchType is LAZY for 1:m and m:n relationships
benefits large objects and relationships with deep hierarchies
However for use cases where data is needed can cause n+1 selects
LAZY N + 1 problem:
@Entity public class Department {
@Id private int id;
@OneToMany(mappedBy = "dept")
private Collection emps ;
... }
SELECT d.id, ... FROM Department d // 1 time
SELECT e.id, ... FROM Employee e
WHERE e.deptId = ? // N times
Lazy loading and JPAWith JPA many-to-one and many-to-many relationships lazy load by default , meaning they will be loaded when the entity in the relationship is accessed. Lazy loading is usually good, but if you need to access all of the "many" objects in a relationship, it will cause n+1 selects where n is the number of "many" objects. You can change the relationship to be loaded eagerly as follows :public class Employee{ @OneToMany(mappedBy = "employee", fetch = FetchType.EAGER) private Collection addresses; .....}However you should be careful with eager loading which could cause SELECT statements that fetch too much data. It can cause a Cartesian product if you eagerly load entities with several related collections. If you want to temporarily override the LAZY fetch type, you could use Fetch Join. For example this query would eagerly load the employee addresses: @NamedQueries({ @NamedQuery(name="getItEarly", query="SELECT e FROM Employee e JOIN FETCH e.addresses")})public class Employee{.....}
Lazy loading and JPA
Relationship can be Loaded Eagerly
But if you have several related relationships, could load too much !
OR
Temporarily override the LAZY fetch type, use Join Fetch in a query:
@Entity public class Department {
@Id private int id;
@OneToMany(mappedBy = "dept", fetch=EAGER)
private Collection employees ;
... }
@NamedQueries({ @NamedQuery(name="getItEarly", query="SELECT d FROM Department d JOIN FETCH d.employees")})
public class Department{.....}
Can cause Cartesian product
Lazy loading and JPAWith JPA many-to-one and many-to-many relationships lazy load by default , meaning they will be loaded when the entity in the relationship is accessed. Lazy loading is usually good, but if you need to access all of the "many" objects in a relationship, it will cause n+1 selects where n is the number of "many" objects. You can change the relationship to be loaded eagerly as follows :
However you should be careful with eager loading which could cause SELECT statements that fetch too much data. It can cause a Cartesian product if you eagerly load entities with several related collections. If you want to temporarily override the LAZY fetch type, you could use Fetch Join. For example this query would eagerly load the employee addresses: Cartiesian product is the set of all possible ordered pairs
Lazy loading and JPA
Capture generated SQL
persistence.xml file:
Test run use cases and examine the SQL statements
optimise the number of SQL statements executed!
only retrieve the data your application needs!
Lazy load large (eg BLOB) attributes and relationships that are not used often
Override to Eagerly load in use cases where needed
Lazy loading and JPAWith JPA many-to-one and many-to-many relationships lazy load by default , meaning they will be loaded when the entity in the relationship is accessed. Lazy loading is usually good, but if you need to access all of the "many" objects in a relationship, it will cause n+1 selects where n is the number of "many" objects. You can change the relationship to be loaded eagerly as follows :public class Employee{ @OneToMany(mappedBy = "employee", fetch = FetchType.EAGER) private Collection addresses; .....}However you should be careful with eager loading which could cause SELECT statements that fetch too much data. It can cause a Cartesian product if you eagerly load entities with several related collections. If you want to temporarily override the LAZY fetch type, you could use Fetch Join. For example this query would eagerly load the employee addresses: @NamedQueries({ @NamedQuery(name="getItEarly", query="SELECT e FROM Employee e JOIN FETCH e.addresses")})public class Employee{.....}
Navigating Relationships
Accessing a LAZY relationship from a detached entity
If not loaded , Causes an exception
Solutions:
Use JOIN FETCH
Or Set Fetch type to EAGER
Or Access the collection before entity is detached:
d.getEmployees().size();
DetachedEntity
Persistence Context
ManagedEntity
Navigating Relationships
Data fetching strategy
Cascade specifies operations on relationships
ALL, PERSIST, MERGE, REMOVE, REFRESH
The default is do nothing
Avoid MERGE, ALL with deep hierarchies
If want to do it, limit the scope
Using Cascade
@Entity public class Employee {
@Id private int id;
private String firstName;
private String lastName;
@ManyToOne(cascade=ALL, fetch=LAZY)
private Department dept;
...
}@Entity public class Department {
@Id private int id;
private String name;
@OneToMany(mappedBy = "dept"cascade=ALL, fetch=LAZY)
private Collection emps = new ...;@OneToManyprivate Collection
codes;
... }
Employee
Department
DepartmentCode
cascade=ALL
X
Agenda
Entity Manager
Persistence Context
Entities
Schema and Queries
Transaction
Database design Basic foundation of performance
Smaller tables use less disk, less memory, can give better performance
Use as small data types as possible
use as small primary key as possible
Vertical Partition:
split large, infrequently used columns into a separate one-to-one table
Use good indexing
Indexes Speed up Querys
Indexes slow down Updates
Index columns frequently used in Query Where clause
Normalization
Normalization Eliminates redundant data
updates are usually faster.
there's less data to change.
However Normalized database causes joins for queries
Queries maybe slower
Normalize then maybe De-normalize frequently read columns and cache them
In a normalized database, each fact is represented once and only once. Conversely, in a denormalized database, information is duplicated, or stored in multiple places.People who ask for help with performance issues are frequently advised to normalize their schemas, especially if the workload is write-heavy. This is often good advice. It works well for the following reasons: Normalized updates are usually faster than denormalized updates. When the data is well normalized, there's little or no duplicated data, so there's less data to change. Normalized tables are usually smaller, so they fit better in memory and perform better. The lack of redundant data means there's less need for DISTINCT or GROUP BY queries when retrieving lists of values. Consider the preceding example: it's impossible to get a distinct list of departments from the denormalized schema without DISTINCT or GROUP BY, but if DEPARTMENT is a separate table, it's a trivial query.The drawbacks of a normalized schema usually have to do with retrieval. Any nontrivial query on a well-normalized schema will probably require at least one join, and perhaps several. This is not only expensive, but it can make some indexing strategies impossible. For example, normalizing may place columns in different tables that would benefit from belonging to the same index.
Mapping Inheritance Hierarchies
Employee--------------------------- int id String firstName
String lastName
Department dept
PartTimeEmployee------------------------ int rate
FullTimeEmployee----------------------- double salary
Single Table Per Class
Benefits
Simple
No joins required
can be fast for Queries
Drawbacks
Not normalized
Wastes space
Requires columns corresponding to subclasses' state to be null
Table can have too many columns
Larger tables= more data, can have negative affects on performance
@Inheritance(strategy=SINGLE_TABLE)
EMPLOYEE--------------------------- IDInt PK,
FIRSTNAMEvarchar(255), LASTNAMEvarchar(255),
DEPT_IDint FK, RATEint NULL, SALARYdouble NULL,
DISCRIMvarchar(30)
single table means that all of those classes are being stored in the same table and all we need is a a discriminator column in that table . So the disc column tells what type. This leads to some wastage of space, if you have a rate then you don't have a salary . But it does make for quick querying because you can find through a single table scan all of the objects of a type.
Joined Subclass
Benefits
Normalized database
Better for storage
Database view same as domain model
Easy to evolve domain model
Drawbacks
Queries cause joins
Slower queries
Poor performance for deep hierarchies, polymorphic queries and relationships
@Inheritance(strategy=JOINED)
IDint PK, FIRSTNAMEvarchar(255), LASTNAMEvarchar(255),
DEPT_IDint FK,
IDint PK FK,RATEint NULL
IDint PK FK, SALARYdouble NULL
EMPLOYEE
PARTTIMEEMPLOYEE
FULLTIMEEMPLOYEE
joined hierarchy , great for storage a little more expensive for querying
Table Per Class
Benefits
No need for joins to read entities of same type
Faster reads
Drawbacks
Not normalized
Wastes space
Polymorphic queries cause union (all employees)
Poor performance
This strategy is not mandatory
@Inheritance(strategy=TABLE_PER_CLASS)
IDint PK, FIRSTNAMEvarchar(255), LASTNAMEvarchar(255), DEPT_IDint FK, SALARYdouble NULL
IDint PK, FIRSTNAMEvarchar(255), LASTNAMEvarchar(255), DEPT_IDint FK, RATEint NULL
PARTTIMEEMPLOYEE
FULLTIMEEMPLOYEE
finally table per class says that every concrete class gets its own table and it will repeat all the inherited state in that table.
vertical partitioning
limit number of columns per table
split large, infrequently used columns into a separate table
CREATE TABLE Customer ( user_id INT NOT NULL AUTO_INCREMENT, email VARCHAR(80) NOT NULL, display_name VARCHAR(50) NOT NULL, password CHAR(41) NOT NULL, first_name VARCHAR(25) NOT NULL, last_name VARCHAR(25) NOT NULL, address VARCHAR(80) NOT NULL, city VARCHAR(30) NOT NULL, province CHAR(2) NOT NULL, postcode CHAR(7) NOT NULL, interests TEXT NULL, bio TEXT NULL, signature TEXT NULL, skills TEXT NULL, PRIMARY KEY (user_id), UNIQUE INDEX (email)) ENGINE=InnoDB;
Less Frequently
referenced,
TEXT data
Frequently
referenced
CREATE TABLE Customer( user_id INT NOT NULL AUTO_INCREMENT, email VARCHAR(80) NOT NULL, display_name VARCHAR(50) NOT NULL, password CHAR(41) NOT NULL, PRIMARY KEY (user_id), UNIQUE INDEX (email)) ENGINE=InnoDB;
CREATE TABLE CustomerInfo ( user_id INT NOT NULL, first_name VARCHAR(25) NOT NULL, last_name VARCHAR(25) NOT NULL, address VARCHAR(80) NOT NULL, city VARCHAR(30) NOT NULL, province CHAR(2) NOT NULL, postcode CHAR(7) NOT NULL, interests TEXT NULL, bio TEXT NULL, signature TEXT NULL, skills TEXT NULL, PRIMARY KEY (user_id), FULLTEXT KEY (interests, skills)) ENGINE=MyISAM;
An example of vertical partitioning might be a table that contains a number of very wide text or BLOB columns that aren't addressed often being broken into two tables that has the most referenced columns in one table and the seldom-referenced text or BLOB data in another. limit number of columns per table split large, infrequently used columns into a separate one-to-one tableBy removing the VARCHAR column from the design, you actually get a reduction in query response time. Beyond partitioning, this speaks to the effect wide tables can have on queries and why you should always ensure that all columns defined to a table are actually needed.
Vertical partitioning
@Entitypublic class Customer {
int userid; String email;
String password; @OneToOne(fetch=LAZY) CustomerInfo info;
}@Entitypublic class CustomerInfo { int userid; String name; String
interests; @OneToOne(mappedBy= "CustomerInfo") Customer
customer;}
split large, infrequently used columns into a separate table
Scalability: Sharding - Application Partitioning
Cust_id 1-999
Cust_id 1000-1999
Cust_id 2000-2999
Web/AppServers
Sharding Architecture
Sharding =Horizontal partitioning
Split table by rows into partitions
Know what SQL is executed
Capture generated SQL:
persistence.xml file:
Find and fix problem SQL:
Watch for slow Queries
use the MySQL slow query log and use Explain
Can reveal problems such as a missing Indexes
Watch for Queries that execute too often to load needed data
Watch for loading more data than needed
You need to understand the SQL queries your application makes and evaluate their performance To Know how your query is executed by MySQL, you can harness the MySQL slow query log and use EXPLAIN. Basically you want to make your queries access less data: is your application retrieving more data than it needs, are queries accessing too many rows or columns? is MySQL analyzing more rows than it needs? Indexes are a good way to reduce data access. When you precede a SELECT statement with the keyword EXPLAIN, MySQL displays information from the optimizer about the query execution plan. That is, MySQL explains how it would process the SELECT, including information about how tables are joined and in which order. With the help of EXPLAIN, you can see where you should add indexes to tables to get a faster SELECT that uses indexes to find rows. You can also use EXPLAIN to check whether the optimizer joins the tables in an optimal order.Developers should run EXPLAIN on all SELECT statements that their code is executing against the database. This ensures that missing indexes are picked up early in the development process and gives developers insight into how the MySQL optimizer has chosen to execute the query.
MySQL Query Analyser
Find and fix problem SQL:
how long a query took
results of EXPLAIN statements
Historical and real-time analysis
query execution counts, run time
Its not just slow running queries that are a problem, Sometimes its SQL that executes a lot that kills your system
MySQL Query AnalyzerThe MySQL Query Analyzer is designed to save time and effort in finding and fixing problem queries. It gives DBAs a convenient window, with instant updates and easy-to-read graphics,The analyzer can do simple things such as tell you how long a recent query took and how the optimizer handled it (the results of EXPLAIN statements). But it can also give historical information such as how the current runs of a query compare to earlier runs.Most of all, the analyzer will speed up development and deployment because sites will use it in conjunction with performance testing and the emulation of user activity to find out where the choke points are in the application and how they can expect it to perform after deployment.The MySQL Query Analyzer saves time and effort in finding and fixing problem queries by providing: Aggregated view into query execution counts, run time, result sets across all MySQL servers with no dependence on MySQL logs or SHOW PROCESSLIST Sortable views by all monitored statisticsSearchable and sortable queries by query type, content, server, database, date/time, interval range, and "when first seen"Historical and real-time analysis of all queries across all serversDrill downs into sampled query execution statistics, fully qualified with variable substitutions, and EXPLAIN resultsThe new MySQL Query Analyzer was added into the MySQL Enterprise Monitor and it packs a lot of punch for those wanting to ensure their systems are free of bad running SQL code.let me tell you the two things I particularly like about it from a DBA perspective: 1. It's Global: If you have a number of servers, you'll love what Query Analyzer does for you. Even Oracle and other DB vendors only provide single-server views of bad SQL that runs across their servers. Query Analyzer bubbles to the top the worst SQL across all your servers which is a much more efficient way to work. No more wondering what servers you need to spend your time on or which have the worst code. 2. It's Smart: Believe it or not, sometimes it's not slow-running SQL that kills your system it's SQL that executes way more times than you think it is. You really couldn't see this well before Query Analyzer, but now you can. One customer already shaved double-digits off their response time by finding queries that were running more much than they should have been. And that's just one area Query Analyzer looks at; there's much more intelligence there too, along with other stats you can't get from the general server utilities.
Agenda
Entities
Entity Manager
Persistence Context
Queries
Transaction
Query Types 1
Named query
Like findByXXXX() from EntityBeans
Compiled by persistence engine
Created either with @NamedQuery or externalized in orm.xml
Dynamic query
Created dynamically by passing a query string to EntityManager
Query query = em.createQuery(select ...);
Beware of SQL injection, better to use with named parameters
q = em.createQuery(select e from Employee e WHERE + e.empId LIKE ' + id + ');
q = em.createQuery(select e from Employee e WHERE + e.empId LIKE ':id');q.setParameter(id, id);
NOT GOOD
GOOD
Query Types 2
Native query
Leverage the native database querying facilities
Not portable ties queries to database
Flush Mode
Controls whether the state of managed entities are synchronized before a query
Types of flush mode
AUTO immediate, default
COMMIT flush only when a transaction commits
NEVER need to invoke EntityManger.flush() to flush
//Assume JTA transactionOrder order = em.find(Order.class, orderNumber);em.persist(order);Query q = em.createNamedQuery(findAllOrders);q.setParameter(id, orderNumber);q.setFlushMode(FlushModeType.COMMIT);//Newly added order will NOT visibleList list = q.getResultList();
Agenda
Entities
Entity Manager
Persistence Context
Queries
Transaction
Transactions
Do not perform expensive and unnecessary operations that are not part of a transaction
Hurt performance
Eg. logging disk write are expensive, resource contention on log
Do not use transaction when browsing data
@TransactionAttribute(NOT_SUPPORTED)
Carol McDonald Java Architect
Sun Microsystems, Inc.
Page
Click to edit the title text format
Click to edit the outline text format
Second Outline Level
Click to edit the notes format
Page
Click to edit the outline text format
Second Outline Level
Third Outline Level
Fourth Outline Level
Fifth Outline Level
Sixth Outline Level
Seventh Outline Level
Eighth Outline Level
Ninth Outline Level
Click to edit the title text format
Click to edit the notes format
Page
Click to edit the title text format
Click to edit the outline text format
Second Outline Level
Third Outline Level
2007 JavaOneSM Conference | Session TS-4902 |
Click to edit the notes format
04/03/09
| JavaOne 2007 | Session XXXX
tx/sec
Extended1
Transactional0.49
CacheTypeRead-onlyRead-writeTransactional EHCachememory, diskYes OSCache memory, diskYes SwarmCacheclustered Yes JBoss Cacheclustered YesYes
???Page ??? (???)04/03/2009, 18:00:17Page /