数据库连接池技术

hibernate 学习笔记 专栏收录该内容
5 篇文章 0 订阅

目录

JDBC 操作数据库

<提示:JDBC -ODBC 桥连接已经不再广泛使用. 淘汰的技术>

JDBC-ODBC 桥

JDBC-ODBC桥是一个JDBC驱动程序。完成了从JDBC操作带ODBC操作之间的转换工作。允许JDBC驱动程序被用作ODBC的驱动程序。使用JDBC-ODBC桥连接数据库的步骤是:

(1) 首先加载JDBC-ODBC桥的驱动程序。代码如下:
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
Class类是java.lang包中的一个类,通过该类的静态方法forName()可加载sun.jdbc.odbc包中的JdbcOdbcDriver类来建立JDBC-ODBC桥连接器。

(2)使用java.sql包中的Connection接口,并通过DriverManager类的静态方法getConnection()创建连接对象。格式如下:
Connection conn = DriverManager.getConnection(“jdbc:odbc:数据源名字” , “user name” , “password”);
数据源必须给出一个简短的描述名。假设没有设置user name和password,要与数据源tom交换数据,建立Connection对象的代码如下:
Connection conn = DriverManager.getConnection(“jdbc.odbc:tom”,”“,”“);

(3)向数据库发送SQL语句。使用Statement接口声明一个SQL语句对象,并通过刚才创建的连接数据库对象conn的createStatement()方法创建这个SQL对象。代码如下:
Statement sql = conn.createStatement();
JDBC-ODBC桥作为连接数据库的过渡性技术,现在已经不被Java技术广泛应用,现在广泛应用的是JDBC技术。但并不表示JDBC-ODBC桥技术已经被淘汰。由于ODBC技术被广泛地使用,使得Java可以利用JDBC-ODBC桥可以访问几乎所有的数据库。JDBC-ODBC桥作为sun.jdbc.odbc包与JDK一起自动安装,不需要特殊配置。

1.通过JDBC-ODBC 桥连接SQL Server 数据库
建立数据库连接,需要指定数据库的驱动和路径。
指定驱动:
String driverClass=”sun.jdbc.odbc.JdbcOdbcDriver”;

采用JDBC-ODBC方式连接数据库,该参数指定的是连接方式,并不需要引入驱动包。
指定路径:
String url=”jdbc:odbc:db_database05”;

以下是win10操作系统中的ODBC 配置

1.打开控制面板-管理工具-找到ODBC数据源-系统DSN-添加
如下图:

选择使用的数据库

添加数据源

由于基本上用不到所以只是做个简介.

JDBC 连接数据库

JDBC是Java连接数据库的一种非常快速和有效的方法。但是JDBC不能直接使用,必须配合数据库提供商所提供的数据库连接驱动才能实现数据库的连接。

使用JDBC连接数据库主要分为3个步骤:获取数据库连接驱动、指定数据库连接字符串和通过驱动管理器管理驱动。
获取数据库连接的驱动,在Java中主要使用Class.forName来实现。Class 类的实例表示正在运行的Java应用程序中的类和接口。其自身并没有公共构造方法,Class 类是在加载时由 Java 虚拟机及通过调用类加载器中的defineClass方法自动构造的。
数据库连接字符串主要由连接数据库所使用驱动器、服务器的IP地址、数据库名称以及连接用户名和密码几部分组成。
通过驱动管理器管理驱动是使用DriverManager类来实现的,该类的主要功能是将数据库连接字符串转换成与其对应的数据库连接接口,以实现数据库的连接。

连接数据库

import java.sql.*; //导入java.sql包
public class Conn { // 创建类Conn
      Connection con; // 声明Connection对象
      public Connection getConnection(){                    //建立返回值为Connection的方法
                  try {
                        // 加载驱动
                        Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
                        System.out.println("数据库驱动加载成功");                                       (1)
                  } catch (ClassNotFoundException e) {
                         e.printStackTrace();
                  }
                  try {
                        // 连接数据库
                        con=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;" +
                                    "DatabaseName=db_jdbc","sa","");                                                                            (2)
                        System.out.println("数据库连接成功");
                  } catch (SQLException e) {
                        e.printStackTrace();
                  } 
                  return con;                                                 //按方法要求返回个Connection对象
            }
       // 主方法
      public static void main(String[] args) {
            Conn c = new Conn(); // 创建本类对象
            c.getConnection(); // 调用连接数据库方法
      }
}

* 向数据库发送SQL 语句 *
实例getConnection()方法,只是获取与数据库的连接。要执行SQL语句首先要获得Statement类对象。通过创建的连接数据库对象con的createStatement()方法可获得Statement对象。

try {
   Statement sql = con.createStatement();
} catch (SQLException e) {
   e.printStackTrace();
}

* 处理查询结果集

有了Statement对象以后,可调用相应的方法实现对数据库的查询和修改。并将查询的结果集存放在ResultSet类的对象中。例如如下语句可返回一个ResultSet对象

try {
   Connection con = ....   // 省略部分代码
   // 获取 Statement
   Statement stmt = con.createStatement();
   // 获取结果集
   ResultSet res = stmt.executeQuery("select * from tb_emp");
   res.close();
   stmt.close();
   con.close();
} catch (Exception e) {
   e.printStackTrace();
}

运行结果为返回一个ResultSet对象,ResultSet对象一次只可以看到结果集中的一行数据,使用该类的next()方法可将光标从当前位置向后或下移一行。

* 顺序查询*
ResultSet类的next()方法的返回值是boolean类型的数据,当游标移动到最后一行之后会返回false。下面的实例就是将数据表tb_emp中的全部信息显示在控制台上。

import java.sql.*; //导入java.sql包

public class Gradation { // 创建类
   static Connection con; // 声明Connection对象
   static Statement sql; // 声明Statement对象
   static ResultSet res; // 声明ResultSet对象

