线程池实现原理_最通俗易懂的解读比特币相关原理

线程池实现原理_最通俗易懂的解读比特币相关原理本篇内容综合广大网友提供内容,笔者经过整理,对数据库连接池原理和实现过程做个很系统的并且通俗易懂的分析讲解,以及手写一个连接池实现过程作为演示。一、早期通过JDBC方式操作数据库我们先来看早期使用JDBC的方式操作数据库的过程,这里以mysql数据库为例讲解JDBC操作数据库原理:一般来说,java应用程序访问数据库的过程是:   ①装载数据库驱动程序;   ②通过jdbc…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

本篇内容综合广大网友提供内容,笔者经过整理,对数据库连接池原理和实现过程做个很系统的并且通俗易懂的分析讲解,以及手写一个连接池实现过程作为演示。

一、早期通过JDBC方式操作数据库

我们先来看早期使用JDBC的方式操作数据库的过程,这里以mysql数据库为例讲解

线程池实现原理_最通俗易懂的解读比特币相关原理

JDBC操作数据库原理:一般来说,java应用程序访问数据库的过程是:

   ①装载数据库驱动程序;

   ②通过jdbc建立数据库连接;

   ③访问数据库,执行sql语句;

   ④断开数据库连接。

1、具体的代码实现步骤

创建数据库配置文件db.properties ,配置文件内容如下:

#连接数据库的url,test表示数据库名,useUnicode=true表示使用Unicode字符集
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8; 
#用户名
user=root
#密码
password=root
#MySQL数据库加载驱动
driverClass=com.mysql.jdbc.Driver

定义一个使用jdbc连接数据库的工具类JdbcUtil.java

public class JdbcUtil{
    //定义全局变量
    private static String url = null;
    private static String user = null;
    private static String password = null;
    private static driverClass = null;
    //读取配置文件内容,放在静态代码块中就行,因为只需要加载一次就可以了
    static{
        try{
            Properties props = new Properties();
            //使用类路径加载的方式读取配置文件
            //读取的文件路径要以“/”开头,使用"/"开头会直接定位到工程的src路径下
            InputStream in = JdbcUtil.class.getResourceAsStream("/db.properties");
            //加载配置文件
            props.load(in);
            //读取配置文件信息
            url = props.getProperty("url");
            user = props.getProperty("user");
            password = props.getProperty("password");
            driverClass = props.getProperty("driverClass");
            //动态注册mysql驱动程序
            Class.forName(driverClass);
            System.out.println("成功加载MySQL驱动程序");
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("mysql驱动程序注册失败!!!");
        }
    }

    //获取连接对象Connection
    public static Connection getConnection(){
        try{
            //要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象
            return DriverManager.getConnection(url,user,password);
        }catch(SQLException e){
            e.printStackTrace();
            //抛出运行时异常
            throw new RuntimeException();
        }
    }

    //关闭连接的方法,后打开的先关闭
    public static void close(Connection conn,Statement stmt,ResultSet rs){
        //关闭ResultSet对象
        if(rs != null){
            try{
                //关闭rs,设置rs=null,因为java会优先回收值为null的变量
                rs.close();
                rs = null;
            }catch(SQLException e){
                e.printStackTrace();
                throw new RuntimeException();
            }
        }
        //关闭Statement对象,因为PrepareStatement和CallableStatement都是Statement的子接口,所以这里只需要有关闭Statement对象的方法就可以了
        if(stmt != null){
            try{
                stmt.close();
                stmt = null;
            }catch(SQLException e){
                e.printStackTrace();
                throw new RuntimeException();
            }
        }
        //关闭Connection对象
        if(conn != null){
            try{
                conn.close();
                conn = null;
            }catch(SQLException e){
                e.printStackTrace();
                throw new RuntimeException();
            }
        }
    }
}

到此,这是一个完整的使用JDBC方式操作数据库的过程,下面我们新建一个测试类TestConn.java 测试一下

package demo;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import utils.JdbcUtil;

public class TestConn {

