[SQL] 数据库连接池, JDBC Template

36 篇文章 0 订阅
5 篇文章 0 订阅
本文详细介绍了数据库连接池的概念,以C3P0和Druid为例阐述其使用步骤,并展示了如何通过Druid工具类简化数据库连接操作。此外,文章还探讨了Spring的JdbcTemplate,解释了其简化JDBC开发的功能,提供了DML和DQL语句的实战示例,展示了JdbcTemplate的高效和便捷。
摘要由CSDN通过智能技术生成

第一章 数据库连接池

1.1 概述

引入案例: 我们开了一家餐馆,每当我们要给客人服务的时候(操作sql),我们就招聘一名服务员(getConnection),但是每当我们服务完毕了,我们却总是会解雇这个服务员(关闭资源),下次再有客人来的时候,我们再重新雇一名服务员,如此反复,简直离谱。

而我们餐馆正常逻辑就是 提前故几个服务员来一直服务

因此,我们需要一个容器,来提前保存连接对象,而这个东西就叫做数据库线程池

数据库连接池: 其实就是一个容器(集合),存放数据库连接的容器

  • 当系统初始化好之后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库的时候,从容器中获取连接对象;用户访问完之后,就将连接对象归还

优点

  1. 节约资源
  2. 用户访问高效(如果自己getConnection的话就要对底层获取资源,比较没有效率)

基本实现

  1. 使用标准接口javax.sql.DataSource(接口的实现类由数据库的厂商提供),对于DriverManager设备的替代方案,这个接口是获取连接的首选方法

    • 方法:

      //获取连接
      Connection getConnection​() 尝试建立与此 DataSource对象所代表的数据源的连接。  
          
      Connection getConnection​(String username, String password) 尝试建立与此 DataSource对象所代表 
          
      //归还连接:如果连接对象是从连接池中获取,那么调用Connection.close()方法,就不会再关闭连接,而是归还连接
      connecion.close();
      
  2. 有下面几种常用的数据库连接池技术

    1. C3P0: 比较老
    2. Druid(德鲁伊): 比较新的数据库连接池实现技术,由阿里巴巴提供的,非常高效,号称全世界最好的数据库连接池技术之一

1.2 C3P0技术

使用步骤:

  1. 导入jar包: c3p0-0.9.5.5-sources.jar 和 mchange-commons-java-0.2.19-sources.jar (注意,数据库的jar包也记得要导)
  2. 定义配置文件
    • 名称:c3p0.peoperties 或者 c3p0-config.xml
    • 路径: src源目录文件下
  3. 创建核心对象: 数据库连接池对象: new ComboPooledDataSource()
  4. 获取连接: getConnection()

1.3 Druid技术

使用步骤

  1. 导入jar包
  2. 定义配置文件:
    • 可以叫做任意名称,可以放在任意目录下,我们要手动读取这个配置文件
  3. 获取数据库连接池对象: 通过工厂类 DruidDataSourceFactory
  4. 获取连接: getConnection()

配置文件

url = jdbc:mysql:///cjy?serverTimezone=GMT%2B8
username = root
password = root
initialSize = 5
maxActive = 10
maxWait = 3000

小试牛刀

import com.alibaba.druid.pool.DruidDataSourceFactory;
import demo12.util.JDBCUtils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class DataSource {
    public static void main(String[] args) throws Exception {

        Properties pro = new Properties();

        ClassLoader cll = DataSource.class.getClassLoader();

        InputStream rs = cll.getResourceAsStream("druid.properties");

        pro.load(rs);

        //创建连接对象,这里参数要一个Properties
        javax.sql.DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);

        Connection conn = dataSource.getConnection();

        Statement stmt = conn.createStatement();

        String sql = "select * from account";

        // 执行sql
        ResultSet res = stmt.executeQuery(sql);

        //7 处理结果
        while (res.next()){
            System.out.println(res.getInt(1) + " \t" + res.getString(2) + "\t" +  res.getDouble(3));
        }

        //8 释放资源
        JDBCUtils.close(stmt,conn);

    }
}
//处理结果
422, 2021 11:39:13 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1 	zhangsan	2000.0
2 	lisi	6000.0

1.4 Druid工具类

通过上面的小试牛刀,我们发现这个过程还是有点麻烦,所以我们打算通过自己写一个改良版的工具类来简化这个过程.

步骤

  1. 定义一个工具类
  2. 开头要写一个静态代码块加载配置文件,同时初始化连接池对象
  3. 里面包含的方法就是获取连接对象,释放资源和获取连接池对象的方法

