小议JPA
以前和数据库打交道的标准INTERFACE是JDBC,放SQL语句,执行,就可以有结果。随着近年ORM的兴起,以对象的方式存取数据库大行其道。于是产生了JPA。也是一套INTERFACE,以ORM的方式提供,由厂商实现,如ECLIPSE LINK,HIBERNATE,OPENEJB等。
ENTITYMANAGERFACTORY:根据配置文件制造ENTITYMANAGER
ENTITYMANAGER:以ORM的方式提供操作数据库的功能
TRANSACTION:事务保证
PERSISTENCE.XML:链接数据库信息,事务类型,重定义JPA的实现厂商等的配置信息
在容器环境下使用:
如果事务是RESOURCE_LOCAL的方式,则合用端需干所有的事情,如构造ENTITYMANAGER,打开事务,关闭事务等。类似于BMT。
以下是在服务器环境中合用RESOURCE_LOCAL型的JPA
事先要在容器中添加数据源。
persistence.xml
<?
xml version="1.0" encoding="UTF-8"
?>
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
<!-- Tutorial "unit" -->
< persistence-unit name ="Tutorial" transaction-type ="RESOURCE_LOCAL" >
< non-jta-data-source >myNonJtaDataSource </ non-jta-data-source >
< class >org.superbiz.jpa.Account </ class >
</ persistence-unit >
</ persistence >
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
<!-- Tutorial "unit" -->
< persistence-unit name ="Tutorial" transaction-type ="RESOURCE_LOCAL" >
< non-jta-data-source >myNonJtaDataSource </ non-jta-data-source >
< class >org.superbiz.jpa.Account </ class >
</ persistence-unit >
</ persistence >
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceUnit;
public class MyEjbOrServlet {
@PersistenceUnit(unitName="Tutorial")
private EntityManagerFactory factory;
// Proper exception handling left out for simplicity
public void ejbMethodOrServletServiceMethod() throws Exception {
EntityManager entityManager = factory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
Account account = entityManager.find(Account. class, 12345);
account.setBalance(5000);
entityTransaction.commit();
}
}
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceUnit;
public class MyEjbOrServlet {
@PersistenceUnit(unitName="Tutorial")
private EntityManagerFactory factory;
// Proper exception handling left out for simplicity
public void ejbMethodOrServletServiceMethod() throws Exception {
EntityManager entityManager = factory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
Account account = entityManager.find(Account. class, 12345);
account.setBalance(5000);
entityTransaction.commit();
}
}
以下是JTA方式的JPA,容器+EJB+JPA+JTA,容器会在EJB的方法调用前打开一个事务,在方法退出后,提交事务,并且如果是多个数据源的,即有多个ENTITYMANAGER的
可以保证一致性,即全局事务。相当于之前的先调用USERTRANSACTION,BEGIN,COMMIT。
事先要在容器中添加数据源。
persistence.xml
<?
xml version="1.0" encoding="UTF-8"
?>
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
<!-- Tutorial "unit" -->
< persistence-unit name ="Tutorial" transaction-type ="JTA" >
< jta-data-source >myJtaDataSource </ jta-data-source >
< non-jta-data-source >myNonJtaDataSource </ non-jta-data-source >
< class >org.superbiz.jpa.Account </ class >
</ persistence-unit >
</ persistence >
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
<!-- Tutorial "unit" -->
< persistence-unit name ="Tutorial" transaction-type ="JTA" >
< jta-data-source >myJtaDataSource </ jta-data-source >
< non-jta-data-source >myNonJtaDataSource </ non-jta-data-source >
< class >org.superbiz.jpa.Account </ class >
</ persistence-unit >
</ persistence >
EJB
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class MyEjb implements MyEjbInterface {
@PersistenceContext(unitName = "Tutorial")
private EntityManager entityManager;
// Proper exception handling left out for simplicity
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void ejbMethod() throws Exception {
Account account = entityManager.find(Account. class, 12345);
account.setBalance(5000);
}
}
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class MyEjb implements MyEjbInterface {
@PersistenceContext(unitName = "Tutorial")
private EntityManager entityManager;
// Proper exception handling left out for simplicity
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void ejbMethod() throws Exception {
Account account = entityManager.find(Account. class, 12345);
account.setBalance(5000);
}
}
如果是J2SE环境下使用JPA,则又是不一样的。
persistence.xml
<?
xml version="1.0" encoding="UTF-8"
?>
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
< persistence-unit name ="SimplePU" transaction-type ="RESOURCE_LOCAL" >
< provider >org.hibernate.ejb.HibernatePersistence </ provider >
< class >com.someone.jmail.valueobject.CallActivity </ class >
< class >com.someone.jmail.valueobject.Email </ class >
< properties >
< property name ="hibernate.connection.driver_class" value ="com.mysql.jdbc.Driver" />
< property name ="hibernate.connection.url" value ="jdbc:mysql://localhost:3306/test" />
< property name ="hibernate.connection.username" value ="root" />
< property name ="hibernate.connection.password" value ="12345" />
< property name ="hibernate.dialect" value ="org.hibernate.dialect.MySQL5Dialect" />
< property name ="hibernate.show_sql" value ="false" />
< property name ="hibernate.format_sql" value ="true" />
< property name ="hibernate.use_sql_comments" value ="false" />
< property name ="hibernate.hbm2ddl.auto" value ="none" />
</ properties >
</ persistence-unit >
</ persistence >
< persistence xmlns ="http://java.sun.com/xml/ns/persistence" version ="1.0" >
< persistence-unit name ="SimplePU" transaction-type ="RESOURCE_LOCAL" >
< provider >org.hibernate.ejb.HibernatePersistence </ provider >
< class >com.someone.jmail.valueobject.CallActivity </ class >
< class >com.someone.jmail.valueobject.Email </ class >
< properties >
< property name ="hibernate.connection.driver_class" value ="com.mysql.jdbc.Driver" />
< property name ="hibernate.connection.url" value ="jdbc:mysql://localhost:3306/test" />
< property name ="hibernate.connection.username" value ="root" />
< property name ="hibernate.connection.password" value ="12345" />
< property name ="hibernate.dialect" value ="org.hibernate.dialect.MySQL5Dialect" />
< property name ="hibernate.show_sql" value ="false" />
< property name ="hibernate.format_sql" value ="true" />
< property name ="hibernate.use_sql_comments" value ="false" />
< property name ="hibernate.hbm2ddl.auto" value ="none" />
</ properties >
</ persistence-unit >
</ persistence >
Dao:
public
class UserDaoImpl
implements UserDao {
public AccountInfo save(AccountInfo accountInfo) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("SimplePU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(accountInfo);
em.getTransaction().commit();
emf.close();
return accountInfo;
}
}
public AccountInfo save(AccountInfo accountInfo) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("SimplePU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(accountInfo);
em.getTransaction().commit();
emf.close();
return accountInfo;
}
}