在JAVAWeb工程中,需要利用JDBC对数据库进行交互,而如果在一次操作中有多个JDBC操作,但是异常发生在JDBC操作的中间,这时就会出现仅完成异常出现前的JDBC操作,会得到错误的结果,需要避免。
在数据库中,为了防止上述错误的发生,需要进行事务管理。
事务管理的原理:
发生异常时使事务进行回滚,之前的操作都会被回滚,无异常则提交。
注意:
JDBCUtils工具类获取连接、提交、回滚关闭连接:
/**
* 获取存入ThreadLocal中的连接
* @return
*/
public static Connection getConnection() {
Connection connection = threadLocal.get();
if (connection == null) {
// threadLocal中为空,第一次获取,从连接池中获取
try {
connection = dataSource.getConnection();
// 放入ThreadLocal中供后续JDBC操作使用
threadLocal.set(connection);
// 创建连接的时候就设置为手动管理事务
connection.setAutoCommit(false);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return connection;
}
ThreadLocal一定要执行 remove 操作,否则就会出错!
因为 Tomcat 服务器底层使用了线程池技术。
/**
* 提交事务并关闭释放连接
*/
public static void commitAndClose() {
Connection connection = threadLocal.get();
if (connection != null) {
try {
// 提交事务
connection.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
/**
* 一定要执行 remove 操作,否则就会出错!
* (因为 Tomcat 服务器底层使用了线程池技术)
*/
threadLocal.remove();
}
/**
* 回滚事务并关闭释放连接
*/
public static void rollbackAndClose() {
Connection connection = threadLocal.get();
if (connection != null) {
try {
// 回滚事务
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
/**
* 一定要执行 remove 操作,否则就会出错!
* (因为 Tomcat 服务器底层使用了线程池技术)
*/
threadLocal.remove();
}
由于工程中所有程序都需要进行事务处理,所以使用Filter过滤器对所有程序进行异常判断,出现异常则回滚,否则提交:
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest, servletResponse);
JDBCUtils.commitAndClose();
} catch (Exception e) {
JDBCUtils.rollbackAndClose();
e.printStackTrace();
// 将异常抛给Tomcat服务器,以跳转页面
throw new RuntimeException(e);
}
}
web.xml中对Filter进行配置:
注意:
由于使用Filter在Servlet层才对异常进行事务处理,所以需要保证异常能抛到Servlet层,即子程序的异常都需要抛出,即BaseDAO和BaseServlet的异常都需要向上抛出;
BaseDAO:
public abstract class BaseDAO {
//使用DbUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* 更新数据库操作
*/
public int Update(String sql,Object ...params){
Connection connection = JDBCUtils.getConnection();
try {
queryRunner.update(connection,sql,params);
return 1;
} catch (SQLException throwables) {
throwables.printStackTrace();
/**
* 因为DAO层捕获异常之后不抛出的话,
* 后续的DAO及Service层无法对异常进行回滚处理,
* 所以必须向上抛出异常以供处理
*/
throw new RuntimeException(throwables);
}
}
BaseServlet:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String action = request.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod
(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用目标业务方法
method.invoke(this, request, response);
} catch (Exception e) {
e.printStackTrace();
// 抛出异常
throw new RuntimeException(e);
}
}
注意Filter捕获异常进行回滚之后,也要将异常抛出给Tomcat服务器,这样Tomcat才能进行页面跳转:
使用Tomcat进行错误页面跳转: