EJB3之JPA程序结构,完美的异常处理

09-08-29 mallon
首先得用到封装了基本实体操作的EntityManagerHelper类,这在网上到处都是:

public class EntityManagerHelper {

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() {

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();

         

mallon
2009-08-29 20:08
还有一种方法:

在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 {

emh.beginTransaction();

runnable.run();

emh.commit();

logger.info("事务执行成功");

} catch (PersistenceException e) {

logger.error("持久化异常:" + e);

try {

emh.rollback();

logger.info("事务回滚成功");

} catch (Exception ex) {

logger.error("事务回滚异常:" + ex);

}

} catch (IllegalStateException e) {

logger.error("非法状态异常:" + e);

try {

emh.rollback();

logger.info("事务回滚成功");

} catch (Exception ex) {

logger.error("事务回滚异常:" + ex);

}

} catch (IllegalArgumentException e) {

logger.error("非法参数异常:" + e);

try {

emh.rollback();

logger.info("事务回滚成功");

} catch (Exception ex) {

logger.error("事务回滚异常:" + ex);

}

} finally {

emh.closeEntityManager();

}

}

使用的时候有两点需要注意:

1、Runnable中应该避免抛出PersistenceException中包含的两个子异常NonUniqueResultException, NoResultException,解决方法是禁用Query.getSingleResult()方法,取而代之以getResultList()方法 - 这应该是一个好习惯。

2、Runnable如果有异常捕获的结构,注意不要捕获通用的Exception异常,而应该具体异常具体对待,避免“吃掉”JPA的异常 - 这也应该是一个好习惯。

[该贴被mallon于2009-08-29 20:13修改过]

[该贴被mallon于2009-08-29 20:19修改过]

mallon
2009-08-29 20:08
呵呵处女作,欢迎指教

xmuzyu
2009-08-29 23:56
为什么不采取容器自动注入entityManager呢?这样不用自己管理,并且切换到JTA事务的时候,也不用我们自己动手。

mallon
2009-08-30 06:57
是在J2SE环境下使用的...

猜你喜欢