JDBC和数据库连接池

时间:2021-05-12 11:53:44

  JDBC是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。

● JDBC

● C3P0

● DRUID


 

一.JDBC

1.基本使用

使用 JDBC 操作MySQL数据库时,可以将步骤分为以下7步:

// 1.注册驱动(将mysql的驱动类加载到内存中)
DriverManager.registerDriver(new Driver());
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/db";
String username = "root";
String password = "root";
Connection con = DriverManager.getConnection(url, username, password);
// 3.编写sql
String sql = " ... ";
// 4.获取语句的执行器
Statement statement = con.createStatement();
// 5.执行sql并返回结果集
ResultSet rs = statement.excuteQuery(sql);
// 6.处理结果集
while(rs.next()){ ... }
// 7.释放资源
rs.close();
statement.close();
con.close();

2.PreparedStatement:预编译对象 

为防止 SQL 注入,我们先将sql 传给数据库,将sql语句事先编译好,使用时直接赋真实值,执行sql即可。

// 使用 ? 占位
String sql = "select * from stu where id= ? "
// 创建预编译对象
PreparedStatement pst = con.prepareStatement(sql);
// 设置具体的参数 (第几个 ?, 具体值)
pst.set(1, 2);
// 执行sql
ResultSet rs = pst.executeQuery();
int i = pst.executeUpdate();

3.封装优化

由于Driver类的源码当中有注册驱动的静态代码块,因此我们可以不用自己再去注册(类加载后就完成了注册),同时为了避免硬编码和代码冗余我们将其优化,封装成简单工具类。

1.编写配置文件 :Jdbc.properties

# 数据库驱动配置
# Driver类的全限定类名(加载即完成注册)
jdbc.driver=com.mysql.jdbc.Driver
#        协议  协议   地址       端口  数据库
jdbc.url=jdbc:mysql://localhost:3306/db
# 用户名
jdbc.username=root
# 密码
jdbc.password=root

2.编写工具类 :JdbcUtils

public class JdbcUtils {
    //声明配置信息
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    private static Connection con;
    //静态代码块,类加载时解析配置信息
    static {
        try {
            InputStreamReader is = new InputStreamReader
                (JdbcUtils.class.getResourceAsStream("/jdbc.properties"));
            Properties properties = new Properties();
            properties.load(is);
            driver = properties.getProperty("jdbc.driver").trim();
            url = properties.getProperty("jdbc.url").trim();
            username = properties.getProperty("jdbc.username").trim();  
            password = properties.getProperty("jdbc.password").trim();
            //加载驱动获取连接
            Class.forName(driver);
            con =  DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获取数据库连接(如果连接关闭则重新创建)
    public static Connection getConnection() {
        try {
            if (con.isClosed()) {
                con =  DriverManager.getConnection(
                    url,username,password);
                return con;
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
        return con;
    }
    // 关闭资源(有结果集)
    public static void close(ResultSet rs, Statement s, 
                             Connection con) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (s != null) {
            try {
                s.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    // 关闭资源(无结果集)
    public static void close(Statement s, Connection con) {
        close(null, s, con);
    }
}

3.注意事项

// 需要注意的是
// 1.将jdbc.properties放到src文件下

// 2.解析配置文件时除上述写法还可以使用如下方式(此法针对src下的properties文件):
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("jdbc.driver").trim();
url = bundle.getString("jdbc.url").trim();
username = bundle.getString("jdbc.username").trim();
password = bundle.getString("jdbc.password").trim();

在使用上述方法连接并操作数据库时,若没有按照上面的代码对连接的状态进行检查那么肯定会遇到这样一个异常:No operations allowed after connection closed. 因为我们只创建了一个连接,当完成一个操作后将其关闭,那么下一次操作获得的连接就是已经关闭了的连接,因此会发生此异常!上述代码中对连接进行了状态的判断,比较麻烦。而数据库连接池正是维护着几个连接供我们使用,使用后将其归还至连接池(并不是真的关闭)。

二.C3P0连接池

C3P0是开源的连接池,Hibernate框架默认使用的就是C3P0连接池。使用配置文件创建连接池时注意文件名称“ c3p0-config.xml"不能更改(放在src下)。

1.创建配置文件:c3p0-config.xml

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
      <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db</property>
    <property name="user">root</property>
    <property name="password">root</property>
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">3000</property>
  </default-config>
<!--  指定名称的配置信息 -->
  <named-config name="myc3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>  
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>

2.获取连接池对象

// 关键代码
// 使用默认配置获取连接池对象
ComboPooledDataSource comboPooledDataSource =
    new ComboPooledDataSource();
// 使用指定的配置  (配置名) 获取连接池对象
ComboPooledDataSource comboPooledDataSource = 
    new ComboPooledDataSource("myc3p0");

三.DRUID(德鲁伊)连接池

DRUID是阿里巴巴开发的目前最好的数据库连接池。 com.alibaba.druid.pool.DruidDataSourceFactory 类创建连接池的方法:

1.创建配置文件:mydruid.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
minIdle=3  # 最小连接池数量

2.获取连接池对象

Properties prop = new Properties();
InputStream is = DruidDemo.class.getClassLoader().
    getResourceAsStream("mydruid.properties");
prop.load(is);
//druid工厂根据配置文件创建druid连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

四.DRUID工具类封装

1.配置文件(参上)

2.关键代码

private static DataSource dataSource;
 static{
     try {
         // 解析druid的配置文件
         Properties prop = new Properties();
         InputStream is = JDBCUtil.class.getClassLoader().
             getResourceAsStream("druid.properties");
         prop.load(is);
         // druid工厂使用配置文件创建druid连接池对象
         dataSource = DruidDataSourceFactory.createDataSource(prop);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }
 //获取druid连接池
 public static DataSource getDataSource(){
     return dataSource;
 }
 //获取druid连接池中的连接
 public static Connection getConnection() throws SQLException {
     return dataSource.getConnection();
 }
 //释放资源(归还连接)
 public static void close(ResultSet rs, Statement st,Connection conn) {
     if(rs!=null){
         try {
             rs.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
     if(st!=null){
         try {
             st.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
     if(conn!=null){
         try {
             conn.close();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
 }
 public static void close(Statement st,Connection conn) {
     close(null,st,conn);
    }

Tips:

// 将properties文件放到src下时
JdbcUtils.class.getResourceAsStream("/jdbc.properties")
//两种方式的参数不一样
JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties")

 

 

关注微信公众号,随时随地学习

JDBC和数据库连接池