	public static void main(String[] args) {
	// TODO Auto-generated method stub
	Connection conn = JdbcUtil.getConnection();
	  try {
		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery("SELECT * FROM user") ;
		//使用结果集(ResultSet)对象的访问方法获取数据:
		 while(rs.next()){   
	         String name = rs.getString("name") ; 
	         System.out.println(name);
	         String pass = rs.getString(1);//此方法比较高效,列是从左到右编号的,并且从列1开始 
	         System.out.println(pass);
	     } 
		 //操作完成以后关闭JDBC对象,要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反: 
		 //关闭顺序1、关闭记录集,2、关闭声明,3、关闭连接对象
		 JdbcUtil.close(conn, stmt, rs);
	  } catch (SQLException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	  }
	}
}

2、分析

       程序开发过程中,存在很多问题:首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

       上述的用户查询案例,如果同时有1000人访问,就会不断的有数据库连接、断开操作:

线程池实现原理_最通俗易懂的解读比特币相关原理

通过上面的分析,我们可以看出来,“数据库连接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。原理如下:

线程池实现原理_最通俗易懂的解读比特币相关原理

二、技术演进出来的数据库连接池

       由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

       我们自己尝试开发一个连接池,来为上面的查询业务提供数据库连接服务:

       ①   编写class 实现DataSource 接口

       ②   在class构造器一次性创建10个连接,将连接保存LinkedList中

       ③   实现getConnection  从 LinkedList中返回一个连接

       ④   提供将连接放回连接池中方法

1、实现mysql数据库连接池代码 

public class MyDataSource implements DataSource {
    //链表实现栈结构
    privateLinkedList<Connection> dataSources = new LinkedList<Connection>();
    //无参构造器,初始化连接数量
    public MyDataSource() {
         //一次性创建10个连接
         for(int i = 0; i < 10; i++) {
            try {
              //1、获取数据库连接对象
              Connection conn = JdbcUtil.getConnection();
              //2、将连接加入连接池中
              dataSources.add(con);
            } catch (Exception e) {
              e.printStackTrace();
          }
       }
     }
 
     @Override
     public Connection getConnection() throws SQLException {
         //取出连接池中一个连接
         final Connection conn = dataSources.removeFirst(); //删除第一个连接返回
         return conn;
     }
 
     //将连接放回连接池
     public void releaseConnection(Connection conn) {
         dataSources.add(conn);
     }
}

这就是数据库连接池的原理,它大大提供了数据库连接的利用率,减小了内存吞吐的开销。我们在开发过程中,我们只关注我们的业务代码的开发,就不需要再关心数据库连接的问题,自然有数据库连接池帮助我们处理。但连接池需要考虑的问题不仅仅如此,还有更多问题需要考虑,在下一节内容中具体分享。

欢迎广大开发者朋友交流,学习,笔者电话(微信):18629374628

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/192999.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • SQL Server备份集中的数据库备份与现有的数据库不同的解决

    SQL Server备份集中的数据库备份与现有的数据库不同的解决在SQLServer2005和2008中,如果您新建了数据库,打算还原数据库备份的话,如果两者的数据库结构等不同的话,就会提示:备份集中的数据库备份与现有的数据库不同……之类的错误,如下图。巧的很,今天烈火小编的一位朋友也遇到这样的问题,我们一起来看看解决方法。其实解决方法很简单,就是在左侧的选项中,将“覆盖现有数据库”打上勾就可以了。如下图:

  • 重建二叉树(Java)

    重建二叉树(Java)题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。链表的结点定义如下:structListNode{ intm_nKey; ListNode*m_pNext;}第一思路:我的第一思路是从头到尾输出类比数组那样,于是乎想把链表中的链表结点的指针反转过来,改变链表的方向,然后实现从头到尾输出(结果为从尾到头输出),可是发现修改链表的指针,反转链表的结构比较麻烦。于是乎放弃。最优…

  • ruby语言是什么东西

    ruby语言是什么东西1、简介Ruby是日本的YukihiroMatsumoto写的,简单易学的面向对象的脚本语言,像perl一样,有丰富的文字处理、系统管理等丰富功能,但是ruby要简单,容易理解和扩充。跟pyth

  • ViewGroup.LayoutParams 和 MeasureSpec

    ViewGroup.LayoutParams 和 MeasureSpec1.LayoutParams LayoutParams 是ViewGroup的内部静态类,ViewGroup的子类(如RelativeLayout,LinearLayout,FrameLayout)都有其对应的   ViewGroup.LayoutParams的子类,如RelativeLayoutParams LayoutParams的作用:指定视图View 的高度(heig…

  • 素数算法的优化之路

    素数算法的优化之路素数算法的优化之路

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号