A previous post about this topic: http://hilaltarakci.blogspot.com/2011/03/jpa-tips.html
But at least, i can recommend to buy the book and read the whole chapter..
In this post, i tried to summarize Java Persistence API: Best Practices slides prepared by Carol McDonald and available at http://www.slideshare.net/caroljmcdonald/td09jpabestpractices2.
Configure L2 caching for entities that are
protect any data that can be concurrently modified with a locking strategy
Configure Query cache
Navigating Entity Relationships
Data fetching strategy
· EAGER – immediate
· LAZY – loaded only when needed
· LAZY is good for large objects and/or with relationships with deep hierarchies
• 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 claus
Mapping Inheritance Hierarchies
• 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)
There is also a blog entry of the same writer about JPA caching, possibly initiated from the slides at http://www.slideshare.net/caroljmcdonald/td09jpabestpractices2 . (http://blogs.sun.com/carolmcdonald/entry/jpa_caching)
java.sql.Blob.. Indeed, the following error shows up when i tried to do so: // beanimport java.sql.Blob;import javax.persistence.Lob;
class MyClass{ @Lob @Column(name = "FLD_BLOB") private Blob myBlob;...}
// the error when deployed on Glassfish (jaxws is used for web services) javax.xml.ws.WebServiceException: Unable to create JAXBContext ... Caused by: java.security.PrivilegedActionException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptionsjava.sql.Blob is an interface, and JAXB can't handle interfaces. this problem is related to the following location: at java.sql.Blob at public java.sql.Blob ...java.sql.Blob does not have a no-arg default constructor....java.sql.Blob is an interface, and JAXB can't handle interfaces....byte [] instead of java.sql.Blob < xs:element name= " myBlob " type= " xs:base64Binary " minoccurs= " 0 " > byte []..FileOutputStream fos = new FileOutputStream( "blobDataReadFromDB.png");fos.write(myBean.getMyBlob());ERROR org.hibernate.util.JDBCExceptionReporter - Large Objects may not be used in auto-commit mode. ...sun-org.hibernate.exception.GenericJDBCException: could not execute query at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)....Caused by: org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode. at org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:200) You might need to put your DB operations into a transaction:
session.beginTransaction();
...
session.getTransaction().commit();
Normally, retrieve operations do not require a transaction since they leave the database unchanged.. You only use transactions for create, update and delete operations since they change database state.. However, retrieval of blob field require transaction as well, maybe due to paging..
I also used and tested the blob field through a bpel process.. Again, persistence and retrieval is successful..// general superclass @MappedSuperclasspublic class MyBean implements Serializable {
@Id @GeneratedValue(strategy = GenerationType.TABLE) private Long id = -1L; // ...}
//////////////////////////////////////////////////////////////// a specific classpublic class SpecificBean extends MyBean {// ...
//////////////////////////////////////////////////////////////// entity manager classpublic class MyEntityManager {
private static final String PERSISTENCE_UNIT = "MyPU";
@PersistenceUnit(unitName = PERSISTENCE_UNIT) private EntityManagerFactory emf;
public EntityManager getEm() { if (emf == null) { emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT); } return emf.createEntityManager(); }}
//////////////////////////////////////////////////////////////// general dao for superclass MyBeanpublic class MyBeanDao {
private Class clazz; protected EntityManager em;
public MyBeanDao(Class clazz, EntityManager em) { this.clazz = clazz; this.em = em; }
public void create(MyBean bean) { em.persist(bean); }
public MyBean retrieve(Long id) { return (MyBean) em.find(this.clazz, id); }
public void remove(Long id) { MyBean bean = retrieve(id); if (bean != null) { em.remove(bean); } }
public MyBean update(MyBean bean) { MyBean updated = em.merge(bean); return updated; }
public void closeEm() { em.close(); }
public void initTransaction() { em.getTransaction().begin(); }
public void finishTransaction() { em.getTransaction().commit(); }
public void rollbackTransaction() { em.getTransaction().rollback(); }}
//////////////////////////////////////////////////////////////// specific dao classespublic class SpecificDao extends MyBeanDao {
public SpecificDao (EntityManager em) { super(SpecificBean.class, em); } // extra methods }
//////////////////////////////////////////////////////////////// sample call
MyEntityManager mem = new MyEntityManager ();EntityManager em = mem.getEm();
SpecificDao dao = new SpecificDao (em);
dao.initTransaction();// do something// ....dao.finishTransaction();
@OneToMany(cascade = CascadeType.ALL) @JoinTable(name = "TBL_INCIDENT_ABSEVIDGRP", joinColumns = { @JoinColumn(name = "FLD_INCIDENT_ID") }, inverseJoinColumns = { @JoinColumn(name = "FLD_ABSEVIDGRP_ID") }) private List childList = new ArrayList(); @ManyToOne @JoinTable(name = "TBL_INCIDENT_ABSEVIDGRP", joinColumns = { @JoinColumn(name = "FLD_ABSEVIDGRP_ID") }, inverseJoinColumns = { @JoinColumn(name = "FLD_INCIDENT_ID") }) private Parent parent;Error while commiting the transactionjavax.persistence.RollbackException: Error while commiting the transaction at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:71)...Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Child Entity
Testcase: emptyTest(entity.PersonTest): Caused an ERROR[PersistenceUnit: SchuchertJpaTutor1PU] Unable to build EntityManagerFactoryjavax.persistence.PersistenceException: [PersistenceUnit: SchuchertJpaTutor1PU] Unable to build EntityManagerFactory at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:677) at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:126) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33) at entity.PersonTest.initEmfAndEm(PersonTest.java:24)Caused by: org.hibernate.HibernateException: Could not find datasource at org.hibernate.connection.DatasourceConnectionProvider.configure(DatasourceConnectionProvider.java:56) at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:124) at org.hibernate.ejb.InjectionSettingsFactory.createConnectionProvider(InjectionSettingsFactory.java:29) at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:62) at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2009) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1292) at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:859) at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669)Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325) at javax.naming.InitialContext.lookup(InitialContext.java:392) at org.hibernate.connection.DatasourceConnectionProvider.configure(DatasourceConnectionProvider.java:52)
Testcase: emptyTest(entity.PersonTest): Caused an ERRORnulljava.lang.NullPointerException at entity.PersonTest.cleanup(PersonTest.java:31)Test entity.PersonTest FAILED<?xml version="1.0" encoding="UTF-8"?><persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"><persistence-unit name="SchuchertJpaTutor1TestPU" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <non-jta-data-source></non-jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa"/> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <property name="hibernate.connection.username" value="sa"/> <property name="hibernate.connection.password" value=""/> </properties> </persistence-unit></persistence>hsqldb.jar and (possibly) servlet.jar to test libs ClassA which ClassB inherits from.. and there is a ClassC which inherits from ClassB..ClassB, for all hierarchy, the inheritance type specified for ClassA, the very root class, is used.
<?xml version="1.0" encoding="UTF-8"?>
<project name="projectname" default="generate-schema" basedir=".">
<path id="classpath">
<pathelement location="path/to/classes"/>
<fileset dir="/path/to/jaxb/lib">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="schemagen" classname="com.sun.tools.jxc.SchemaGenTask">
<classpath refid="classpath"/>
</taskdef>
<target name="generate-schema">
<schemagen srcdir="path/to/src" destdir="path/to/generatedfiles">
<classpath refid="classpath"/>
<schema namespace="http://namespace" file="nameOfMySchema.xsd" />
</schemagen>
</target>
</project>