   public Connection getConnection() { // 连接数据库方法
      try {
         // 加载驱动
         Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
         // 创建数据库连接
         con = DriverManager.getConnection(
               "jdbc:microsoft:sqlserver://localhost:1433;"
                     + "DatabaseName=db_jdbc", "sa", "111");
      } catch (Exception e) {
         e.printStackTrace();
      }
      return con;
   }
   public static void main(String[] args) { // 主方法
      Gradation c = new Gradation(); // 创建本类对象
      con = c.getConnection(); // 与数据库建立连接
      try {
         sql = con.createStatement(); // 实例化Statement对象
         res = sql.executeQuery("select * from tb_stu"); // 执行SQL语句,返回结果集
         while (res.next()) { // 如果当前语句不是最后一条则进入循环
            String id = res.getString("id"); // 获取列名是“id”的字段值
            String name = res.getString("name"); // 获取列名是“name”的字段值
            String sex = res.getString("sex"); // 获取列名是“sex”的字段值
            String brithday = res.getString("brithday"); // 获取列名是“brithday”的字段值
            System.out.print("编号:" + id); // 将列值输出
            System.out.print(" 姓名:" + name);
            System.out.print(" 性别:" + sex);
            System.out.println(" 生日:" + brithday);
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

* 模糊查询 *

SQL语句中提供了LIKE操作符进行模糊查询,可使用“%”来代替0个或多个字符,使用下划线“_”来代替一个字符。例如,查询姓张的同学信息,SQL语句如下。

import java.sql.*; //导入java.sql包

public class Train { // 创建类Train
   static Connection con; // 声明Connection对象
   static Statement sql; // 声明Statement对象
   static ResultSet res; // 声明ResultSet对象

   public Connection getConnection() { // 与数据库连接方法
      try {
         Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
         con = DriverManager.getConnection(
               "jdbc:microsoft:sqlserver://localhost:1433;"
                     + "DatabaseName=db_jdbc", "sa", "");
      } catch (Exception e) {
         e.printStackTrace();
      }
      return con;
   }

   public static void main(String[] args) { // 主方法
      Train c = new Train(); // 创建本类对象
      con = c.getConnection(); // 获取与数据库的连接
      try { // try语句捕捉异常
         sql = con.createStatement(); // 实例化Statement对象
         res = sql.executeQuery("select * from tb_stu where name like '张%'");// 执行SQL语句
         while (res.next()) { // 如果当前记录不是结果集中的最后一条,进入循环体
            String id = res.getString(1); // 获取id字段值
            String name = res.getString("name"); // 获取name字段值
            String sex = res.getString("sex"); // 获取sex字段值
            String brithday = res.getString("brithday"); // 获取brithday字段值
            System.out.print("编号:" + id); // 输出信息
            System.out.print(" 姓名:" + name);
            System.out.print(" 性别:" + sex);
            System.out.println(" 生日:" + brithday);
         }
      } catch (Exception e) { // 处理异常
         e.printStackTrace(); // 输出异常信息
      }
   }
}

* 预处理语句 *

向数据库发送一个SQL语句,数据库中的SQL解释器负责把SQL语句生成底层的内部命令,然后执行该命令。完成相关的数据操作。如果不断地向数据库提交SQL语句肯定会增加数据库中SQL解释器的负担。影响执行的速度。
对于JDBC,可以通过Connection对象的prepareStatement(String sql)方法对SQL语句进行编译预处理,生成数据库底层的内部命令,并将该命令封装在PreparedStatement对象中。通过调用该对象的相应方法执行底层数据库命令。这样应用程序能针对连接的数据库,实现将SQL语句解释为数据库底层的内部命令,然后让数据库执行这个命令,这样可以减轻数据库的负担,提供了访问数据库的速度。
对SQL进行预处理时可以通过使用通配符“?”来代替任何的字段值。例如:

sql = con.prepareStatement("select * from tb_stu where id = ?");

在执行预处理语句前,必须相应方法来设置通配符所表示的值。例如:
sql.setInt(1,2);
上述语句中的“1”表示从左向右的第几个通配符。“2”表示设置的通配符的值。将通配符的值设置为2后,功能等同于:

sql = con.prepareStatement("select * from tb_stu where id = 2”);

尽管书写两条语句,看似麻烦了一些,但使用预处理语句可使应用程序更容易动态的改变SQL语句中关于字段值条件的设定。
注意:通过setXXX()方法为SQL语句中的参数赋值时,建议利用与参数匹配的方法,也可以利用setObject()方法为各种类型的参数赋值。例如:
sql.setObject(2,’李丽’);
例 本实例预处理语句动态的获取制定编号的同学信息,本实例以查询编号为2的同学信息为例结果预处理语句的用法。

import java.io.*;
import java.sql.*;
public class Prep {                       //创建类Perp
   static Connection con;                 //声明Connection对象
   static PreparedStatement sql;          //声明预处理对象
   static ResultSet res;                  //声明结果集对象
   public Connection getConnection() {    //与数据库连接方法
      try {
         Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
         con = DriverManager.getConnection(
               "jdbc:microsoft:sqlserver://localhost:1433;"
                     + "DatabaseName=db_jdbc", "sa", "");
      } catch (Exception e) {
         e.printStackTrace();
      }
      return con;
   }
   public static void main(String[] args) {   //主方法
      Prep c = new Prep ();                   //创建本类对象
      con = c.getConnection();                //获取与数据库的连接
      try {          
         sql = con.prepareStatement("select * from tb_stu where id = ?"); //实例化预处理对象
         sql.setInt(1, 2);                        //设置参数
         res = sql.executeQuery();               //执行预处理语句
         while (res.next()) {                    //如果当前记录不是结果集中最后一行,则进入循环体
            String id = res.getString(1);        //获取结果集中的第一列的值
            String name = res.getString("name"); //获取name列的列值
            String sex = res.getString("sex");   //获取sex列的列值
            String brithday = res.getString("brithday");    //获取brithday列的列值
            System.out.print("编号:" + id);          //输出信息
            System.out.print(" 姓名:" + name);
            System.out.print(" 性别:" + sex);
            System.out.println(" 生日:" + brithday);
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

* 添加 修改 删除记录 *
可以通过SQL语句对数据进行添加、修改和删除操作。可通过PreparedStatement类的指定参数动态的对数据表中原有数据进行修改操作。并通过executeUpdate()方法执行更新语句。

import java.sql.*; //导入java.sql包
public class Renewal { // 创建类
   static Connection con; // 声明Connection对象
   static PreparedStatement sql; // 声明PreparedStatement对象
   static ResultSet res; // 声明ResultSet对象

   // 建立返回值为Connection的方法
   public Connection getConnection() {
      try {
         // 加载数据库驱动
         Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
         // 创建数据库连接
         con = DriverManager.getConnection(
               "jdbc:microsoft:sqlserver://localhost:1433;"
                     + "DatabaseName=db_jdbc", "sa", "111");
      } catch (Exception e) {
         e.printStackTrace();
      }
      // 按方法要求返回个Connection对象
      return con;
   }
   // 主方法
   public static void main(String[] args) {
      Renewal c = new Renewal(); // 创建本类对象
      con = c.getConnection(); // 调用连接数据库方法
      try {
         sql = con.prepareStatement("select * from tb_stu"); // 查询数据库
         res = sql.executeQuery(); // 执行SQL语句
         System.out.println("执行增加、修改、删除前数据:");
         // 遍历查询结果集
         while (res.next()) {
            String id = res.getString(1);
            String name = res.getString("name");
            String sex = res.getString("sex");
            String brithday = res.getString("brithday");
            System.out.print("编号:" + id);
            System.out.print(" 姓名:" + name);
            System.out.print(" 性别:" + sex);
            System.out.println(" 生日:" + brithday);
         }
         // 创建PrepareStatement对象
         sql = con.prepareStatement("insert into tb_stu values(?,?,?,?)");
         sql.setInt(1, 10);
         sql.setString(2, "张宏"); // 预处理添加数据
         sql.setString(3, "女");
         sql.setString(4, "1993-10-20");
         sql.executeUpdate();
         // 创建PrepareStatement对象
         sql = con
               .prepareStatement("update tb_stu set brithday = ? where id = ?");
         sql.setString(1, "1994-11-02"); // 更新数据
         sql.setInt(2, 2);
         sql.executeUpdate();
         // 创建PrepareStatement对象
         sql = con.prepareStatement("delete from tb_stu where id = ?");
         sql.setInt(1, 1); // 删除数据
         sql.executeUpdate();
         // 查询修改数据后的tb_stu表中数据
         sql = con.prepareStatement("select * from tb_stu");
         res = sql.executeQuery(); // 执行SQL语句
         System.out.println("执行增加、修改、删除后的数据:");
         // 遍历查询结果集
         while (res.next()) {
            String id = res.getString(1);
            String name = res.getString("name");
            String sex = res.getString("sex");
            String brithday = res.getString("brithday");
            System.out.print("编号:" + id);
            System.out.print(" 姓名:" + name);
            System.out.print(" 性别:" + sex);
            System.out.println(" 生日:" + brithday);
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

* Connection 接口 *

Connection接口

* Statement 接口 *

Statement接口

* PreparedStatement *

PreparedStatement接口

* DriverManager 类*
DriverManager类

ResultSet

ResultSet接口

ResultSet接口

开发步骤

(1)数据库连接类的实现,代码如下:

<%! 
    Connection Con;
    public boolean Con() throws SQLException{
        try
        { 
             Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
             String URL = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_database05";
             String user="sa"; 
             String password="";  
             Con = DriverManager.getConnection(URL,user,password);
             return true;
        }
        catch(ClassNotFoundException e)
        {
             return false; 
        }
    }
%>

(2)连接数据库并显示连接成功与失败的提示,代码如下:

<%
if (Con()){
   out.println("数据库连接成功!");
}
else{
   out.println("数据库连接失败!");
}
%>

程序完整代码:

<%@ page language="java" import="java.sql.*" import="java.util.*" pageEncoding="GB2312"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%! 
      Connection Con;
      public boolean Con() throws SQLException{
            try
            { 
                  Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
                  String URL = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_database05";
                  String user="sa"; 
                  String password="";  
                  Con = DriverManager.getConnection(URL,user,password);
                  return true;
            }
            catch(ClassNotFoundException e)
            {
                  return false; 
            }
      }
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>通过JDBC连接SQL Server数据库</title>

      <meta http-equiv="pragma" content="no-cache">
      <meta http-equiv="cache-control" content="no-cache">
      <meta http-equiv="expires" content="0">    
      <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
      <meta http-equiv="description" content="This is my page">
      <!--
      <link rel="stylesheet" type="text/css" href="styles.css">
      -->

  <meta http-equiv="Content-Type" content="text/html; charset=gb2312"><style type="text/css">
<!--
body {
      background-image: url();
}
.style1 {
      color: #FFFFFF;
      font-weight: bold;
}
-->
  </style></head>

  <body>
            <div align="center">
                  <table width="546" height="196" border="0" cellpadding="0"
                        cellspacing="0" background="1.gif">
                        <tr>
                              <td valign="middle">
                                    <div align="center">
                                          <div align="center">
                                                <p>
                                                      <%
                                                               if (Con()) {
                                                               out.println("数据库连接成功!");
                                                        } else {
                                                               out.println("数据库连接失败!");
                                                        }
                                                      %>
                                                      <br>&nbsp;
                                              <% 
                                          String SQL = "Select * From ClassList_Tab";
                                          Statement Smt; 
                                 ResultSet Rs;
                                 Smt = Con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
                                 Rs = Smt.executeQuery(SQL);
                                          %> 
                                            </p>
                                                <table width="413" border="0" cellspacing="0" cellpadding="0">
                                  <tr>
                                    <td width="86"><div align="left">课程列表</div></td>
                                    <td width="80"><div align="left">课程名称</div></td>
                                    <td width="82"><div align="left">开课时间</div></td>
                                    <td width="78"><div align="left">学时</div></td>
                                    <td width="87"><div align="left">课程类别</div></td>
                                  </tr>
                                  <% 
                                  for (int i=0 ;i<2 ;i++){
                                  Rs.next();
                                  %>
                                  <tr>
                                    <td><div align="left"><%=Rs.getString("CID")%></div></td>
                                    <td><div align="left"><%=Rs.getString("CName")%></div></td>
                                    <td><div align="left"><%=Rs.getString("CStartDate")%></div></td>
                                    <td><div align="left"><%=Rs.getString("CPeriod")%></div></td>
                                    <td><div align="left"><%=Rs.getString("CType")%></div></td>
                                  </tr>
                                  <% 
                                  }
                                  %>
                                </table>
                                                <p>&nbsp;

                                            </p>
                                                <p>

                                                </p>
                                          </div>
                                    </div>
                              </td>
                        </tr>
              </table>
                  <p>&nbsp;

              </p>
            </div>
  </body>
</html>

DBCP 连接池

本实例在使用数据库连接池连接数据库的时候主要用到了BasicDataSource类,BasicDataSource类位于org.apache.tomcat.dbcp.dbcp包中,声明语法如下所示:

public class BasicDataSource extends Object implements DataSource
BasicDataSource类主要通过JavaBeans的形式来配置数据库连接池参数。

(1)setDriverClassName()方法,用于设置数据库驱动类,声明语法如下所示:

public void setDriverClassName(String driverClassName)

driverClassName:数据库驱动类名称。
在本实例中设置数据库驱动类的关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");

(2)setUrl()方法,用于设置数据库连接字符串,声明语法如下所示:
public void setUrl(String url)
url:连接数据库字符串。
在本实例中设置数据库连接字符串的关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setUrl("jdbc:mysql://localhost:3306/db_database02");

(3)setUsername()方法用于设置连接数据库的用户名,声明语法如下所示:
public void setUsername(String username)
username:数据库用户名。
在本实例中设置连接数据库用户名的关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setUsername("mr");

(4)setPassword()方法用于设置连接数据库的密码,声明语法如下所示:

public void setPassword(String password)

password:数据库密码。
在本实例中设置连接数据库密码的关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setPassword("mrsoft");

(5)setInitialSize()方法用于设置数据库连接池初始化的时候创建的连接数量,声明语法如下所示:

public void setInitialSize(int initialSize)

initialSize:连接池初始连接数量。
在本实例中将连接池初始化时的连接数量设置为5,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
dbs.setInitialSize(5);

(6)setMinIdle()方法用于设置连接池内空闲连接的最小数量,声明语法如下所示:

public void setMaxIdle(int maxIdle)

maxIdle:最小空闲连接数。
在本实例中将最小空闲连接数量设置为2,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setMinIdle(2);

(7)setMaxActive()方法用于设置连接池内最大活动连接的数量。

public void setMaxActive(int maxActive)

maxActive:最大活动连接数。
在本实例中将最大活动连接数量设置5,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setMaxActive(5);

(8)setMaxWait()方法用于设置当池内没有可用连接时,等待的最大时间,声明语法如下所示:

public void setMaxWait(long maxWait)

maxWait:最大等待时间。
在本实例中将等待的最大时间设置为10000毫秒,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setMaxWait(10000);

(9)setMaxIdle()方法用于设置连接池内最大空闲连接的数量。

public void setMinIdle(int minIdle)

minIdle:最大空闲连接数。
在本实例中将连接池内允许的最大空闲连接数量设置为4,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
bds.setMaxIdle(4);

(10)getConnection()方法用于从连接池中获取连接,声明语法如下所示:

public Connection getConnection() throws SQLException

在本实例中获取数据库连接,关键代码如下所示:

……//省略部分代码
bds = new BasicDataSource();
Connection con = bds.getConnection();

(1)编写DBPool类,用于初始化一个数据库连接池,关键代码如下所示:

public class DBPool {
    public static BasicDataSource bds;                     //声明静态的BasicDataSource
    private static DBPool dbPool;                      //声明静态的DBPool
    private static String driver = "com.mysql.jdbc.Driver";              //数据库驱动类
    private static String url = "jdbc:mysql://localhost:3306/db_database02";            //数据库连接字符串
    private static String name = "mr";         //数据库用户名
    private static String password = "mrsoft";    //数据库密码
    static {
        dbPool = new DBPool();              //实例化一个DBPool对象
    }
    //构造方法
    public DBPool() {
        bds = new BasicDataSource();             //创建BasicDataSource对象
        //配置数据库连接参数
        bds.setDriverClassName(driver);   //数据库驱动
        bds.setUrl(url);                   //数据库连接字符串
        bds.setUsername(name);              //数据库名称
        bds.setPassword(password);        //数据库密码
        bds.setInitialSize(5);             //初始化时连接数量
        bds.setMinIdle(2);                //最小空闲连接数
        bds.setMaxActive(5);            //最大活动连接数
        bds.setMaxWait(10000);              //最大等待时间,单位毫秒
        bds.setMaxIdle(4);               //最大空闲连接数
    }
}

(2)在DBPool类中编写getInstance()方法和getConnection()方法,用于从连接池中获取连接,关键代码如下所示:

public final Connection getConnection() {
    try {
        return bds.getConnection(); //返回一个数据库连接
    } catch (SQLException ex) {
        ex.printStackTrace();
        return null;                   //如果出现异常返回null
    }
}
public final static DBPool getInstance() {
    return dbPool;
}

(3)在DBPool类中编写freeConnection()方法,用于将使用完的数据库连接释放,关键代码如下所示:

public final static void freeConnection(Connection conn) {
    if (conn != null) {
        try {
            conn.close();              //关闭连接
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

使用DBCP连接池需要commons.dbcp.jar,同时DBCP连接池还依赖Apache的另外2个开源项目commons.collections.jar和commons.pool.jar,这些jar包都可以在http://www.apache.org上下载到,下载这三个jar包并将其添加到项目中就可以使用了。在Tomcat服务器中已经内置了DBCP连接池所需要的包,所以在使用Tomcat服务器时不需要另外下载jar文件了。

(4)新建demo.jsp页面,用于显示在不同情况下,连接池内连接数量的变化情况,关键代码如下所示:

<html>
    <body>
        <!-- 初始化连接池 -->
        --------------------连接池初始化---------------------- <br>
        初始化连接数:<%= DBPool.bds.getInitialSize()%><br>
        最小空闲连接数:<%= DBPool.bds.getMinIdle()%><br>
        最大空闲连接数:<%= DBPool.bds.getMaxIdle()%><br>
        最大等待时间(毫秒):<%= DBPool.bds.getMaxWait()%><br>
        最大活动连接数:<%= DBPool.bds.getMaxActive()%><br>
        当前活动的连接数:<%= DBPool.bds.getNumActive()%><br>
        当前空闲的连接数:<%= DBPool.bds.getNumIdle()%><br>
        <table width="700px" align="center" border="1">
            <tr align="center">
                <td width="80px">员工编号</td>
                <td width="90px">员工姓名</td>
                <td width="80px">员工姓别</td>
                <td width="80px">员工年龄</td>
                <td width="200px">所在部门</td>
                <td>职务</td>
            </tr>
            <!-- 创建一个连接对数据库进行查询 -->
        <%
        Connection con = DBPool.getInstance().getConnection();
        Statement st = con.createStatement();
        ResultSet rs = st.executeQuery("SELECT * FROM tb_employee");
        while(rs.next()){
        %>
            <tr align="center">
                <td><%= rs.getInt("id") %></td>
                <td><%= rs.getString("name") %></td>
                <td><%= rs.getString("sex") %></td>
                <td><%= rs.getString("age") %></td>
                <td><%= rs.getString("dept") %></td>
                <td><%= rs.getString("duty") %></td>
            </tr>
        <%
        }
        rs.close();
        st.close();
        %>
        </table>
        --------------------调用获得连接方法之后---------------------- <br>
        当前活动的连接数:<%= DBPool.bds.getNumActive()%><br>
        当前空闲的连接数:<%= DBPool.bds.getNumIdle()%><br>
        <!-- 将连接释放后 -->
        --------------------调用释放连接方法之后---------------------- <br>
        <%
        DBPool.freeConnection(con);
        %>
        当前活动的连接数:<%= DBPool.bds.getNumActive()%><br>
        当前空闲的连接数:<%= DBPool.bds.getNumIdle()%><br>
    </body>
</html>

TOMCAT 连接池

数据库连接池是当今Java程序控制开发中常用的技术,其主要用于解决高负载数据库访问造成的性能问题,提高数据库的使用效率。本实例将介绍如何通过Tomcat连接池访问数据库。

连接池技术原理如图2所示。连接的建立、断开都由连接池自身来管理,当程序需要建立数据库连接时,只需从内存中取一个来用而不用新建。同样,使用完毕后,将其放回内存即可。另外,连接池还可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
数据源是在JDBC 2.0中引入的一个概念。在JDBC 2.0扩展包中定义了javax.sql.DataSource接口来描述数据源。如果希望通过Tomcat连接池建立一个数据库连接,通过查询在JNDI服务(Java名称和目录接口服务)中的数据源,可以从数据源中获取相应的数据库连接。这样就只能提供一个逻辑名称,而不是数据库登录的具体细节。

(1)把数据库驱动包(mssqlserver.jar、msutil.jar、msbase.jar)复制到%Tomcat_HOME%\ common\lib文件夹下。
(2)配置%Tomcat_HOME %\conf\server.xml文件。笔者使用的是Tomcat 5.5服务器,打开Tomcat 5.5\conf\server.xml文件,在该文件中的之间加入如下代码:

<Context path="/ connectionPool"  docBase=" connectionPool" debug="5" reloadable="true" corssContext="true">
<Resource name="jdbc/ConnectionPool"
auth="Container"
type="javax.sql.DataSource"
maxActive="20"
maxIdle="30"
maxWait="10000"
username="sa"
password=""
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=db_database05"/>
</Context>

参数说明:

l path:指定访问Web应用程序的URL入口。

l docBase:指定Web应用程序的文件路径,可以是绝对路径,也可以是相对于Host的appBase属性的相对路径。

l maxActive:连接池处于活动状态的数据库连接的最大数目,取0表示不受限制。

l maxIdle:连接池处于空闲状态的数据库连接的最大数目,取0表示不受限制。

l maxWait:连接池中数据库连接处于空闲状态的最长时间(以毫秒为单位),取0表示无限期等待时间。

l username:数据库登录名。

l password:数据库登录密码。

l driverClassName:指定数据库的JDBC驱动程序。

l url:指定连接数据库URL,db_database05是数据库名称。

(3)创建index.jsp页面文件,显示数据库是否已经连接,关键代码如下:

<%@ page import="java.sql.*"%>
<%@ page import="javax.sql.*"%>
<%@ page import="javax.naming.*"%>
<div align='center'>
<%
DataSource ds = null;
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try{
InitialContext ctx=new InitialContext();
ds=(DataSource)ctx.lookup("java:comp/env/jdbc/ConnectionPool");
conn = ds.getConnection();
}
catch(Exception e){
e.printStackTrace();
}
%>
<%if(conn!=null){
try{
stmt=conn.createStatement();
rs=stmt.executeQuery("select * from tb_userOperation");
%>
取得数据库连接成功!!!</span>
<table width="220" border="1">
  <tr align="center">
    <td>姓名</td>
    <td>年龄</td>
    <td>职业</td>
  </tr>
  <%while(rs.next()){
%>
  <tr align="center">
    <td><%=rs.getString("name")%></td>
    <td><%=rs.getString("sex")%></td>
    <td><%=rs.getString("profession")%></td>
  </tr>
  <%}%>
</table>
<%
}catch(Exception e){
out.print("32131");
}%>
<%}%>
(4)在web.xml文件引用连接池,关键代码如下:
<resource-ref>
    <description>SQL server text app</description>
    <res-ref-name>jdbc/ConnectionPool</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
     <res-auth>Container</res-auth>
</resource-ref>

(4)在web.xml文件引用连接池,关键代码如下:

<resource-ref>
    <description>SQL server text app</description>
    <res-ref-name>jdbc/ConnectionPool</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
     <res-auth>Container</res-auth>
</resource-ref>

(5)程序完整代码如下:

<%@ page contentType="text/html; charset=gb2312" language="java"  errorPage="" %>
<%@ page import="java.sql.*"%>
<%@ page import="javax.sql.*"%>
<%@ page import="javax.naming.*"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>通过Tomcat连接池连接SQL Server数据库</title>
<style type="text/css">
<!--
.style1 {color: #0000FF}
-->
</style>
</head>

<body>
<div align='center'>
<span class="style1">
<%
DataSource ds = null;
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;

try{
InitialContext ctx=new InitialContext();
ds=(DataSource)ctx.lookup("java:comp/env/jdbc/ConnectionPool");
conn = ds.getConnection();
}
catch(Exception e){
e.printStackTrace();
}
%>
<%if(conn!=null){
try{
stmt=conn.createStatement();
rs=stmt.executeQuery("select * from tb_userOperation");
%>
取得数据库连接成功!!!</span>
<table width="220" border="1">
  <tr align="center">
    <td><span class="style1">姓名</span></td>
    <td><span class="style1">年龄</span></td>
    <td><span class="style1">职业</span></td>
  </tr>
  <%while(rs.next()){
%>
  <tr align="center">
    <td><%=rs.getString("name")%></td>
    <td><%=rs.getString("sex")%></td>
    <td><%=rs.getString("profession")%></td>
  </tr>
  <%}%>
</table>
<%
}catch(Exception e){

}%>
<%}%>
</body>
</html>

★★★★★WEB-INF\web.xml★★★★★

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
  <display-name>web</display-name>
  <resource-ref>
  <description>SQL server text app</description>
  <res-ref-name>jdbc/ConnectionPool</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
       <res-auth>Container</res-auth>
</resource-ref>
</web-app>

利用WebLogic连接池访问数据库不但可以提高网站的访问速度,而且可以保证数据库的安全。下面将介绍如何通过WebLogic连接池连接SQL Server 2000数据库。

通过WebLogic连接池连接数据库时,首先需要获得一个引用本地服务器上JNDI服务的Context对象,然后再通过Context对象的lookup()方法,得到JNDI名字服务中的DataSource对象的引用,最后通过DataSource对象的getConnection()方法获得一个Connection对象的实例。关键代码如下:

Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("database05JNDI");
conn = ds.getConnection();
其中,DataSource对象代表了数据源,一般由数据库驱动程序厂商实现,其主要方法如下。
l     getConnection():获取一个Connection对象。
l     getConnection(String username,String password):获取一个Connection对象。
l     getLogWriter():从DataSource获得LogWriter对象,该对象是PrinterWriter对象的实例。
l     setLogWriter(PrintWriter out):设置DataSource的LogWriter对象。
l     getLoginTimeout():获得DataSource尝试连接数据库的最大时间。
l    setLoginTimeout():设置DataSource尝试连接数据库的最大时间。

(1)在SQL Server企业管理器中,创建一个名称为mr的登录用户,该用户的登录密码为mrsoft,并指定该用户可以访问本实例所用的数据库db_database05。
(2)首先在WebLogic服务控制台中配置名称为database05Pool的数据库连接池,然后配置名称为database05DS的Data Sources数据源,其JNDI名字为database05JNDI。具体方法可参见实例014。
(3)编写连接SQL Server数据库的JavaBean“ConnDB”,将其保存到com.core包中,并定义相应的全局变量,关键代码如下:

package com.core;
import java.sql.*;
import javax.sql.*;
import javax.naming.Context;
public class ConnDB{
    public Connection conn = null;
    public Statement stmt = null;
    public ResultSet rs = null;
    public Context context = null;
}

(4)编写执行查询操作的方法executeQuery(),在该方法中将通过WebLogic服务的JNDI名字访问指定数据源,获取数据库配置信息,并连接数据库。具体代码如下:

public ResultSet executeQuery(String sql) {
    try {
       Context ctx = new InitialContext();
       DataSource ds = (DataSource) ctx.lookup("database05JNDI");
       conn = ds.getConnection();
       stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                          ResultSet.CONCUR_READ_ONLY);
       rs = stmt.executeQuery(sql);
    } catch (Exception ex) {
       System.err.println(ex.getMessage());
    } finally {}
    return rs;
}

(5)在JSP页面中调用executeQuery()方法查询公告信息,关键代码如下:

<jsp:useBean id="conn" scope="page" class="com.core.ConnDB"/>
<%ResultSet rs= conn.executeQuery("select * from tb_BBS");%>

(6)程序完整代码如下:

package com.core;

import java.sql.*;
import javax.sql.*;
import javax.naming.Context;

import javax.naming.*;

public class ConnDB {
    public Connection conn = null;
    public Statement stmt = null;
    public ResultSet rs = null;
    public Context context = null;

    public ConnDB() {}

    /***************************************************
     *method name:      executeQuery()
     *功能:执行查询操作
     *return value: ResultSet
     ****************************************************/
    public ResultSet executeQuery(String sql) {
        try {
            Context ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("database05JNDI");
            conn = ds.getConnection();
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                                        ResultSet.CONCUR_READ_ONLY);
            rs = stmt.executeQuery(sql);
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
        } finally {}
        return rs;
    }

    /***************************************************
     *method name:      close()
     *功能:关闭数据库链接
     *return value:       void
     ****************************************************/
    public void close() {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {}
        try {
            if (stmt != null) {
                stmt.close();
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {}
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {}
    }
}

index.jsp

<%@ page contentType="text/html; charset=GBK" import="java.sql.*"%>
<jsp:useBean id="conn" scope="page" class="com.core.ConnDB"/>
<html>
<head>
<title>
通过WebLogic连接池连接SQL Server数据库
</title>
</head>
<body bgcolor="#ffffff">
<link href="CSS/style.css" rel="stylesheet">
<%ResultSet rs= conn.executeQuery("select * from tb_BBS");%>
  <table width="182" height="155"  border="0" align="center" cellpadding="0" cellspacing="0">
      <tr>
        <td><img src="images/shop_22.gif" width="182" height="58"></td>
      </tr>
      <tr>
        <td height="97" align="center" valign="top" class="tableBorder_l"><table width="88%"  border="0" cellspacing="0" cellpadding="0">
            <%
            int ID_bbs=0;
            String title="";
                try{
            while(rs.next()){
              ID_bbs=rs.getInt(1);
              title=rs.getString(2);
%>
            <tr>
              <td height="24" class="tableBorder_T_dashed"><a href="#"><%=title%></a></td>
            </tr>
<%             }
                }catch(Exception e){
                System.out.println(e.getMessage());
                }%>
        </table></td>
      </tr>
</table>
</body>
</html>

CSS\style.css

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<!--
td {
      font-size: 9pt;     color: #000000;
}
a:hover {
      font-size: 9pt;     color: #FF6600;
}
a {
      font-size: 9pt;     text-decoration: none;  color: #676767;
      noline:expression(this.onfocus=this.blur);
}
img{
      border:0;
}

.word_white{
 color:#FFFFFF;
}
.word_deepgrey{
 color:#999999;
}
.word_orange{
 color:#FF6600;
}
.word_green{
 color:#82CBC8;
}
.noborder{
border:none;
}
.word_gray{
 color:#dddddd;
}
body {
      margin-left: 0px;
      margin-top: 0px;
      margin-right: 0px;
      margin-bottom: 0px;
      background-image:url(../images/bg.gif)
}
.textarea {
      font-family: "宋体";
      font-size: 9pt;
      color: #333333;
      border: 1px solid #999999;
}
.tableBorder {
      border: #D8D8D8 1px solid;
}
.tableBorder_dashed {
      border: #D8D8D8 1px dashed;
}
.tableBorder_l {
      border: #D8D8D8 1px solid;
      border-top-style:none;     
}
.tableBorder_lb {
      border: #D8D8D8 1px solid;
      border-left-style:none;
      border-top-style:none;
}
.tableBorder_l_dashed {
      border: #D8D8D8 1px dashed;
      border-bottom-style:none;
      border-left-style:none;
      border-top-style:none;
}
.tableBorder_T_dashed {
      border: #D8D8D8 1px dashed;
      border-bottom-style:none;
      border-left-style:none;
      border-right-style:none;
}
.tableBorder_LTR_dashed {
      border: #D8D8D8 1px dashed;
      border-bottom-style:none;
}
.tableBorder_B_dashed {
      border: #D8D8D8 1px dashed;
      border-top-style:none;
      border-left-style:none;
      border-right-style:none;
}
.hidden_a_line{
      noline:expression(this.onfocus=this.blur);
}
hr{
border-style:dashed;
color:#CCCCCC;
}

WEB-INF\web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  <display-name>defaultroot</display-name>
</web-app>

WEB-INF\web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">

<weblogic-web-app>
  <context-root>084</context-root>
</weblogic-web-app>

C3P0 连接池

想要用数据库连接池技术来提高程序的执行效率,就要根据服务的性能来配置连接池的参数,本实例在为连接池配置参数的时候主要用到了ComboPooledDataSource类,ComboPooledDataSource类位于com.mchange.v2.c3p0包中,声明语法如下所示:

public final class ComboPooledDataSource
extends com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
implements PooledDataSource, java.io.Serializable, javax.naming.Referenceable

ComboPooledDataSource类主要通过JavaBeans的形式来配置数据库连接池参数,下面介绍一下c3p0连接池常用的参数以及用途。
(1)setDriverClass()方法,用于设置数据库驱动类,声明语法如下所示:

public void setDriverClass(String driverClass)

driverClass:数据库驱动类名称。
在本实例中设置MySQL数据库驱动类的关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");

(2)setJdbcUrl()方法,用于设置连接数据库url,声明语法如下所示:

public void setJdbcUrl(java.lang.String jdbcUrl)

jdbcUrl:数据库连接字符串。
在本实例中设置连接MySQL数据库的连接字符串,关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_database02");  //连接到db_database02数据库

(3)setUser()方法,用于设置连接数据库的用户名,声明语法如下所示:

public void setUser(java.lang.String user)

user:连接数据库的用户名。
在本实例中设置连接数据库的用户名为mr,关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("mr");

(4)setPassword()方法,用于设置连接数据库的密码,声明语法如下所示:

public void setPassword(java.lang.String password)

password:连接数据库的密码。
在本实例中设置连接数据库的密码为mrsoft,关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setPassword("mrsoft");

(5)setInitialPoolSize()方法,用于设置连接池初始化时创建的连接数量,取值应在minPoolSize与maxPoolSize之间,默认值为3,声明语法如下所示:

public void setInitialPoolSize(int initialPoolSize)

initialPoolSize:初始化创建连接的数量。
在本实例中设置初始化数据库连接的数量为8,关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setInitialPoolSize(8);

(6)setMinPoolSize()方法,用于设置连接池中保留的最小连接数,默认值为3,声明语法如下所示:

public void setMinPoolSize(int minPoolSize)

minPoolSize:连接池中最小连接数。
在本实例中设置连接池保留的最小连接数为5,的关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setMinPoolSize(5);

(7)setMaxPoolSize()方法,用于设置连接池中保留的最大连接数,默认值为15,声明语法如下所示:

public void setMaxPoolSize(int maxPoolSize)

maxPoolSize:连接池中最大连接数。
在本实例中设置数据库的关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setMaxPoolSize(10);

(8)setAcquireIncrement()方法,用于设置当连接池中的连接耗尽的时候c3p0一次性新建的连接数,默认值为3,声明语法如下所示:

public void setAcquireRetryAttempts(int acquireRetryAttempts)

acquireRetryAttempts:连接耗尽时一次性新建的连接数。
在本实例中设置连接耗尽时一次性新建3个连接,关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setAcquireIncrement(3);

(9)setAutoCommitOnClose)方法,用于设置连接关闭时将所有未提交的操作回滚,默认值为false,声明语法如下所示:

public void setAutoCommitOnClose(boolean autoCommitOnClose)

autoCommitOnClose:连接关闭时是否自动回滚未提交的操作。
在本实例中设置连接关闭时不自动回滚未提交的操作关键代码如下所示:

……//省略部分代码
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setAutoCommitOnClose(false);

开发步骤

(1)将c3p0数据库连接池驱动包导入到项目中。本实例中使用的c3p0驱动包版本为0.9.1.2,在http://sourceforge.net/projects/c3p0上可以下载到该包。

(2)新建DBPool类,用于初始化一个c3p0数据库连接池,关键代码如下所示:

public class DBPool {
    private static DBPool dbpool;                             //声明DBPool
    public static ComboPooledDataSource dataSource;     //声明ComboPooledDataSource
    static {
        dbpool = new DBPool();                            //实例化dbpool对象
    }
    public DBPool() {                                      //构造方法
        try {
            dataSource = new ComboPooledDataSource();    //实例化ComboPooledDataSource对象
            dataSource.setUser("mr");                  //设置连接数据库用户名
            dataSource.setPassword("mrsoft");           //设置密码
            dataSource.setDriverClass("com.mysql.jdbc.Driver");               //设置数据库驱动类
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db_database02");//设置数据库连接字符串
            dataSource.setAcquireIncrement(3);                   //当连接池中的连接耗尽的时候c3p0一次同时新建的连接数
            dataSource.setAcquireRetryAttempts(30);    //定义在从数据库获取新连接失败后重复尝试的次数
            dataSource.setAcquireRetryDelay(1000);            //两次连接中间隔时间,单位毫秒
            dataSource.setAutoCommitOnClose(false);  //连接关闭时默认将所有未提交的操作回滚。
            dataSource.setCheckoutTimeout(5000);              //获取连接等待时间,超时后抛出异常,0为一直等待
            dataSource.setIdleConnectionTestPeriod(60);      //每60秒检查所有连接池中的空闲连接
            dataSource.setInitialPoolSize(8);                 //初始化时创建8个连接
            dataSource.setMinPoolSize(5);                           //连接池中保留的最小连接数
            dataSource.setMaxPoolSize(10);                        //连接池中保留的最大连接数
            dataSource.setNumHelperThreads(3);                 //允许3个线程同时工作
        } catch (PropertyVetoException ex) {
            ex.printStackTrace();
        }
    }
    /**
     *返回该类的实例
     **/
    public final static DBPool getInstance() {
        return dbpool;
    }
}

(3)在DBPool类中编写getConnection()方法,用于从连接池中获取一个连接,关键代码如下所示:

public final Connection getConnection() {
    try {
        return dataSource.getConnection();
    } catch (SQLException ex) {
        System.out.println("创建连接失败");
        return null;
    }
}

(4)在DBPool类中编写freeConnection()方法,用于释放数据库连接,关键代码如下所示:

public final static void freeConnection(Connection con){
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

(5)新建demo.jsp页面,用于显示在不同情况下,连接池内连接数量的变化情况,关键代码如下所示:

<html>
    <body>
            -----------------------初始化数据库连接池-----------------------<br>
            数据库连接池初始连接数:<%= DBPool.dataSource.getInitialPoolSize()%>;
            数据库连接池保留的最小连接数:<%= DBPool.dataSource.getMinPoolSize()%><br>
            数据库连接池保留的最大连接数:<%= DBPool.dataSource.getMaxPoolSize()%>
            获得连接最大等待时间(毫秒): <%= DBPool.dataSource.getCheckoutTimeout()%><br>
            数据库连接池当前活动连接数:<%= DBPool.dataSource.getNumBusyConnections()%>;
            数据库连接池当前空闲连接数:<%= DBPool.dataSource.getNumIdleConnections()%><br>
            <hr>
            <table width="50%" border="1">
                <tr align="center">
                    <td>学生姓名</td>
                    <td>考试科目</td>
                    <td>考试成绩</td>
                </tr>
                <%
        Connection con = DBPool.getInstance().getConnection();
        new Thread().currentThread().sleep(500);
        Statement st = con.createStatement();
        ResultSet rs = st.executeQuery("SELECT * FROM tb_grade");
        while (rs.next()) {
                %>
                <tr align="center">
                    <td><%= rs.getString("name")%></td>
                    <td><%= rs.getString("subject")%></td>
                    <td><%= rs.getString("grade")%></td>
                </tr>
        <%
        }
        rs.close();
        st.close();
        %>
            </table>
            -----------------------获得一个连接-----------------------<br>
            数据库连接池当前活动连接数:<%= DBPool.dataSource.getNumBusyConnections()%>;
            数据库连接池当前空闲连接数:<%= DBPool.dataSource.getNumIdleConnections()%><br>
            <hr>
            -----------------------连接使用完成释放-----------------------<br>
            <%
                DBPool.freeConnection(con);
                //释放连接会有一定延迟,这里为了显视演示效果,将当前线程延迟100毫秒
                new Thread().currentThread().sleep(100);
            %>
            数据库连接池当前活动连接数:<%= DBPool.dataSource.getNumBusyConnections()%>;
            数据库连接池当前空闲连接数:<%= DBPool.dataSource.getNumIdleConnections()%><br>
        </div>
    </body>
</html>

由于c3p0是异步的,在第一次获取连接的时候为了提高速度,它只会建立满足需求的几个连接,并且在系统空闲的时候将剩于连接建立好,在释放连接的时候也不会立即释放,而是等到系统空闲或连接不够的时候才去释放,为了让页面显示最后结果需要让当前线程暂停执行一小段时

Druid连接池

Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,有不得不使用数据库连接池。数据库连接池有很多选择,c3p0、dhcp、proxool等,druid作为一名后起之秀,凭借其出色的性能,也逐渐印入了大家的眼帘。接下来本教程就说一下druid的简单使用。

首先从 http://repo1.maven.org/maven2/com/alibaba/druid/ 下载最新的jar包。如果想使用最新的源码编译,可以从 https://github.com/alibaba/druid 下载源码,然后使用maven命令行,或者导入到eclipse中进行编译。

和dbcp类似,druid的配置项如下

配置缺 省 值说明
name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字, 格式是:”DataSource-” + System.identityHashCode(this)
jdbcUrl连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username连接数据库的用户名
password连接数据库的密码。如果你不希望密码直接写在配置文件中, 可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
driverClassName根据url自动识别这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName
initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive8最大连接池数量
maxIdle8已经不再使用,配置了也没效果
minIdle最小连接池数量
maxWait获取连接时最大等待时间,单位毫秒。配置了maxWait之后, 缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
poolPreparedStatementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。 在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。作者在5.5版本中使用PSCache,通过监控界面发现PSCache有缓存命中率记录, 该应该是支持PSCache。
maxOpenPreparedStatements-1要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true。 在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100
validationQuery用来检测连接是否有效的sql,要求是一个查询语句。 如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。
testOnBorrowtrue申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdlefalse建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。
timeBetweenEvictionRunsMillis有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun不再使用,一个DruidDataSource只支持一个EvictionRun
minEvictableIdleTimeMillis
connectionInitSqls物理连接初始化的时候执行的sql
exceptionSorter根据dbType自动识别当数据库抛出一些不可恢复的异常时,抛弃连接
filters属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
proxyFilters类型是List, 如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系

表1.1 配置属性

**加入 druid-1.0.9.jar
ApplicationContext.xml**

[html] view plain copy 在CODE上查看代码片派生到我的代码片
< bean name = "transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >     
    < property name = "dataSource" ref = "dataSource" ></ property >  
     </ bean >  
    < bean id = "propertyConfigurer" class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >    
       < property name = "locations" >    
           < list >    
                 < value > /WEB-INF/classes/dbconfig.properties </ value >    
            </ list >    
        </ property >    
    </ bean >  

ApplicationContext.xml配置druid

[html] view plain copy 在CODE上查看代码片派生到我的代码片
<!-- 阿里 druid 数据库连接池 -->  
  < bean id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource"destroy-method = "close" >    
       <!-- 数据库基本信息配置 -->  
       < property name = "url" value = "${url}" />    
       < property name = "username" value = "${username}" />    
       < property name = "password" value = "${password}" />    
       < property name = "driverClassName" value = "${driverClassName}" />    
       < property name = "filters" value = "${filters}" />    
        <!-- 最大并发连接数 -->  
       < property name = "maxActive" value = "${maxActive}" />  
       <!-- 初始化连接数量 -->  
       < property name = "initialSize" value = "${initialSize}" />  
       <!-- 配置获取连接等待超时的时间 -->  
       < property name = "maxWait" value = "${maxWait}" />  
       <!-- 最小空闲连接数 -->  
       < property name = "minIdle" value = "${minIdle}" />    
       <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->  
       < property name = "timeBetweenEvictionRunsMillis" value ="${timeBetweenEvictionRunsMillis}" />  
       <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->  
       < property name = "minEvictableIdleTimeMillis" value ="${minEvictableIdleTimeMillis}" />    
       < property name = "validationQuery" value = "${validationQuery}" />    
       < property name = "testWhileIdle" value = "${testWhileIdle}" />    
       < property name = "testOnBorrow" value = "${testOnBorrow}" />    
       < property name = "testOnReturn" value = "${testOnReturn}" />    
       < property name = "maxOpenPreparedStatements" value ="${maxOpenPreparedStatements}" />  
       <!-- 打开 removeAbandoned 功能 -->  
       < property name = "removeAbandoned" value = "${removeAbandoned}" />  
       <!-- 1800 秒,也就是 30 分钟 -->  
       < property name = "removeAbandonedTimeout" value ="${removeAbandonedTimeout}" />  
       <!-- 关闭 abanded 连接时输出错误日志 -->     
       < property name = "logAbandoned" value = "${logAbandoned}" />  
  </ bean >  

dbconfig.properties

[html] view plain copy 在CODE上查看代码片派生到我的代码片
url: jdbc:mysql:// localhost :3306/ newm  
driverClassName: com.mysql.jdbc.Driver  
username: root  
password: root  
filters: stat  
maxActive: 20  
initialSize: 1  
maxWait: 60000  
minIdle: 10  
maxIdle: 15  
timeBetweenEvictionRunsMillis: 60000  
minEvictableIdleTimeMillis: 300000  
validationQuery: SELECT 'x'  
testWhileIdle: true  
testOnBorrow: false  
testOnReturn: false  
maxOpenPreparedStatements: 20  
removeAbandoned: true  
removeAbandonedTimeout: 1800  
logAbandoned: true  

web.xml

[html] view plain copy 在CODE上查看代码片派生到我的代码片
<!-- 连接池 启用 Web 监控统计功能    start-->  
  < filter >  
     < filter-name > DruidWebStatFilter </ filter-name >  
     < filter-class > com.alibaba.druid.support.http.WebStatFilter </ filter-class >  
     < init-param >  
         < param-name > exclusions </ param-name >  
         < param-value > *. js ,*. gif ,*. jpg ,*. png ,*. css ,*. ico ,/ druid /* </ param-value >  
     </ init-param >  
  </ filter >  
  < filter-mapping >  
     < filter-name > DruidWebStatFilter </ filter-name >  
     < url-pattern > /* </ url-pattern >  
  </ filter-mapping >  
  < servlet >  
     < servlet-name > DruidStatView </ servlet-name >  
     < servlet-class > com.alibaba.druid.support.http.StatViewServlet </ servlet-class >  
  </ servlet >  
  < servlet-mapping >  
     < servlet-name > DruidStatView </ servlet-name >  
     < url-pattern > / druid /* </ url-pattern >  
  </ servlet-mapping >  
  <!-- 连接池 启用 Web 监控统计功能    end-->  

访问监控页面: http://ip:port/projectName/druid/index.html

  • 2
    点赞
  • 0
    评论
  • 8
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值