数据库连接池之自定义连接池(mysql)

上一篇博文是"基于mysql的JDBC的增删改查的封装":点击可查看

今天本仙在昨天JDBC封装增删改查的基础上实现自定义的数据库连接池:

为什么要使用数据库连接池:
用户每次请求都需要向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机.

数据库连接池:顾名思义就是一个存放着数据库连接的游泳池,这些数据库连接初始化后都在这个池子里面遨游,当有请求要获取连接时,拿出去一个使用,用完后再放回这个池子里面,方便循环使用.数据库连接小鱼生生不息,有效的节省了资源,提高了处理效率,这个解释通俗易懂吧~
​废话不多说,我们开始:

1 项目结构:

昨天有个’屎’嘲笑我的项目路径竟然包括中文,本仙受挫了,哼,但是他所说的对,于是乎决定全改成英文,本仙一定会好好学习英语的

2 省略的过程

  1. 项目的创建
  2. jdbc驱动jar包的导入
  3. 数据库中用户表(user)的创建和添加数据(可见上一篇,传送门)
  4. 实体类(User)的创建(可见上一篇,传送门)
  5. 配置文件(db.properties)的创建(可见上一篇,传送门)

3 自定义数据库连接池的实现(DB_pool.java)

实现下面目录中类的封装:

3.1 数据库连接池的初始化

Java为连接池实现提供了一个规范(接口),规范的写法,我们需要实现DataSource接口(当然这个接口中的方法我们不用每个都实现,没有实现的方法我就不贴了)!

public class DB_pool implements DataSource {public static final int CONNCOUNT = 5;//创建连接的集合public static List<Connection> connections;private static String driverClass;private static String url;private static String user;private static String password;//初始化数据库连接池static {//使用安全集合才存储连接connections = Collections.synchronizedList(new LinkedList<>());try {//获取配置文件InputStream inputStream = DB_Tools.class.getClassLoader().getResourceAsStream("db.properties");Properties properties = new Properties();properties.load(inputStream);//从配置文件中获取数据信息driverClass = properties.getProperty("driverClass");url = properties.getProperty("url");user = properties.getProperty("user");password = properties.getProperty("password");//注册驱动Class.forName(driverClass);System.out.println("注册驱动成功");//初始化Connection对象for (int i = 0; i < CONNCOUNT; i++) {connections.add(DriverManager.getConnection(url, user, password));}System.out.println("数据库连接池初始化完成");} catch (Exception e) {e.printStackTrace();System.out.println("初始化失败");}}
}
3.2 通过数据库连接池获取数据库连接
public class DB_pool implements DataSource {//获取连接,即从连接池中取出一个连接来使用@Overridepublic Connection getConnection() throws SQLException {synchronized (connections) {if (connections.size() > 0) {Connection connection = connections.remove(0);//测试一下我们拿到的是哪个连接System.out.println("使用了Connection:"+connection.toString());return connection;}}return null;}
}
3.3 断开数据库连接

数据库连接使用完毕之后,并不是将这个连接给close()掉,而是重新放入数据库连接池中(不然你在数据库连接池中拿一个连接,用完了就关闭不放回去…N轮之后数据库连接池就没有连接了,那数据库连接池就是去了它存在的意义)

public class DB_pool implements DataSource {//自定义断开连接方法,其实实现的是将使用完的connection放回连接池public void releaseConnection(Connection connection){//测试一下,是将哪个链接返回了数据库System.out.println("归还了Connection:"+connection.toString());connections.add(connection);}
}

4 JDBC增删改查封装类(DB_Tools.java)的修改

传送门:上一篇博客:简易JDBC增删改查的封装
实现下面目录中类的封装:
要配合数据库连接池使用,所以这里在初始化连接和关闭连接时做了一点点的修改

