JDBC 的连接池


JDBC 的连接池

1. 连接池

a. 概述

  • 连接池其实就是一个容器(集合),存放数据库连接的容器。
  • 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
  • 原理可见:JDBC 连接池原理
    在这里插入图片描述

b. 优点

  • 节约资源,减轻服务器压力;
  • 提高连接复用性,用户访问高效。

c. 常见连接池

  1. DBCP:Apache 提供的数据库连接池技术。
  2. C3P0:数据库连接池技术,目前使用它的开源项目有 Hibernate、Spring 等。
  3. HikariCP:日本开发的连接池技术,性能之王,目前使用它的开源项目有 SpringBoot 等。
  4. Druid([ˈdruːɪd],也称德鲁伊):阿里巴巴提供的数据库连接池技术,是目前最好的数据库连接池。600+ 项目中使用,支持 SQL 日志监控。

d. 实现 DataSource

  • Java 为数据库连接池提供了公共的接口 DataSource ,各个连接池厂商去实现这套接口,提供 Jar 包。
    在这里插入图片描述
  • DataSource 功能:
    • 获取连接:
      Connection getConnection()
    • 归还连接:
      connection.close()
      • 如果连接对象是通过连接池获取的,那么执行 connection.close() 方法时,是归还到连接池,而不是销毁对象。
      • 底层通过动态代理技术对 close() 方法进行了增强。

2. Druid 连接池

a. 快速入门

i. 导入 Druid 相关 Jar 包

在这里插入图片描述

ii. 测试代码
package com.regino.util;

import com.alibaba.druid.pool.DruidDataSource;

import java.sql.Connection;

public class DruidDemo {

    public static void main(String[] args) throws Exception {
        // 1.创建Druid连接池对象
        DruidDataSource dataSource = new DruidDataSource();
        // 2.与MySQL建立连接(初始化一些连接个数),设置数据库基本四项
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/regino");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        // 3.从连接池中获取连接
        Connection connection = dataSource.getConnection();
        // 4.处理业务
        System.out.println(connection);
        // 5.归还连接
        connection.close();// 注意:此方法执行完毕,不是销毁对象,而是归还到连接池容器中
    }
}
iii. API 介绍
  • initialSize:初始化时建立物理链接的个数。初始化发生在显示调用 init 方法,或者第一次 getConnection 时。例如,容器创建完后,先初始化 10 个对象。
  • maxActive:最大连接池数量。例如,白天设为 100 个。
  • minIdle:最小连接池数量。例如,凌晨设为 20 个。
  • maxWait:获取链接时最大等待时间,单位毫秒。即等待上一个用户归还链接。

b. 配置文件版本

i. 定义配置文件 druid.properties
# 数据库基本四项
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/regino
username=root
password=root

# 初始化个数
initialSize=5

# 最大连接数
maxActive=10

# 等待时间,单位毫秒
maxWait=3000
ii. 测试代码
package com.regino.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

public class DruidDemo {

    public static void main(String[] args) throws Exception {
        // 通过类加载器读取src目录下配置文件,获取io流
        InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        // 创建Properties对象
        Properties properties = new Properties();
        properties.load(is);
        // Druid连接池工厂对象,初始化连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        // 获取连接
        // 测试最大连接数
        for (int i = 1; i <= 11; i++) {

            Connection connection = dataSource.getConnection();
            System.out.println(connection);
            if (i == 10) {
                connection.close();
            }
        }

        // 归还连接
        // connection.close();
    }
}

在这里插入图片描述

c. 连接池工具类 JdbcUtils

  • 每次操作数据库都需要创建连接池,获取连接,关闭资源,都是重复的代码。可以将创建连接池和获取连接池的代码放到一个工具类中。
  1. 初始化连接池对象(Druid),一个项目只有一个 static{}
  2. 提供获取连接池对象静态方法
  3. 提供连接对象的静态方法
  4. 提供释放资源的静态方法(Connection 是归还)
