Filter 和 ThreadLocal 组合管理事务:
事物:
public class TransactionFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { try { // Filter中主要的事物处理机制 filterChain.doFilter(servletRequest,servletResponse); JdbcUtils.commitAndClose();// 提交事务 } catch (Exception e) { JdbcUtils.rollbackAndClose();//回滚事务 e.printStackTrace(); } } }
<filter> <filter-name>TransactionFilter</filter-name> <filter-class>com.atguigu.filter.TransactionFilter</filter-class> </filter> <filter-mapping> <filter-name>TransactionFilter</filter-name> <!-- /* 表示当前工程下所有请求 --> <url-pattern>/*</url-pattern> </filter-mapping>
public abstract class BaseDao { //使用 DbUtils 操作数据库 private QueryRunner queryRunner = new QueryRunner(); /** * update() 方法用来执行:InsertUpdateDelete 语句 * @return 如果返回-1,说明执行失败<br/>返回其他表示影响的行数 */ public int update(String sql, Object... args) { Connection connection = JdbcUtils.getConnection(); try { return queryRunner.update(connection, sql, args); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e);// 在所有的Dao中必须将异常抛给Filter } }
public abstract class BaseServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 解决 post 请求中文乱码问题 // 一定要在获取请求参数之前调用才有效 req.setCharacterEncoding("UTF-8"); String action = req.getParameter("action"); try { // 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象 Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); // 调用目标业务 方法 method.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e);// 把异常抛给 Filter 过滤器 }} }
public class JdbcUtils { private static DruidDataSource dataSource; private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>(); static { try { Properties properties = new Properties(); // 读取 jdbc.properties 属性配置文件 InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"); // 从流中加载数据 properties.load(inputStream); // 创建 数据库连接 池 dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } /** * 获取数据库连接池中的连接 * @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功 */ public static Connection getConnection(){ Connection conn = conns.get(); if (conn == null) { try { conn = dataSource.getConnection();//从数据库连接池中获取连接 conns.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用 conn.setAutoCommit(false); // 设置为手动管理事务 } catch (SQLException e) { e.printStackTrace(); } } return conn; } /** * 提交事务,并关闭释放连接 */ public static void commitAndClose(){ Connection connection = conns.get(); if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库 try { connection.commit(); // 提交 事务 } catch (SQLException e) { e.printStackTrace(); } finally { try { connection.close(); // 关闭连接,资源资源 } catch (SQLException e) { e.printStackTrace(); } } } // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术) conns.remove(); } /** * 回滚事务,并关闭释放连接 */ public static void rollbackAndClose(){ Connection connection = conns.get(); if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库 try { connection.rollback();//回滚事务 } catch (SQLException e) { e.printStackTrace(); } finally { try { connection.close(); // 关闭连接,资源资源 } catch (SQLException e) { e.printStackTrace();} } } // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术) conns.remove(); } }
FIlter中的日志处理: