private static final EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal;
private static final Logger logger;
static {
emf = Persistence.createEntityManagerFactory("EjbTestPU");
threadLocal = new ThreadLocal<EntityManager>();
logger = Logger.getLogger("EjbTestPU");
logger.setLevel(Level.ALL);
}
public static EntityManager getEntityManager() {
EntityManager em = threadLocal.get();
if (em == null || !em.isOpen()) {
em = emf.createEntityManager();
threadLocal.set(em);
}
return em;
}
public static void closeEntityManager() {
EntityManager em = threadLocal.get();
threadLocal.set(null);
if (em != null && em.isOpen()) {
em.close();
}
}
public static void beginTransaction() {
getEntityManager().getTransaction().begin();
}
public static void commit() {
getEntityManager().getTransaction().commit();
}
public static void rollback() {
getEntityManager().getTransaction().rollback();
}
public static Query createQuery(String query) {
return getEntityManager().createQuery(query);
}
}
然后呢,所有需要或者不需要事务操作的地方都可以这样写:
try {
EntityManagerHelper.beginTransaction();
// 这里是自己的数据库操作
EntityManagerHelper.commit();
System.out.println("提交成功!");
} catch (Exception e) {
System.out.println("提交异常:" + e);
try {
EntityManagerHelper.rollback();
System.out.println("回滚成功");
} catch (Exception ex) {
System.out.println("回滚异常:" + ex);
}
} finally {
EntityManagerHelper.closeEntityManager();
}
其中重点要注意的地方就是 rollback也需要捕获异常。只有捕获了所有异常,程序才不会“飞”掉。
很显然,如果程序中所有实体操作的地方都这样写,不累死才怪呢,所以可以写这样一个抽象类封装异常处理:
public abstract class Transaction {
final static Logger logger = Logger.getLogger(Transaction.class);
public abstract void run();
public void start() {
EntityManagerHelper EntityManagerHelper = EntityManagerHelper.getInstance();
try {
EntityManagerHelper.beginTransaction();
run();
EntityManagerHelper.commit();
logger.info("事务提交成功");
} catch (Exception e) {
System.out.println("事务提交异常:" + e);
try {
EntityManagerHelper.rollback();
System.out.println("事务回滚成功");
} catch (Exception ex) {
System.out.println("事务回滚异常:" + ex);
}
} finally {
EntityManagerHelper.closeEntityManager();
}
}
}
使用的时候只需要继承此抽象类即可,例如:
(new Transaction() {
@Override
public void run() {
// 这里是自己的数据库操作
}
}).start();
还有一种方法:
在EntityManagerHepler中新建一个方法doTransaction,这样貌似更符合Java的一般习惯:
public void doTransaction(Runnable runnable) {
try {
EntityManagerHelper.beginTransaction();
runnable.run();
EntityManagerHelper.commit();
logger.info("事务提交成功");
} catch (Exception e) {
logger.error("事务提交异常:" + e);
try {
EntityManagerHelper.rollback();
logger.info("事务回滚成功");
} catch (Exception ex) {
logger.error("事务回滚异常:" + ex);
}
} finally {
EntityManagerHelper.closeEntityManager();
}
}
进一步,Exception可以细化成PersistenceException,这样避免和其它异常相混淆,再加上后来查JavaDoc发现漏掉两个异常,所以这样应该完美了:
public void doTransaction(Runnable runnable) {
try {
EntityManagerHelper.beginTransaction();
runnable.run();
EntityManagerHelper.commit();
logger.info("事务执行成功");
} catch (PersistenceException e) {
logger.error("持久化异常:" + e);
try {
EntityManagerHelper.rollback();
logger.info("事务回滚成功");
} catch (Exception ex) {
logger.error("事务回滚异常:" + ex);
}
} catch (IllegalStateException e) {
logger.error("非法状态异常:" + e);
try {
EntityManagerHelper.rollback();
logger.info("事务回滚成功");
} catch (Exception ex) {
logger.error("事务回滚异常:" + ex);
}
} catch (IllegalArgumentException e) {
logger.error("非法参数异常:" + e);
try {
EntityManagerHelper.rollback();
logger.info("事务回滚成功");
} catch (Exception ex) {
logger.error("事务回滚异常:" + ex);
}
} finally {
EntityManagerHelper.closeEntityManager();
}
}
使用的时候有两点需要注意:
1、Runnable中应该避免抛出PersistenceException中包含的两个子异常NonUniqueResultException, NoResultException,解决方法是禁用Query.getSingleResult()方法,取而代之以getResultList()方法 - 这应该是一个好习惯。
2、Runnable如果有异常捕获的结构,注意不要捕获通用的Exception异常,而应该具体异常具体对待,避免“吃掉”JPA的异常 - 这也应该是一个好习惯。
首先得用到封装了基本实体操作的EntityManagerHelper类,这在网上到处都是:
public class EntityManagerHelper {