package com.regino.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {

    private static DataSource dataSource = null;

    // 1.初始化连接池对象(Druid),一个项目只有一个 static{}
    static {
        try {
            // 通过类加载器读取src目录下配置文件,获取io流
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            // 创建Properties对象
            Properties properties = new Properties();
            properties.load(is);
            // Druid连接池工厂对象,初始化连接池
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 2.提供获取连接池对象静态方法
    public static DataSource getDataSource() {
        return dataSource;
    }

    // 3.提供连接对象的静态方法
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 4.提供释放资源的静态方法(Connection是归还)
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    // 重载关闭方法
    public static void close(Statement statement, Connection connection) {
        close(null, statement, connection);
    }
}

3. 综合案例:用户登录

a. 主要需求

  • 使用三层架构 + JDBC 连接池技术(面向接口编程),实现用户登录案例。

b. 需求分析

在这里插入图片描述
在这里插入图片描述

c. 环境搭建

d. 编写 User 实体类

在这里插入图片描述

  • 一个 Java 实体(class 类) 对应一张表;
  • 一个 Java 对象对应一条记录。
package com.regino.domain;

public class User {
    private Integer id;
    private String username;
    private String password;

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

e. 代码实现

在这里插入图片描述

i. UserDao 接口
package com.regino.dao;

import com.regino.domain.User;

public interface UserDao {

    // 我来定义规范(根据用户名和密码查询User对象)
    public User login(String username, String password);
}
ii. UserDaoImpl 实现类
package com.regino.dao;

import com.regino.domain.User;
import com.regino.util.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserDaoImpl implements UserDao {

    @Override
    public User login(String username, String password) {

        Connection connection =null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet =null;
        try {
            // 1.获取连接【从连接池】
            connection = JdbcUtils.getConnection();
            // 2.编写sql
            String sql = "select * from user where username = ? and password = ?";
            // 3.获取sql预编译执行对象
            preparedStatement = connection.prepareStatement(sql);
            // 4.设置实际参数
            preparedStatement.setString(1, username);
            preparedStatement.setString(2, password);
            // 5.执行sql并返回结果
            resultSet = preparedStatement.executeQuery();
            // 6.处理结果
            User user = null;
            if (resultSet.next()) {
                // 获取 id 用户名、密码
                int id = resultSet.getInt("id");
                username = resultSet.getString("username");
                password = resultSet.getString("password");
                user = new User();
                user.setId(id);
                user.setUsername(username);
                user.setPassword(password);
            }
            return user;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7.释放资源
            JdbcUtils.close(resultSet, preparedStatement, connection);
        }
        return null;
    }
}
iii. UserService 接口
package com.regino.service;

import com.regino.domain.User;

public interface UserService {

    // 我来定义规范(根据用户名和密码查询User对象)
    public User login(String username, String password);
}
iv. UserServiceImpl 实现类
package com.regino.service;

import com.regino.dao.UserDao;
import com.regino.dao.UserDaoImpl;
import com.regino.domain.User;

public class UserServiceImpl implements UserService {

    @Override
    public User login(String username, String password) {
        UserDao userDao = new UserDaoImpl();
        return userDao.login(username, password);
    }
}
v. LoginServlet
package com.regino.web;

import com.regino.domain.User;
import com.regino.service.UserService;
import com.regino.service.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 1.接收请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 2.调用service
        UserService userService = new UserServiceImpl();
        User user = userService.login(username, password);
        // 3.判断
        if (user == null) {
            // 登录失败,友情提示
            request.setAttribute("error", "用户名或密码错误");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        } else {
            // 登录成功
            request.getSession().setAttribute("user", user);
            response.sendRedirect(request.getContextPath() + "/list.jsp");
        }
    }

}
vi. list.jsp

在这里插入图片描述

f. 测试

在这里插入图片描述


原文链接:https://qwert.blog.csdn.net/article/details/106002538

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值