apache httpclient 连接池 工具_如何实现DBCP数据库连接池工具类&mvc分层开发web流程操作?

DBCP是tomcat中的一个工具类。

DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。

5dc522f0bdfd941f73219e66fb13f4ec.png

DBCP数据库连接池操作如下:

1、导入驱动jar包(dbcp连接池jar包通常依赖于pool包一起使用)

原理:dbcp包会产生许多个连接对象,这些对象供pool包进行统一管理。

16417ad0cdf217f8bf2827216297c3d4.png
a2b32e59efbe5f7bba0719ec72c38146.png

2、创建数据库工具类:DBUtils.java

工具类优点:

  • 1、提高性能

告别传统方式每次连接数据库都要进行创建并关闭,严重影响性能,使用数据库连接池DBCP技术实现连接池中存放多个连接对象供使用。当不需要连接时,将连接对象存放到池中即可,提高性能!

  • 2、避免多线程访问连接对象混乱问题

将连接保存在ThreadLocal类中,相当于map结构,它是将当前线程对象作为key,保存连接conn对象,避免多线程访问业务层和dao层导致使用的conn连接对象不一致问题。先从threadLocal中获取连接,如果连接为null,从连接池获取连接,设置到threadLocal中。

  • 3、将提交和回滚事务统一处理

先从ThreadLocal类中获取连接,如果连接不为null,提交或者回滚事务,然后关闭连接,清理当前线程所绑定的连接。

  • 4、方便关闭连接

关闭除过conn连接对象的其他对象statement、resultset等。

DBCP核心设置代码如下:

// 创建数据库连接池ds = new BasicDataSource();// 设置连接信息ds.setDriverClassName("com.mysql.cj.jdbc.Driver");ds.setUrl(URL);ds.setUsername(USERNAME);ds.setPassword(PASSWORD);// 设置连接池信息// 最大空闲连接数ds.setMaxIdle(30);// 最小空闲连接数ds.setMinIdle(2);// 设置初始连接数ds.setInitialSize(2);// 创建连接时最大等待时间ds.setMaxWaitMillis(4000);// 毫秒// 从数据源中拿到的连接,关闭其自动提交的事务ds.setDefaultAutoCommit(false);

完整代码如下:

