当每个执行JDBC的类都需要执行回滚和提交的操作,如下:
那么如果有的DAO成功提交,有的需要回滚。但是service的操作需要是一个整体,不能部分成功,部分失败。所以事务管理应该以业务层的方法为单位,而不能以DAO层的单精度方法为单位。
所以应该将上图中的try...catch...语句执行的内容转到service中。但因为servlet对应一个service,service又被filter拦截,所以可以将事务提交转移到filter中,如下:
Notations:DAO1、2、3中的数据库连接Connection需要同一个。因此需要ThreadLocal本地线程。里面有set和get方法,将Connection设置到线程中。
OpenSessionFilter:
先写一个开始、提交和回滚事务的工具类,如下所示:
public class TransManager {
//本地线程存储连接方便各个DAO方法使用
private static ThreadLocal threadLocal=new ThreadLocal();
//开始事务
public void startTrans() throws SQLException {
this.getConnection().setAutoCommit(false);
}
//提交事务
public void commitTrans() throws SQLException {
this.getConnection().commit();
//因为这里的提交和回滚函数都是在filter处理响应的时候才执行,所以要执行关闭连接的操作
this.getConnection().close();
}
//回滚事务
public void rollTrans() throws SQLException {
this.getConnection().rollback();
this.getConnection().close();
}
private Connection getConnection() throws SQLException{
Connection con=threadLocal.get();
if(con==null){
//发现threadLocal里面没有connection,就获取并设置
//放在threadLocal里面就是为了一个DAO调用后再给下一个调用
con=DButil.getConnection();
threadLocal.set(con);
}
return con;
}
}
然后在Filter的doFilter方法中进行事务的管理
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
TransManager tm=new TransManager();
try {
tm.startTrans();
filterChain.doFilter(servletRequest,servletResponse);
tm.commitTrans();
} catch (SQLException e) {
try {
tm.rollTrans();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
ThreadLocal
ThreadLocal的set(obj)方法。源码如下:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}
首先获取了当前的线程。每个线程都有一个容器(ThreadLocalMap)。map.set(this)就是将ThreadLocal作为key,因为我们的组件中需要传输的对象可能有多个。后面的createMap是初始化Map。
set的源码如下:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
其中this指的是ThreadLocal对象,通过它才知道是哪个ThreadLocalMap。entry.value是获取工具箱。
Listener(监听器)
Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
部分示例:
1,ServletContextListener-监听ServletContext对象的创建和销毁的过程
2,HttpSessionListener-同理
3,ServletRequestListener
4,ServletContextAttributeListener-监听ServletContext的保存域的改动
5,HttpSessionBindingListener-监听某个对象在session中的绑定与移除