4.1 初始化数据库连接池(修改)
public class DB_Tools {//全静态变量private static DB_pool db_pool;//完成了数据库连接池的初始化static {db_pool = new DB_pool();}
}
4.2 获取数据库连接(修改)
public class DB_Tools {/*** 通过连接池来获取数据库连接** @return 返回一个连接的对象*/public static Connection getDBConnection() {try {return db_pool.getConnection();} catch (SQLException e) {e.printStackTrace();}return null;}
}
4.3 释放资源(修改)
public class DB_Tools {/*** 3.释放资源close()** @param connection        连接* @param preparedStatement 执行命令* @param resultSet         结果集*/public static void allClose(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {try {if (preparedStatement != null) {preparedStatement.close();}if (resultSet != null) {resultSet.close();}if (connection != null) {db_pool.releaseConnection(connection);}System.out.println("执行结束");} catch (SQLException e) {e.printStackTrace();}}
}
4.4 增删改查的方法(一点点修改)
public class DB_Tools {/*** 4.执行增删改** @param sql     sql操作语句* @param objects sql语句中的参数,可以为null* @return int >0操作(增删改)成功 <0操作失败*/public static int excumentDBUpdate(String sql, Object[] objects) {int updateResult = 0;Connection connection = null;PreparedStatement preparedStatement = null;try {//1.获取连接connection = getDBConnection();//2.获取增删改查的执行命令preparedStatement = connection.prepareStatement(sql);//3.向sql语句中?填充数据if (objects != null) {for (int i = 0; i < objects.length; i++) {preparedStatement.setObject(i + 1, objects[i]);}}//4.执行增删改查updateResult = preparedStatement.executeUpdate();} catch (SQLException e) {e.printStackTrace();} finally {//5.关闭连接,释放资源allClose(connection, preparedStatement, null);}return updateResult;}/*** 5.查询单条数据(反射加内省实现)** @param sql     sql操作语句* @param objects sql语句中的参数,可以为null* @param tClass* @param <T>     泛型* @return 返回单个实体对象*/public static <T> T getSingleResult(String sql, Object[] objects, Class<T> tClass) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;T object = null;try {//1.获取连接connection = getDBConnection();//2.创建命令对象preparedStatement = connection.prepareStatement(sql);//3.向sql语句中添加数据(objects),如果objects不为空的话if (objects != null) {for (int i = 0; i < objects.length; i++) {preparedStatement.setObject(i + 1, objects[i]);}}//4.执行查询语句resultSet = preparedStatement.executeQuery();//5.通过反射创建tClass类的对象//6.从结果集中获取数据if (resultSet.next()) {object = getObject(resultSet, tClass);}} catch (Exception e) {e.printStackTrace();} finally {//7.关闭连接释放资源allClose(connection, preparedStatement, resultSet);}//8.返回object对象return object;}/*** 5.2查询多条数据(反射+内省实现)** @param sql     sql操作语句* @param objects sql语句中的参数,可以为null* @param tClass* @param <T>     泛型* @return 返回多个对象的集合*/public static <T> List<T> getComplexResult(String sql, Object[] objects, Class<T> tClass) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;List<T> tList = new ArrayList<T>();try {//1.获取连接connection = getDBConnection();//2.创建命令对象preparedStatement = connection.prepareStatement(sql);//3.向sql语句中添加数据(objects),如果objects不为空的话if (objects != null) {for (int i = 0; i < objects.length; i++) {preparedStatement.setObject(i + 1, objects[i]);}}//4.执行查询语句resultSet = preparedStatement.executeQuery();//5.从结果集中获取数据while (resultSet.next()) {T object = getObject(resultSet, tClass);tList.add(object);}} catch (Exception e) {e.printStackTrace();} finally {//7.关闭连接释放资源allClose(connection, preparedStatement, resultSet);}//8.返回tList集合return tList;}/*** 通过反射+内省将结果集中数据拿出来* @param resultSet 结果集啊* @param tClass 传递过来的操作类* @param <T> 泛型* @return 返回一个泛型对象Object* @throws Exception*/public static <T> T getObject(ResultSet resultSet, Class<T> tClass) throws Exception {T object = tClass.newInstance();ResultSetMetaData resultSetMetaData = resultSet.getMetaData();for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {//获取列名String colName = resultSetMetaData.getColumnName(i + 1);//通过内省获取包含列名指定方法(一般是get和set)PropertyDescriptor propertyDescriptor = new PropertyDescriptor(colName, tClass);if (propertyDescriptor != null) {//获取到方法后我们再获取set方法来对private修饰的相关属性进行赋值Method method = propertyDescriptor.getWriteMethod();//然后我们执行这个方法并将属性添加到object对象中method.invoke(object, resultSet.getObject(colName));}}return object;}
}

通过上面我们就分别封装好了自定义的数据库连接池和JDBC操作类,在这里写一个接口封装几个方法使用数据库连接池和JDBC封装的方法来实现:

5 封装接口(DbPoolsDao.java)

封装接口:

public interface DbPoolsDao {/*** 通过主键查询单条用户信息** @param id 主键id* @return*/public User findSingleUserByPrimaryKey(int id);/*** 查询全部的用户信息** @return*/public List<User> findUserAllUser();/*** 添加用户信息** @param user*/public void addUserInfo(User user);/*** 更新用户信息** @param user*/public void updateUserInfoByPrimaryKey(User user);/*** 通过主键删除用户信息** @param id*/public void deleteUserInfoByPrimaryKey(int id);}

6 实现上面的接口(DbPoolDaoImpl.java)

实现接口:

public class DbPoolDaoImpl implements DbPoolsDao {@Overridepublic User findSingleUserByPrimaryKey(int id) {String sql = "select * from user where id = ?";Object[] objects = {id};return DB_Tools.getSingleResult(sql, objects, User.class);}@Overridepublic List<User> findUserAllUser() {String sql = "select * from user";return DB_Tools.getComplexResult(sql, null, User.class);}@Overridepublic void addUserInfo(User user) {String sql = "insert into user values(?,?,?,?,?)";Object[] objects = {user.getId(),user.getUsername(),user.getPassword(),user.getAge(),user.getGendar()};DB_Tools.excumentDBUpdate(sql, objects);}@Overridepublic void updateUserInfoByPrimaryKey(User user) {String sql = "update user set username=?,password=?,age=?,gendar=? where id=?";Object[] objects = {user.getUsername(),user.getPassword(),user.getAge(),user.getGendar(),user.getId()};DB_Tools.excumentDBUpdate(sql, objects);}@Overridepublic void deleteUserInfoByPrimaryKey(int id) {String sql = "delete from user where id=?";Object[] objects = {id};DB_Tools.excumentDBUpdate(sql, objects);}
}

7 测试

上面写了那么多,到底结果如何呢,这里本仙分别用单元测试(简易版),测试数据库连接池的封装类(DB_pool)和接口实现(DbPoolDaoImpl)看看写的代码成功与否**走你┏ (゜ω゜)=☞**

7.1 测试数据库连接池封装类
public class DB_poolTest {@Testpublic void testPool() {for (int i = 0; i < 100; i++) {Connection connection = DB_Tools.getDBConnection();DB_Tools.allClose(connection, null, null);System.out.println(connection.toString() + "\n--------------------------------------------------");//JDBC4Connection:connection.getClass()从数据库获取的原生连接}}
}
//运行结果:
/*
注册驱动成功
数据库连接池初始化完成
使用了Connection:com.mysql.jdbc.JDBC4Connection@4ca8195f
归还了Connection:com.mysql.jdbc.JDBC4Connection@4ca8195f
执行结束
com.mysql.jdbc.JDBC4Connection@4ca8195f
--------------------------------------------------
使用了Connection:com.mysql.jdbc.JDBC4Connection@65e579dc
归还了Connection:com.mysql.jdbc.JDBC4Connection@65e579dc
执行结束
com.mysql.jdbc.JDBC4Connection@65e579dc
--------------------------------------------------
使用了Connection:com.mysql.jdbc.JDBC4Connection@61baa894
归还了Connection:com.mysql.jdbc.JDBC4Connection@61baa894
执行结束
com.mysql.jdbc.JDBC4Connection@61baa894
--------------------------------------------------
使用了Connection:com.mysql.jdbc.JDBC4Connection@b065c63
归还了Connection:com.mysql.jdbc.JDBC4Connection@b065c63
执行结束
com.mysql.jdbc.JDBC4Connection@b065c63
--------------------------------------------------
使用了Connection:com.mysql.jdbc.JDBC4Connection@768debd
归还了Connection:com.mysql.jdbc.JDBC4Connection@768debd
执行结束
com.mysql.jdbc.JDBC4Connection@768debd
.....(这里往后省略)
*/
7.2 测试实现接口
public class Db_PoolDaoTest {private static DbPoolsDao dbPoolsDao;@BeforeClasspublic static void beforeTest() {dbPoolsDao = new DbPoolDaoImpl();}@AfterClasspublic static void afterTest() {dbPoolsDao = null;}@Testpublic void findSingleUserByPrimaryKeyTest() {User user = dbPoolsDao.findSingleUserByPrimaryKey(100);System.out.println(user);}@Testpublic void findUserAllUserTest() {List<User> users = dbPoolsDao.findUserAllUser();for (User user : users) {System.out.println(user);}}@Testpublic void addUserInfoTest() {dbPoolsDao.addUserInfo(new User(105, "明明", "mingming", 20, "male"));System.out.println("添加成功");}@Testpublic void updateUserInfoByPrimaryKeyTest() {dbPoolsDao.updateUserInfoByPrimaryKey(new User(105, "明明", "helloworld", 18, "male"));System.out.println("修改成功");}@Testpublic void deleteUserInfoByPrimaryKeyTest() {dbPoolsDao.deleteUserInfoByPrimaryKey(105);System.out.println("删除成功");}
}

方法太多,测试结果我就不一个一个贴上来了,不过每个方法小编都是测试过的!如果哦除了问题,那肯定是你代码里有小臭虫了,本仙这里是通过的,若你再测试过程中遇到了问题,可以留言欧,我超级喜欢给别人找Bug的.
感谢您的阅读,希望您有收获,祝您生活愉快,开心快乐每一天~

数据库连接池之自定义连接池(mysql)相关推荐