package com.yueqian.store.common;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.HashMap;import java.util.Map;import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;public class DBUtils {private static final String URL = "jdbc:mysql://127.0.0.1:3306/store?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";private static final String USERNAME = "root";private static final String PASSWORD = "root";private static final BasicDataSource ds;static {// 加载驱动try {// 方式一DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());// 方式二 根据传入字符串形式的类名加载该类 (加载类时调用静态代码块加载驱动)// Class.forName("com.mysql.cj.jdbc.Driver()");} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}// 创建数据库连接池ds = new BasicDataSource();// 设置连接信息ds.setDriverClassName("com.mysql.cj.jdbc.Driver");ds.setUrl(URL);ds.setUsername(USERNAME);ds.setPassword(PASSWORD);// 设置连接池信息// 最大空闲连接数ds.setMaxIdle(30);// 最小空闲连接数ds.setMinIdle(2);// 设置初始连接数ds.setInitialSize(2);// 创建连接时最大等待时间ds.setMaxWaitMillis(4000);// 毫秒// 从数据源中拿到的连接,关闭其自动提交的事务ds.setDefaultAutoCommit(false);}// 定义连接保存在ThreadLocal类中,将当前线程对象作为key,保存连接conn对象,避免多线程访问业务层和dao层导致使用的conn连接不一致问题// service里绑定每个线程对象的连接,调用的dao层获取该处理线程对象的连接private static ThreadLocal threadLocal = new ThreadLocal();/** * 连接数据库 *  * @return */public static Connection getConnection() {//先从threadLocal中获得连接,threadLocal类似map存放,ThreadLocal中是以键为当前线程对象,值为conn连接存放的。Connection conn = threadLocal.get();//如果连接为null,从连接池中获取连接if (conn == null) {try {conn = ds.getConnection();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}//将得到的连接设置到threadLocal中threadLocal.set(conn);}return conn;}/** * 关闭连接 *  * @param rs * @param stmt * @param conn */public static void close(ResultSet rs, Statement stmt) {if (rs != null) {try {rs.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (stmt != null) {try {stmt.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}// 提交事务public static void commit() {Connection conn = threadLocal.get();if(conn != null){try {conn.commit();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally {//关闭连接try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}//清理当前线程所绑定的连接threadLocal.remove();}}}// 回滚事务public static void rollback() {Connection conn = threadLocal.get();if(conn != null){try {conn.rollback();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally {//关闭连接try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}//清理当前线程所绑定的连接threadLocal.remove();}}}}
5ee7d59e6488c0f8032ba76714efaa9d.png

3、业务层

使用同一个连接对象,调用多个Dao层处理。所有事务处理完成之后,统一操作成功,调用DBUtils.commit()方法提交事务,一个失败,全部回滚。

package com.yueqian.store.service;import java.util.List;import com.yueqian.store.common.DBUtils;import com.yueqian.store.dao.ProductTypeDao;import com.yueqian.store.domain.ProductType;/** * 商品类别业务层 *  * @author LinChi * */public class ProductTypeService {private ProductTypeDao typeDao = new ProductTypeDao();/** * 查询所有商品类目 *  * @return */public List findAllProType() {List list = null;try {//调用多个Dao对象处理,最后统一事务提交list = typeDao.findAllProType();//使用同一个连接对象,执行后续的DAO方法//提交事务DBUtils.commit();} catch (Exception e) {//执行失败回滚事务DBUtils.rollback();}return list;}}

4、dao层

dao层直接调用DBUtils.getConnection()方法获得连接,将dao层所有出现的异常向上抛到业务层,业务层统一处理,最后统一提交并回滚事务,dao层不处理异常,一直声明抛出即可,

package com.yueqian.store.dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import com.yueqian.store.common.DBUtils;import com.yueqian.store.domain.ProductType;public class ProductTypeDao {/** * 查询所有商品类目表 * @return * @throws SQLException  将dao层所有出现的异常向上抛到业务层,业务层统一处理,最后统一提交并回滚事务 */public List findAllProType()throws SQLException{Connection conn = null;PreparedStatement pstm = null;List list = new ArrayList();ResultSet rs = null;ProductType proType = null;conn = DBUtils.getConnection();String sql = "SELECT p.product_type_id,p.name FROM product_types p";try {pstm = conn.prepareStatement(sql);rs = pstm.executeQuery();while(rs.next()) {proType = new ProductType();proType.setTypeId(rs.getInt(1));proType.setTypeName(rs.getString(2));list.add(proType);}} finally {DBUtils.close(rs, pstm);}return list;}}

5、controller层

调用业务层,处理相应的逻辑

  • BaseServlet.java

这是个通过反射机制,将前端传入String的参数类型转换为对应的类型。其他servlet集成该类即可方便转换类型。参数如下(前端name名称,请求对象req,要转化类型的字节码Integer.class)

package com.yueqian.store.controller;import java.sql.Date;import java.text.SimpleDateFormat;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;public class BaseServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");// 获取请求的参数,根据请求的参数转化为特定的类型public  T paseParamter(String parseName, HttpServletRequest req, Class clz) {// 获取请求参数String parmValue = req.getParameter(parseName);// 定义返回类型的对象T result = null;// clz类型 Integer.class String.class Double.class,Float.class,Date.classtry {if (parmValue != null || parmValue.length() > 0) {// 因为Float类型没有String参数的构造方法,所以只能传入long参数的构造方法if (clz == Date.class) {// 将paramValue转换成long类型的值long longValue = sdf.parse(parmValue).getTime();// 创建指定类型的String参数构造方法result = clz.getDeclaredConstructor(long.class).newInstance(longValue);} else {// 将paramValue作为指定类型构造方法的参数result = clz.getDeclaredConstructor(String.class).newInstance(parmValue);}}} catch (Exception e) {e.printStackTrace();}return result;}}
ProductServlet

具体使用如下:

package com.yueqian.store.controller;import java.io.IOException;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.yueqian.store.dao.ProductDAO;import com.yueqian.store.dao.ProductTypeDao;import com.yueqian.store.domain.ProductInfo;import com.yueqian.store.domain.ProductType;import com.yueqian.store.service.ProductService;import com.yueqian.store.service.ProductTypeService;public class ProductServlet extends BaseServlet {/** *  */private static final long serialVersionUID = 1L;private ProductService productService = new ProductService();private ProductTypeService typeService = new ProductTypeService();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String uri = req.getRequestURI();if (uri.indexOf("/prd/list") >= 0) {// 商品列表List findAllProduct = productService.findAllProduct();// 设置列表到请求页面req.setAttribute("findAllProduct", findAllProduct);// 请求转发到目标页面req.getRequestDispatcher("/product/product_list.jsp").forward(req, resp);} else if (uri.indexOf("/prd/add") >= 0) {// 查看所有类目List findAllProType = typeService.findAllProType();// 存放到请求域中转发到其他页面req.setAttribute("findAllProType", findAllProType);req.getRequestDispatcher("/product/product_add.jsp").forward(req, resp);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");String uri = req.getRequestURI();if (uri.indexOf("/prd/add") > 0) {// 获取请求的参数Integer typeId = super.paseParamter("typeId", req, Integer.class);String productName = super.paseParamter("productName", req, String.class);String desc = super.paseParamter("desc", req, String.class);Float price = super.paseParamter("price", req, Float.class);System.out.println("productName:"+productName+"-------------------------");System.out.println("price:"+price+"-------------------------");//输入校验//数据库中商品名称不能为null,如果为null,将返回消息和用户填写的其他数据if(productName == null || productName.equals("")) {req.setAttribute("msg", "商品名称不能为空!");req.setAttribute("typeId", typeId);req.setAttribute("desc", desc);req.setAttribute("price", price);req.setAttribute("findAllProType", this.typeService.findAllProType());//请求转发到添加页面req.getRequestDispatcher("/product/product_add.jsp").forward(req, resp);return;}// 添加新商品ProductInfo info = new ProductInfo();if (typeId != null && typeId > 0) {info.setProductTypeId(typeId);}info.setProductName(productName);info.setDesc(desc);info.setPrice(price);int count = productService.saveInfo(info);System.out.println(info.getProductName()+"========================");// 重定向到添加请求url (此处不能使用请求转发,因为表单刷新会发送第二次请求,导致添加两次商品)resp.sendRedirect(req.getContextPath() + "/prd/add?count=" + count + "&from=add&proId=" + info.getProductId());}}}

6、view层

将servlet传入的数据,通过jsp展示到页面给用户

商品添加页面 typeList = (List) request.getAttribute("findAllProType");//获取传递的url参数String count = request.getParameter("count");String from = request.getParameter("from");String proId = request.getParameter("proId");%>返回主页商品类别:请选择商品类别 0) {for (ProductType types : typeList) {%>>
商品名称:
商品描述:
商品价格:/> 0) {out.print(f + "了" + count + "件商品,刚刚录入的商品编号为:" + proId);}else{out.print(f+"失败!");}}Object msg = request.getAttribute("msg");if(msg!=null){out.print(msg);}%>

好了,该项目的部分代码如上所示,这节你将学到如何优化数据库连接、mvc分层创建web项目流程 、反射机制转换前端传递的类型。

这就是DBCP连接池的使用,可以大大提供系统的性能,可能现在我们的项目比较小,还没有真正体会到效率提高的到底有多少,相信在今后接触到更大的项目,我们会经常使用连接池的,继续前行……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值