DevEX - reference for building teams, processes, and platforms
Java Persistence API
1. Enterprise JavaBean 3.0 & Java Persistence APIs: Simplifying Persistence Carol McDonald Java Architect Sun Microsystems
2.
3.
4.
5.
6. Entity Annotated as “Entity” @Id denotes primary key @Entity public class Customer implements Serializable { @Id protected Long id; protected String name; public Customer() {} public Long getId() {return id;} public String getName() {return name;} public void setName(String name) {this.name = name;} … }
7.
8. An Example Data Model Maps entity states to data store Maps relationship to other entities Customer int id String name int c_rating Image photo Set<Order> orders Collection<Phone> phones ... Order int id Customer cust ... Phone int id Collection<Customer> custs ... 1 M M N
9. Simple Mapping Mapping defaults to matching column name . Only configure if entity field and table column names are different public class Customer { int id; String name; int c_rating; Image photo; } @Entity(access=FIELD) @Column(name=“CREDIT”) @Id @Lob CUSTOMER ID NAME CREDIT PHOTO
10. Entity Annotated as “Entity” @Id denotes primary key @Entity public class Customer implements Serializable { @Id protected Long id; protected String name; @Transient protected int reservationCount; public Customer() {} public Long getId() {return id;} public String getName() {return name;} public void setName(String name) {this.name = name;} … }
11. Entity Class for Customer @Entity(access=FIELD) @Table(name = “customer”) public class Customer { @Id public int id; ... public String name; @Column(name=”CREDIT”) public int c_rating; @LOB public Image photo; ... } Annotated as “Entity” Data are accessed as fields @Id denotes primary key Maps to “customer” table Specify the table column to map to
14. Relationship Mappings – OneToMany Bidirectional public class Order { int id; ... Customer cust ; } public class Customer { int id; ... Set<Order> orders; } @Entity(access=FIELD) @Entity(access=FIELD) @ManyToOne @OneToMany(mappedBy=“ cust ”) @Id @Id 1 n has to say where the foreign key is using mappedBy CUSTOMER ID . . . ORDER CUST_ID ID . . .
15.
16. Relationship Mappings – ManyToOne Automatically creates a ADDR_ID field for mapping. Can be overridden via @ManyToOne annotation public class Customer { int id; Address addr ; } CUSTOMER ADDR_ID ID ADDRESS . . . ID @Entity(access=FIELD) @ManyToOne @Id ADDR_ID
17. Relationship Mappings – ManyToMany public class Customer { int id; ... Collection<Phone> phones ; } @Entity(access=FIELD) @Entity(access=FIELD) @Id @Id @ManyToMany @ManyToMany(mappedBy=“phones”) public class Phone { int id; ... Collection<Customer> custs ; } Join table name is made up of the 2 entities. Field name is the name of the entity plus the name of the PK field PHONES _ID CUSTS _ID CUSTOMER ID . . . PHONE ID . . . CUSTOMER_PHONE ID
18. Relationship Mappings – ManyToMany Can override the default column names PHONES_ID CUST_ID CUSTOMER ID . . . PHONE ID . . . CUST_PHONE @Entity(access=FIELD) public class Customer { ... @ManyToMany @ JoinTable (table=@Table(name=“CUST_PHONE”), joinColumns =@JoinColumn(name=“CUST_ID”), inverseJoinColumns =@JoinColumn(name=“PHONES_ID”)) Collection<Phone> phones; }
19.
20. Mapping of Embedded Objects @Entity(access=FIELD) @Embedded @Id @Embeddable(access=FIELD) public class CustomerInfo { String name; int credit; @Lob Image photo; } public class Customer { int id ; CustomerInfo info; } Embedded objects have no identity of their own . Takes on the identity of the container object CUSTOMER ID NAME CREDIT PHOTO
21.
22. Entity Inheritance – (Abstract) Entity Class @Entity public abstract class Person { @Id protected Long id; protected String name; @Embedded protected Address address; } @Entity public class Customer extends Person { @Transient protected int orderCount; @OneToMany protected Set<Order> orders = new HashSet(); } @Entity public class Employee extends Person { @ManyToOne protected Department dept; }
23.
24. Entity Inheritance – Mapped Superclass @MappedSuperclass public class Person { @Id protected Long id; protected String name; @Embedded protected Address address; } @Entity public class Customer extends Person { @Transient protected int orderCount; @OneToMany protected Set<Order> orders = new HashSet(); } @Entity public class Employee extends Person { @ManyToOne protected Department dept; }
25.
26. Entity Inheritance – Non Entity Class public class Person { protected String name; } @Entity public class Customer extends Person { //Inherits name but not persisted @Id public int id; @Transient protected int orderCount; @OneToMany protected Set<Order> orders = new HashSet(); } @Entity public class Employee extends Person { //Inherits name but not persisted @Id public int id; @ManyToOne protected Department dept; }
27.
28. Inheritance mapping strategies Object Model AirAnimal wingSpan: int LandAnimal legCount: int Animal id: int name: String
29.
30. Discriminator Column and Value for Single Table @Entity @Table(name="ANIMAL") @Inheritance(strategy=SINGLE_TABLE) @DiscriminatorColumnName(name=”DISC”) @DiscriminatorValue(“ANIMAL”) public class Animal { @Id protected int id; protected String name; ... } @Entity @DiscriminatorValue("LANDANIMAL") public class LandAnimal extends Animal { @Column(name=”LEG_CNT”) protected int legCount; ... ANIMAL LEG_CNT ID DISC NAME WING_SPAN
35. Example of orm.xml File <entity-mappings> <entity class=”Customer”> <id name=”id”> <generated-value/> </id> <basic name=”c_rating”> <column name=”ratings”/> </basic> ... <one-to-many name=”orders” mapped-by=”cust”/> </entity> ... </entity-mappings> Overriding the default annotations in source
36.
37.
38. Persistence Unit Persistence Context Persistence Context Primary interface to interact with underlying persistence engine A set of entities associated with a particular transaction Configuration for entities mapped to a single data store Persistence Unit MyApp Employee e = new Employee(); e.setName(“Lucas”); em.persist(e); persistence.xml
39.
40.
41. EntityManager Persistence Context Persistence Context Primary interface to interact with underlying persistence engine A set of managed entities associated with a particular transaction Configuration for entities mapped to a single data store Persistence Unit MyApp Employee e = new Employee(); e.setName(“Lucas”); em.persist(e); persistence.xml
45. EntityManager Example @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) { return ( entityManager.merge ( orderLine ) ); } } Dependency injection
46.
47.
48. Entity Lifecycle Illustrated – The Code @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 newOL= entityManager.merge(orderLine) return ( newOL ) ); } } New entity Managed entity Detached entity
49.
50. Cascading Persist example: ManyToOne public class Order { int id; ... Customer cust ; } public class Customer { int id; ... Set<Order> orders; } @Entity(access=FIELD) @Entity(access=FIELD) @ManyToOne @OneToMany(mappedBy=“cust”) @Id @Id CUSTOMER ID . . . ORDER CUST_ID ID . . .
51. Persist OneToMany bi-directional Not Cascading em.persist to persist the order @Stateless public class OrderManagementBean implements OrderManagement { … @PersistenceContext EntityManager em; … public Order addNewOrder (Long id,Product product){ Customer cust = em.find (Customer.class, id); Order order = new Order(product); customer.getOrders().add(order); order.setCustomer(cust); em.persist(order); return order; } }
52. Cascading Persist cascade=Persist Order persisted automatically, when added to Customer @Entity public class Customer { @Id protected Long id; … @OneToMany(cascade=PERSIST) protected Set<Order> orders = new HashSet(); } … public Order addNewOrder(Customer customer, Product product) { Order order = new Order(product); customer.getOrders().add(order); order.setCustomer(cust); return order; }
53.
54. Remove When order is removed, the lineItems are removed with it @Entity public class Order { @Id protected Long orderId; … @OneToMany(cascade={PERSIST,REMOVE}) protected Set<LineItem> lineItems = new HashSet(); } … @PersistenceContext EntityManager em; … public void deleteOrder(Long orderId) { Order order = em.find(Order.class, orderId); em.remove(order); }
55.
56. Merge When order is merged, the lineItems are merged with it @Entity public class Order { @Id protected Long orderId; … @OneToMany(cascade={PERSIST, REMOVE, MERGE}) protected Set<LineItem> lineItems = new HashSet(); } … @PersistenceContext EntityManager em; … public Order updateOrder(Order changedOrder) { return em.merge(changedOrder); }
57.
58. Types of Persistence Context and Entity Managers Persistence Context Entity Manager Persistence Context Entity Manager Data source same entity
59.
60.
61.
62. Java™ Transaction Service Application Server Transaction Service Application UserTransaction interface Resource Manager XAResource interface Transactional operation TransactionManager Interface Resource EJB Transaction context
65. Spring 2.0 & JPA @Repository @Transactional public class CatalogDAO implements CatalogService { @PersistenceContext (unitName="PetCatalogPu") private EntityManager em; public List<Item> getItems (int firstItem,int batchSize) { Query q = em. createQuery("select object(o) from Item as o"); q.setMaxResults(batchSize); q.setFirstResult(firstItem); List<Item> items= q.getResultList(); return items; }
66.
67.
68. Declarative Transaction Management Example TX_REQUIRED TX_REQUIRED TX_REQUIRED PC PC PC Session Facade Inventory Service Order Service Check Out 1. Update Inventory New Persistence Context Persistence Context Propagated Transaction Attributes 2. Create Order and send JMS message to Warehouse Application
69.
70.
71. Transaction Example Application Server Transaction Manager Transaction context DataBase Server and JMS Provider Resource Client Controller Inventory Order 1) Check Out TX_REQUIRED TX_REQUIRED BEGIN 4) Update Inventory 7) createOrder 11) Check context x to see if updates will work 12) Commit or rollback Start Prepare 10) END
72.
73.
74.
75. Web JTA Transaction and Container EM protected void buyBook(String book, int custId, String creditCard) throws … { utx.begin(); Customer customer = new CustomerHelper (). getCustomer (custId); Order order = new OrderHelper (). create (book, creditCard, customer); utx.commit(); } JTA
76. Web JTA Transaction and Container EM EM public Order create (String book, String creditCard, Customer customer) { EntityManager em = (EntityManager) new InitialContext() .lookup(“java:comp/env/persistence/bookStore”); Order order = new Order(customer); order.setCreditCard(creditCard); order.setBook(book); em.persist (order); } //CustomerHelper public Customer getCustomer (int id) { EntityManager em = (EntityManager) new InitialContext().lookup( “ java:comp/env/persistence/bookStore”); return em.find (Customer.class, id); } // OrderHelper
77.
78.
79. Stateless Session and Container EM No need for JNDI lookup of EM No need for Transaction Management @Stateless public class OrderMgrBean implements OrderMgr { @PersistenceContext EntityManager em; create(String book, String creditCard, Customer cust) { Order order = new Order(cust); order.setCreditCard(creditCard); order.setBook(book); em.persist(order); } } @Stateless public class CustomerMgrBean implements CustomerMgr { @PersistenceContext EntityManager em; public Customer getCustomer(int id) { return em.find(Customer.class, id); } }
80.
81. Extended Persistence Context @Stateful public class ShoppingCart { //Specify that we want an EXTENDED @PersistenceContext (type=PersistenceContextType.EXTENDED) EntityManager em ; //Cached order private Order order ; //Find and cache order public void lookupOrder(String id) { //order remains managed for the lifetime of the bean order = em.find(Order.class, id); }
82. Persistence Context- Transactional vs. Extended @Stateless public class OrderSessionStateless implements OrderService { @PersistenceContext(unitName=”java_one”) EntityManager em; public void addLineItem (OrderLineItem li){ // First, look up the order. Order order = em.find(Order.class, orderID); order.lineItems.add(li); } @Stateful public class OrderSessionStateful implements OrderService { @PersistenceContext(type = PersistenceContextType. EXTENDED )) EntityManager em; // Order is a member variable Loaded from the db in lookupOrder Order order public void addLineItem (OrderLineItem li){ // No em.find invoked for the order object order.lineItems.add(li); }
83.
84. Conversation @Stateful public class OrderBean { @PersistenceContext(type=EXTENDED) EntityManager em ; public void add(String itemCode, int qty) { ... } public void confirmOrder() { ... } ... } ________________________________________________________________ protected void doPost(HttpServletRequest req, ...) throws ... { String cmd = req.getParameter(“cmd”); if (cmd.equals(“NEW”)) { //Create stateful session bean, hold in HttpSession req.getSession().setAttribute(“order”, orderBean); } else if (cmd.equals(“ADD_ITEM”)) { //Add item to order bean orderBean.add(...); } else if (cmd.equals(“CONFIRM”)) { orderBean.confirmOrder(); order.remove(); req.getSession().removeAttribute(“order”); }
85. Persistence Context Source: Internal benchmarks Does it affect performance? Micro benchmark with lots of lookups
86.
87.
88. Data Base Transaction Management Transaction Manager EJB Container Resource Manager Data Base JTA A S EJB Local Servlet JDBC Transactions JTA Transactions servlet Resource Manager EJB servlet servlet servlet Java SE
89. Application managed Entity Manager and JTA Transaction ( Web ) @Resource UserTransaction utx; @PersistenceUnit EntityManagerFactory factory; public void createDistributor(String n) { //Begin transaction utx.begin(); EntityManager em = emf.createEntityManager() ; //Create entity Distributor dist = new Distributor(); dist.setName(n); //Save it em.persist( dist ) ; //Commit transaction and close EntityManager utx.commit(); em.close() ; }
90. Application Managed EM Extended Persistence Context Helper public class ExtendedPersistenceContextServlet extends HttpServlet { @PersistenceUnit EntityManagerFactory emf; public EntityManager getEntityManager (HttpSession s) { EntityManager em = s.getAttribute(“entityManager”); if (em==null) { em = emf.createEntityManager(); s.setAttribute(“entityManager”, em); } em.joinTransaction(); return em; } public void endConversation (HttpSession s) { getEntityManager().close(); s.removeAttribute(“entityManager”); }
91.
92.
93.
94. RESOURCE_LOCAL Transaction Java SE // Create EntityManagerFactory for a persistence unit // called manager1 EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1"); EntityManager em = emf.createEntityManager(); // Get a transaction instance and start the transaction EntityTransaction tx = em.getTransaction(); // Create a new customer,persist and commit it. tx.begin(); Distributor dist = new Distributor(); dist.setName("Joe Smith"); em.persist(dist); tx.commit(); em.close(); emf.close();
95.
96.
97.
98.
99.
100.
101.
102. Dynamic Queries public List findWithName (String name) { Query query = em.createQuery ( “ SELECT c FROM Customer c” + “ WHERE c.name LIKE :custName ”) query.setParameter(“ custName ”, name); query.setMaxResults(10); return (query.getResultList()); }
113. Executing a Query Outside of a Transaction @Stateless public class QueryServiceBean implements QueryService { @PersistenceContext(unitName="EmployeeService") EntityManager em; @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public List findAllDepartmentsDetached() { return em.createQuery("SELECT d FROM Department d") .getResultList(); } // ... }
129. Entity merge Don't @Entity public class Order { @OneToMany(cascade=CascadeType.ALL, ...) public Collection<OrderLineItem> getLineItems(){ return lineItems; } } @Stateless public class OrderSessionStateless { @PersistenceContext private EntityManager em; public void applyDiscount( Collection<OrderLineItem> lis){ applyDiscount(lis); em.merge(order); } }
130. Entity merge DO @Entity public class Order { @OneToMany(cascade=CascadeType.ALL, ...) public Collection<OrderLineItem> getLineItems(){ return lineItems; } } @Stateless public class OrderSessionStateless { @PersistenceContext private EntityManager em; public void applyDiscount( Collection<OrderLineItem> lis){ for(OrderLineItem li : lis) { applyDiscount(li); em.merge(li); } } }
131.
132. Enterprise JavaBean 3.0 and Java Persistence APIs: Simplifying Persistence Carol McDonald [email_address] Sun Microsystems