我写的工具类

package demo12.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

/**
 * JDBC工具类
 */

public class JDBCDruidUtils {

    private static final Properties pro;
    private static DataSource dataSource;


    //配置文件的读取,只需要一次就可以了,用静态代码块
    static {
        pro = new Properties();

        ClassLoader cl = JDBCDruidUtils.class.getClassLoader();

        InputStream is = cl.getResourceAsStream("druid.properties");

        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //初始化连接池对象
        try {
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //获取连接对象
    public static Connection getConnection() throws Exception {

        return dataSource.getConnection();

    }

    //关闭资源
    public static void close(Statement stmt, Connection conn) {
        judge(stmt, conn);


    }

    public static void judge(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    //获取连接池的方法
    public static DataSource getDataSource(){
        return dataSource;
    }

}

代码测试

package demo13;

import demo12.util.JDBCDruidUtils;
import demo12.util.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;


public class DataSource {
    public static void main(String[] args) throws Exception {

        Connection conn = JDBCDruidUtils.getConnection();

        Statement stmt = conn.createStatement();

        String sql = "select * from account";

        // 执行sql
        ResultSet res = stmt.executeQuery(sql);

        //7 处理结果
        while (res.next()){
            System.out.println(res.getInt(1) + " \t" + res.getString(2) + "\t" +  res.getDouble(3));
        }

        //8 释放资源
        JDBCUtils.close(stmt,conn);

    }
}
//运行结果
422, 2021 12:38:17 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1 	zhangsan	2000.0
2 	lisi	6000.0

我们会发现步骤简化了很多

第二章 JDBC Spring

2.1 简述

Spring框架对JDBC的简单封装. 提供了一个JDBCTemplate对象简化了JDBC的开发

步骤

  1. 导入jar包

  2. 创建JDBCTemplate对象.这个对象依赖于数据源DataSource

    • JdbcTemplate temp = new JdbcTemplate(datesource)
  3. 调用JdbcTemplate的方法来万册灰姑娘CRUD操作

    • update();执行DML语句.
          
      queryForMap(): 查询结果将结果封装为Map集合(将列名作为key,将值作为values,封装为一个map集合)这个方法只能存取一个记录
          
      queryForList():查询结果并将结果封装为list集合 (里面存取多个map)
          
      query():查询结果,并将结果封装为JavaBean对象  (一般用于将数据封装到我们自己创建的对象里面,然后再返回一个List<我们创建的对象>)
          
      queryForObject():查询结果,并将结果封装为Object对象 (一般用于聚合函数)
      

2.2 快速入门

import demo12.util.JDBCDruidUtils;
import org.springframework.jdbc.core.JdbcTemplate;

public class JDBCTemplate {
    public static void main(String[] args) {
        //创建jdbctemplate对象
        JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());

        //他使用的是PreparedStatement对象
        String sql = "update account set balance = 5000 where id = ?";
        int update = temp.update(sql, 2);
        System.out.println(update);
        //不需要释放资源,他会自动释放掉
    }
    //运行结果 1
//我们会发现用了Template + 我们自己写的工具类,语句既高效又简单,同时也不会发生注入问题等,简直无敌朋友们

2.3 DML语句练习

需求

对于下面这个表

在这里插入图片描述

  1. 我们修改一号数据的分数为100

    • public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "update stu set score = 100.0 where id = ?";
              int update = temp.update(sql, 1);
              System.out.println(update);
              //不需要释放资源,他会自动释放掉
          }
      }
      //运行结果 2
      //查看表格,我们会发现内容被正确修改
      
  2. 添加一条记录(随便什么内容都行)

    • import demo12.util.JDBCDruidUtils;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "insert into stu (id,name,age,score) values(1,'老铁双击666',66,66)";
              int update = temp.update(sql);
              System.out.println(update);
              //不需要释放资源,他会自动释放掉
          }
      }
      //运行结果 1  结果在数据表已经成功被创建出来
      
  3. 删除刚才添加的记录

    • package demo13;
      
      import demo12.util.JDBCDruidUtils;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "delete  from stu  where id = ? and name = ?";
              int update = temp.update(sql,1,"老铁双击666");
              System.out.println(update);
              //不需要释放资源,他会自动释放掉
          }
      }
      //运行结果 1  数据已经成功被删除
      

2.4 DQL语句练习