  1. jdbc 连接池 java_JDBC自定义连接池过程详解

    这篇文章主要介绍了JDBC自定义连接池过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 开发中,"获得连接"和" ...

  2. 数据库连接池和Tomcat连接池的配置问题

    在做系统优化的时候师哥给我们提了一个连接池的概念,问我们有没有配置,我对这个概念一无所知,于是进行了一些研究,连接池有很多,比如WCF.EF还有数据库.CAS也可以配连接池,这些连接池用通俗的语言来说 ...

  3. java数据库配置_java--数据库(文件配置连接,自定义连接池)

    import java.util.ResourceBundle; public class Mtest7Demo { //使用properties配置文件完成数据库的连接 /* * 开发中获得连接的4 ...

  4. 使用装饰者设计模式增强自定义连接池

    为什么需要增强? 自定义连接池中存在严重的问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用conn.close()将连接真正的释放,连 ...

  5. mysql连接池永驻_【学习笔记】Oracle连接池 数据库常驻连接池(Database Resident Connection Pool)案例介绍...

    天萃荷净 分享一篇关于应用程序与Oracle数据库连接的连接方法介绍,数据库常驻连接池(Database Resident Connection Pool)案例介绍 一.介绍常驻连接池(Databas ...

  6. c3p0和jdbctemplate配置oracle集群rac,C3P0连接池、DRUID连接池和JdbcTemplate

    目录 一.C3P0连接池 1.C3P0连接池简介 2.常用的配置参数 3.C3P0连接池基本使用 (1)C3P0配置文件 (2)API介绍 4.使用步骤 二.DRUID连接池 1. DRUID简介 2 ...

  7. C3P0连接池、DRUID连接池和JdbcTemplate

    目录 一.C3P0连接池 1.C3P0连接池简介 2.常用的配置参数 3.C3P0连接池基本使用 (1)C3P0配置文件 (2)API介绍 4.使用步骤 二.DRUID连接池 1. DRUID简介 2 ...

  8. JDBC、封装JDBC连接池、第三方连接池工具

    主要内容: JDBC简介 JDBC来源 通过代码实现JDBC JDBC的改进需求 JDBC改进的代码实现 JDBC使用的设计模式 封装连接池 封装JDBC连接池 ThreadLoacl的使用 Thre ...

  9. 池技术:连接池,线程池,内存池,进程池等汇总分析

    引言 在软件开发中,经常会遇到需要频繁创建和销毁某些资源的情况.这些资源可能是内存.线程.数据库连接等.频繁地创建和销毁资源可能导致性能下降和资源浪费.为了解决这些问题,软件开发者设计了一种称为&qu ...

最新文章

  1. 031_vue编程式导航
  2. 实战dock安装和镜像的拉取
  3. python 批量读取文件夹的动漫美女图并显示
  4. chrome谷歌浏览器安装教程 20200701
  5. Aptana studio 3汉化教程
  6. 找回Win8.1(windows server 2012 R2)的双拼
  7. 7.docker pull
  8. python正则表达式面试题,带有utf8问题的python正则表达式
  9. SpringBoot整合Swagger生成接口文档
  10. RTKLIB源码之单点定位/相对定位后处理简化版—第一版
  11. tcl中数字加减的怪异现象
  12. 7-112 约分最简分式
  13. RHEL5下nginx+php+mysql+tomcat+memchached配置全过程
  14. android下雨动画效果,Android利用SurfaceView实现下雨的天气动画效果
  15. 常用数据库排名及分类介绍
  16. html中按钮怎么设置渐变色,CSS3渐变色按钮
  17. Python:根据itchat编了一个3岁智商的机器人
  18. HARK学习(五)--AudioStreamFromMic
  19. 【十三香吗?】网易严选-苹果12商品评论数据可视化分析
  20. ViewPager详解

热门文章

  1. Navigation Controller 的常用操作
  2. MFC不同窗口之间传递数据
  3. sublime插件之sidebar
  4. newt.h:没有那个文件或目录
  5. NLP_task4文本表示_CBOW和Skip-gram模型
  6. 项目awesome-semantic-segmentation-pytorch以及FCN、Unet、deeplabv1、deeplabv2、deeplabv3、deeplabv3+的网络
  7. 硕士生论文存在的问题
  8. 西门子——好用的通讯仿真通讯工具NetToPLCsim
  9. long(Long)与int(Integer)四种类型之间互相转换的方法分享
  10. LoadRunner Error -27792: Failed to connect to server