javaWeb学习记录:BaseServlet 与 service事务
2016-04-11 01:42
597 查看
本文根据崔希凡老师的讲课视频和笔记整理而成
1. BaseServlet
分析
通常,写一个项目可能会出现N多个Servlet,而且一般一个Servlet只有一个方法(doGet或doPost),如果项目大一些,那么Servlet的数量就会很惊人。为了避免Servlet的“膨胀”,我们写一个BaseServlet。它的作用是让一个Servlet可以处理多种不同的请求。不同的请求调用Servlet的不同方法。我们写好了BaseServlet后,让其他Servlet继承BaseServlet,例如CustomerServlet继承BaseServlet,然后在CustomerServlet中提供add()、update()、delete()等方法,每个方法对应不同的请求。并且每个方法放回一个字符串,指出它重定向或转发请求的路径,BaseServlet获得这个路径,再帮助子类转发请求或重定向到特定的页面。见下图:
我们知道,Servlet中处理请求的方法是service()方法,这说明我们需要让service()方法去调用其他方法。例如调用add()、mod()、delele()、findAll()等方法!具体调用哪个方法需要在请求中给出方法名称!然后service()方法通过方法名称来调用指定的方法。
无论是点击超链接,还是提交表单,请求中必须要有method参数,这个参数的值就是要请求的方法名称,这样BaseServlet的service()才能通过方法名称来调用目标方法。例如某个链接如下:
<a href=”/xxx/CustomerServlet?method=add”>添加客户”</a>
见下图:
BaseServlet完整代码
import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public abstract class BaseServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 1. 获取参数,用来识别用户想请求的方法 * 2. 然后判断是否哪一个方法,是哪一个我们就调用哪一个 */ String methodName = req.getParameter("method"); if(methodName == null || methodName.trim().isEmpty()) { throw new RuntimeException("您没有传递method参数!无法确定您想要调用的方法!"); } /* * 1. 得到方法名,通过方法名再得到Method类的对象! * * 需要得到Class,然后调用它的方法进行查询!得到Method * * 我们要查询的是当前类的方法,所以我们需要得到当前类的Class */ Class<? extends BaseServlet> c = this.getClass();//得到当前类的class对象 Method method = null; try { method = c.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); } catch (Exception e) { throw new RuntimeException("您要调用的方法:" + methodName + "(HttpServletRequest,HttpServletResponse),它不存在!"); } /* * 调用method表示的方法 */ try { String result = (String)method.invoke(this, req, resp); /* * 获取请求处理方法执行后返回的字符串,它表示转发或重定向的路径! * 如果用户返回的是字符串为null,或为"",那么什么也不做! */ if(result == null || result.trim().isEmpty()) { return; } /* * 查看返回的字符串中是否包含冒号,如果没有,表示转发 * 如果有,使用冒号分割字符串,得到前缀和后缀! * 其中前缀如果是f,表示转发,如果是r表示重定向,后缀就是要转发或重定向的路径了! */ if(result.contains(":")) { // 使用冒号分割字符串,得到前缀和后缀 String str[] = result.split(":");//用冒号分割字符串 String s = str[0];//取出前缀,表示操作 String path = str[1];//取出后缀,表示路径 if(s.equalsIgnoreCase("r")) {//如果前缀是r,那么重定向! resp.sendRedirect(req.getContextPath() + path); } else if(s.equalsIgnoreCase("f")) { req.getRequestDispatcher(path).forward(req, resp); } else { throw new RuntimeException("你指定的操作:" + s + ",当前版本还不支持!"); } } else {//没有冒号,默认为转发! req.getRequestDispatcher(result).forward(req, resp); } } catch (Exception e) { System.out.println("您调用的方法:" + methodName + ", 它内部抛出了异常!"); throw new RuntimeException(e); } } }
2. service事务
我们要清楚一件事,DAO中不是处理事务的地方,因为DAO中的每个方法都是对数据库的一次操作,而Service中的方法才是对应一个业务逻辑。也就是说我们需要在Service中的一方法中调用DAO的多个方法,而这些方法应该在一个事务中。怎么才能让DAO的多个方法使用相同的Connection呢?方法不能再自己来获得Connection,而是由外界传递进去。public void daoMethod1(Connection con, …) { } public void daoMethod2(Connection con, …) { }
由于在Service中不应该出现Connection,它应该只在DAO中出现。所以我们把对事务的开启和关闭放到JdbcUtils工具类中,在Service中调用JdbcUtils的方法来完成事务的处理。DAO中的方法不用再让Service来传递Connection了。DAO会主动从JdbcUtils中获取Connection对象,这样,JdbcUtils成为了DAO和Service的中介!
我们在JdbcUtils中添加beginTransaction()和rollbackTransaction(),以及commitTransaction()方法。为了处理多线程的问题,我们还要使用ThreadLocal类,为每个线程提供一个Connection,这样每个线程都可以开启自己的事务了。
JdbcUtils的完整代码:
import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JdbcUtils { // 配置文件的默认配置!要求你必须给出c3p0-config.xml!!! private static ComboPooledDataSource dataSource = new ComboPooledDataSource(); // 它是事务专用连接! private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); /** * 使用连接池返回一个连接对象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { Connection con = tl.get(); // 当con不等于null,说明已经调用过beginTransaction(),表示开启了事务! if(con != null) return con; return dataSource.getConnection(); } /** * 返回连接池对象! * @return */ public static DataSource getDataSource() { return dataSource; } /** * 开启事务 * 1. 获取一个Connection,设置它的setAutoComnmit(false) * 2. 还要保证dao中使用的连接是我们刚刚创建的! * -------------- * 1. 创建一个Connection,设置为手动提交 * 2. 把这个Connection给dao用! * 3. 还要让commitTransaction或rollbackTransaction可以获取到! * @throws SQLException */ public static void beginTransaction() throws SQLException { Connection con = tl.get(); if(con != null) throw new SQLException("已经开启了事务,就不要重复开启了!"); /* * 1. 给con赋值! * 2. 给con设置为手动提交! */ con = getConnection();//给con赋值,表示事务已经开始了 con.setAutoCommit(false); tl.set(con);//把当前线程的连接保存起来! } /** * 提交事务 * 1. 获取beginTransaction提供的Connection,然后调用commit方法 * @throws SQLException */ public static void commitTransaction() throws SQLException { Connection con = tl.get();//获取当前线程的专用连接 if(con == null) throw new SQLException("还没有开启事务,不能提交!"); /* * 1. 直接使用con.commit() */ con.commit(); con.close(); // 把它设置为null,表示事务已经结束了!下次再去调用getConnection()返回的就不是con了 tl.remove();//从tl中移除连接 } /** * 提交事务 * 1. 获取beginTransaction提供的Connection,然后调用rollback方法 * @throws SQLException */ public static void rollbackTransaction() throws SQLException { Connection con = tl.get(); if(con == null) throw new SQLException("还没有开启事务,不能回滚!"); /* * 1. 直接使用con.rollback() */ con.rollback(); con.close(); tl.remove(); } /** * 释放连接 * @param connection * @throws SQLException */ public static void releaseConnection(Connection connection) throws SQLException { Connection con = tl.get(); /* * 判断它是不是事务专用,如果是,就不关闭! * 如果不是事务专用,那么就要关闭! */ // 如果con == null,说明现在没有事务,那么connection一定不是事务专用的! if(con == null) connection.close(); // 如果con != null,说明有事务,那么需要判断参数连接是否与con相等,若不等,说明参数连接不是事务专用连接 if(con != connection) connection.close(); } }
相关文章推荐
- SQL Server误区30日谈 第1天 正在运行的事务在服务器故障转移后继续执行
- 浅析SQL Server中包含事务的存储过程
- Mysql中的事务是什么如何使用
- MySql的事务使用与示例详解
- C#分布式事务的超时处理实例分析
- C#中的事务用法实例分析
- SQL Server的事务操作隔离模式介绍
- MySQL中事务概念的简洁学习教程
- C#处理Access中事务的方法
- oracle 合并查询 事务 sql函数小知识学习
- sql不常用函数总结以及事务,增加,删除触发器
- mysql的XA事务恢复过程详解
- 在Mysql存储过程中使用事务实例
- mysql存储过程事务管理简析
- php+mysql事务rollback&commit示例
- PHP中的事务使用实例
- SQLServer存储过程中事务的使用方法
- 在Java的JDBC使用中设置事务回滚的保存点的方法
- PHP使用Mysql事务实例解析
- MySql事务无法回滚的原因有哪些