承接上面的练习

  1. 查询id为2的记录,将其封装为Map集合 (注意,这个方法,我们只能返回一个结果)

    • package demo13;
      
      import demo12.util.JDBCDruidUtils;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      import java.util.Map;
      
      public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "select * from stu where id =?";
              Map<String, Object> res = temp.queryForMap(sql, 2);
              System.out.println(res);
      
              //不需要释放资源,他会自动释放掉
      
          }
      }
      //运行结果 {id=2, name=儿子, age=11, score=88.0, birthday=2020-11-11, insert_time=2021-04-16 16:38:39.0, sex=男, address=null}
      
      
  2. 查询所有的记录,将其封装为list (返回两条以上的记录的时候,我们就要用到list集合来存储多个map结果)

    • package demo13;
      
      import demo12.util.JDBCDruidUtils;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      import java.util.List;
      import java.util.Map;
      
      public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "select * from stu";
              List<Map<String, Object>> res = temp.queryForList(sql);
              System.out.println(res);
      
              //不需要释放资源,他会自动释放掉
      
          }
      }
      //运行结果 
      422, 2021 5:11:24 下午 com.alibaba.druid.pool.DruidDataSource info
      信息: {dataSource-1} inited
      [{id=2, name=儿子, age=11, score=88.0, birthday=2020-11-11, insert_time=2021-04-16 16:38:39.0, sex=, address=null}, {id=1, name=爸爸, age=20, score=100.0, birthday=2000-11-19, insert_time=2021-04-17 19:21:23.0, sex=, address=杭州}, {id=3, name=爷爷, age=88, score=66.0, birthday=1920-11-11, insert_time=2021-04-17 19:21:29.0, sex=, address=深圳}, {id=4, name=孙子, age=1, score=0.0, birthday=2020-11-11, insert_time=2021-04-17 19:21:32.0, sex=, address=香港}, {id=1, name=爸爸, age=20, score=100.0, birthday=2000-11-19, insert_time=2021-04-17 19:21:23.0, sex=, address=杭州}, {id=5, name=你爹, age=20, score=66.0, birthday=1998-06-11, insert_time=2021-04-17 19:21:44.0, sex=, address=南京}, {id=6, name=妈妈, age=20, score=89.0, birthday=1965-06-11, insert_time=2021-04-17 19:21:58.0, sex=, address=北京}, {id=7, name=奶奶, age=88, score=99.0, birthday=1945-06-11, insert_time=2021-04-22 16:49:54.0, sex=, address=广州}, {id=8, name=ouMygod, age=28, score=100.0, birthday=2021-04-30, insert_time=2021-04-22 16:39:59.0, sex=, address=湖南}]
      
  3. 查询所有记录,将其封装为stu对象的list集合

    ​ 懒得创建stu对象了,就不演示了哈哈哈哈哈哈哈哈哈哈

    ​ 这里我直接截图了(例子和我的不太一样,这里主要使用query方法来实现这个,其他方法实现不了)

    在这里插入图片描述

    这里RowMapper的作用就是使用将查询得到的Result对象通过我们自己的重写方法,将数据都存放到我们自己的对象里面,然后返回这个对象

    ​ 所以说query()方法还是返回一个list集合,里面存放的就是我们创建的对象

    同时,我们注意到,刚才那个方法太麻烦了,我们总是要获取值,然后又set进我们的属性里面,十分的麻烦,所以,其实java提供了一个实现类,我么通过这个实现类可以直接完成这个复杂的过程(前提是类中的成员变量和表格的成员变量完全一致,同时里面要有getter和setter方法)

在这里插入图片描述

代码就变成了这么一小段,但是结果是一样的,原因就是我们使用了BeanProertiesRowMapper类,他是RowMapper类的子类

  1. 查询表的总记录数(我们使用QueryForObject()方法)

    1. import demo12.util.JDBCDruidUtils;
      import org.springframework.jdbc.core.JdbcTemplate;
      
      public class JDBCTemplate {
          public static void main(String[] args) {
              //创建jdbctemplate对象
              JdbcTemplate temp = new JdbcTemplate(JDBCDruidUtils.getDataSource());
      
              //他使用的是PreparedStatement对象
              String sql = "select count(id) from stu";
              Long res = temp.queryForObject(sql, Long.class);//这里传进去一个字节码文件,可以决定返回值类型
              System.out.println(res);
      
              //不需要释放资源,他会自动释放掉
      
          }
      }
      //运行结果  9
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值