早期我们怎么进行数据库操作呢?
1、原理:一般来说,Java应用程序访问数据库的过程是:
- 加载数据库驱动程序;
- 通过jdbc建立数据库连接;
- 访问数据库,执行SQL语句;
- 断开数据库连接。
2、代码
1 //查询所有用户
2 Public void FindAllUsers(){
3 //1、装载sqlserver驱动对象
4 DriverManager.registerDriver(new SQLServerDriver());
5 //2、通过JDBC建立数据库连接
6 Connection con = DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer","sa","123");
7 //3、创建状态
8 Statement state = con.createStatement();
9 //4、查询数据库并返回结果
10 ResultSet result = state.executeQuery("select * from users");
11 //5、输出查询结果
12 while(result.next()){
13 System.out.println(result.getString("email"));
14 }
15 //6、断开数据库连接
16 result.close();
17 state.close();
18 con.close();
19 }
3、分析
程序开发过程中,存在很多问题:
首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至上千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。
其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄露,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾忌的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。
通过上面的分析,我们可以看出,“数据库连接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理,其实我们查询玩数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库链接和断开的操作时间消耗。原理如下:
技术演进出来的数据库连接池
由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个著名的设计模式:资源池设计模式。该模式正是为了解决资源的频繁分配、释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本系思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽地与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发、测试及性能调整提供依据。
我们自己尝试开发一个连接池,来为上面的查询业务提供数据库连接服务:
1)编写class实现DataSource接口;
2)在class的构造器一次性创建10个连接,将连接保存在LinkedList中;
3)实现getConnection,从LinkedList中返回一个连接;
4)提供将连接放回连接池中的方法;
1、连接池代码
1 Pubic class MyDataSource implements DataSource{
2 //因为LinkedList是用链表实现的,对于增删实现起来比较容易
3 LinkedList dataSources = new LinkedList();
4 //初始化连接数量
5 public MyDataSource(){
6 //问题:每次new MyDataSource都会建立10个连接,可使用单例设计模式解决此问题。
7 for(int i=0;i<10;i++){
8 try{
9 //1、装载sqlserver驱动对象
10 DriverManager.registerDriver(new SQLServerDriver())
11 //2、通过JDBC建立数据库连接
12 Connection con =DriverManager.getConnection("jdbc:sqlserver://192.168.2.6:1433;DatabaseName=customer","sa","123");
13 //3、将连接加入连接池中
14 dataSources.add(con);
15 }catch(Exception e){
16 e.printStackTrace();
17 }
18 }
19 }
20 public Connection getConnection() throws SQLException{
21 //取出连接池中一个连接
22 final Connection conn = dataSources.removeFirst();//删除第一个连接返回
23 return conn;
24 }
25 //将连接放回连接池
26 public void releaseConnection(Connection conn){
27 dataSources.add(conn);
28 }
29 }
2、使用连接池重构我们的用户查询函数
1 //查询所有用户
2 Public void FindAllUsers(){
3 //1、使用连接池建立数据库连接
4 MyDataSources dataSources = new MyDataSources();
5 Connection conn = dataSources.getConnection();
6 //2、创建状态
7 Statement state = con.createStatement();
8 //3、查询数据库并返回结果
9 ResultSet result =state.executeQuery("select * from users");
10 //4、输出查询结果
11 while(result.next()){
12 System.out.println(result.getString("email"));
13 }
14 //5、断开数据库连接
15 result.close();
16 state.close();
17 //6、归还数据库链接给连接池
18 dataSources.releaseConnection(conn);
19 }
连接池的工作原理:
连接池的核心思想是连接的复用,通过建立一个数据库连接池以及一套连接使用、分配和管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁简历和关闭的开销。
连接池的工作原理主要由三部分组成,分别为连接池的建立,连接池中连接的使用管理,连接池的关闭。
第一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中建立几个连接对象,以便使用时能从连接池中获取。Java中提供了很多容器类,可以方便的构建连接池,例如Vector(线程安全类)、linkedlist等。
第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其策略是:
当客户请求数据库链接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给用户使用并作相应处理(即标记该连接为正在使用,引用计数加1);如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没有达到最大连接数,就重新创建一个连接给请求的用户;如果达到,就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。
当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过了就从连接池中删除该链接,并判断当前连接池内总的连接数是否小于最小连接数,若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。
第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关资源,该过程正好与创建相反。
连接池的主要优点:
1)减少连接的创建时间。连接池中的连接是已准备好的,可以重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。
2)更快的系统响应速度。数据库连接池在初始化过程中,往往已经创建了若干个数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3)统一的连接管理。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统的连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了系统在大量用户应用时的稳定性。