由于dao的设计粒度比manager要细,所以一个manager会调用多个dao的方法,这些方法要么要执行成功,要么都不执行。这时候就要引入事务。如下图:
但是类那么多,每个写这几句话不仅很麻烦,而且还不好去管理。这时就引入了动态的代理模式来封装这些代码。
1、首先建立一个代理类实InvocationHandler接口。
2、定义目标对象,在newProxyInstance方法中传入目标对象,并调用
Proxy的newProxyInstance方法。该方法有三个参数
(1)目标对象类加载器
(2)目标对象的接口
(3)把代理类传进去
3、重写invoke方法。
如下图:
public class TransactionHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object tarObject) {
this.targetObject=tarObject;
return Proxy.newProxyInstance(tarObject.getClass().getClassLoader(),
tarObject.getClass().getInterfaces() ,
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Connection conn=null;
Object ret=null;
try{
//从ThreadLocal中获得connection
conn=ConnectionManager.getConnection();
if(method.getName().startsWith("add")||
method.getName().startsWith("del")||
method.getName().startsWith("modify")){
//手动控制事务
ConnectionManager.beginTransaction(conn);
}
//调用业务逻辑方法
ret= method.invoke(targetObject, args);
if(conn.getAutoCommit()==false){
ConnectionManager.commitTransaction(conn);
}
}catch(ApplicationException e){
ConnectionManager.rollbackTransaction(conn);
throw e;
}
catch(Exception e){
if(e instanceof InvocationTargetException){
InvocationTargetException ete=(InvocationTargetException)e;
throw ete.getTargetException();
}
e.printStackTrace();
ConnectionManager.rollbackTransaction(conn);
throw new ApplicationException("操作失败");
}finally{
ConnectionManager.closeConnection();
}
return ret;
}
}
代理类写好以后,在上几篇博客中曾说过把service(就是manager)放入工厂中实现。那么现在在工厂中把生成好的service用代理包装,就可以相当于service的代理类。
try {
service= Class.forName(className).newInstance();
//采用动态代理包装service
TransactionHandler transactionHandler=new TransactionHandler();
service= transactionHandler.newProxyInstance(service);
//将创建的对象放入map中
serviceMap.put(s.getName(), service);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
return service;
以后manager类就只用关系业务逻辑了,也不用关系conn等的资源有没有释放等问题,代码就简洁了。
try{
//生成流向单单号
String flowCardVouNo=flowCardDao.generateVouNo();
//添加流向单主信息
flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);
//添加流向单明细信息
flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
}catch(DaoException e){
throw new ApplicationException("添加流向单失败");
}