JavaWeb--数据库连接池,SpringJDBC

JavaWeb-- 数据库连接池,SpringJDBC

JavaWeb-- 数据库连接池

概述

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

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

  • 好处

    • 节约资源
    • 用户访问高效

实现

  • 标准接口:DataSoure,java sql 包下
Interface DataSource -- 一个连接到这个DataSource对象所代表的物理数据源的工厂
-- 基本实现 - 生成标准的Connection对象 
连接池实现 - 生成将自动参与连接池的Connection对象。 此实现与中间层连接池管理器配合使用。 
分布式事务实现 - 生成可用于分布式事务的Connection对象,并且几乎总是参与连接池。 此实现与中间层事务管理器一起工作,并且几乎总是使用连接池管理器。
  • 方法:

    • getConnection() -- 获取连接
      
    • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
      
  • 一般我们不去实现它,有数据库厂商来实现

    • C3P0:数据库连接池技术

    • Druid:数据库连接池实现技术,由阿里巴巴提供的


数据库连接池 C3P0-- 基本使用

步骤

  • 导入 jar 包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,
    • 不要忘记导入数据库驱动 jar 包
  • 定义配置文件:
    • 名称: c3p0.properties 或者 c3p0-config.xml
      * 路径:直接将文件放在 src 目录下即可。
  • 创建核心对象 数据库连接池对象 ComboPooledDataSource
    • 获取连接: getConnection
public class C3P0Demo01 {
    public static void main(String[] args) throws SQLException {
        // 创建数据库连接池
        DataSource ds = new ComboPooledDataSource();
        // 获取连接对象
        Connection conn = ds.getConnection();
        // 打印连接对象
        System.out.println(conn);
    }
}
  • 成功后会返回日志数据和连接对象地址

数据库连接池 C3P0-- 配置演习

配置文件

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
   <!--  连接参数 -->
    <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db4</property>
    <property name="user">root</property>
    <property name="password">123456</property>
<span class="hljs-comment">&lt;!-- 连接池参数 --&gt;</span>
<span class="hljs-comment">&lt;!-- 初始化申请的连接数量--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"initialPoolSize"</span>&gt;</span>5<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>
<span class="hljs-comment">&lt;!-- 最大的连接数量--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxPoolSize"</span>&gt;</span>10<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>
<span class="hljs-comment">&lt;!-- 超时时间3s报错--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"checkoutTimeout"</span>&gt;</span>3000<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>

</default-config>

<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db4</property>
<property name="user">root</property>
<property name="password">123456</property>

<span class="hljs-comment">&lt;!-- 连接池参数 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"initialPoolSize"</span>&gt;</span>5<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"maxPoolSize"</span>&gt;</span>8<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"checkoutTimeout"</span>&gt;</span>2000<span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>

</named-config>
</c3p0-config>

演示代码

public class C3P0Demo02 {
    public static void main(String[] args) throws SQLException {
        // 获取 datasoure, 什么都没有传的话使用配置文件的默认设置 default-config
//        DataSource ds = new ComboPooledDataSource();
        // 使用指定名称的配置
        DataSource ds = new ComboPooledDataSource("otherc3p0");
        // 获取连接
        for (int i = 1; i <= 7; i++) {
            Connection conn = ds.getConnection();
            System.out.println(i + ":" + conn);
        }
}

}


数据库连接池 Druid-- 基本使用

  • 步骤:
    • 步骤:
      1. 导入 jar 包 druid-1.0.9.jar
      2. 定义配置文件:
      * 是 properties 形式的
      * 可以叫任意名称,可以放在任意目录下
      3. 加载配置文件。Properties
      4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
      5. 获取连接:getConnection

配置文件

  • 由于出现 -- 严重: testWhileIdle is true, validationQuery not set 的错误,在配置文件添加

  • driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/db4
    username=root
    password=123456
    # 初始化连接数
    initialSize=5
    # 最大连接数
    maxActive=10
    maxWait=3000
    

    -- 添加
    filters=stat
    timeBetweenEvictionRunsMillis=60000
    minEvictableIdleTimeMillis=300000
    validationQuery=SELECT 1
    testWhileIdle=true
    testOnBorrow=false
    testOnReturn=false
    poolPreparedStatements=false
    maxPoolPreparedStatementPerConnectionSize=200

演示代码

//druid 演示
public class DruidDemo01 {
    public static void main(String[] args) throws Exception {
        // 导入 jar 包
        // 定义配置文件
        // 加载配置文件
        Properties pro = new Properties();
        InputStream is = DruidDemo01.class.getClassLoader().getResourceAsStream("druid.properties");
        pro.load(is);
        // 获取连接池
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        // 获取连接
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">1</span>; i &lt;=<span class="hljs-number">10</span> ; i++) {
        <span class="hljs-type">Connection</span> <span class="hljs-variable">conn</span> <span class="hljs-operator">=</span> ds.getConnection();
        System.out.println(i+<span class="hljs-string">":"</span>+conn);
    }
}

}

数据库连接池 Druid-- 工具类

定义工具类

  • 定义一个类 JDBCUtils
    2. 提供静态代码块加载配置文件,初始化连接池对象
    3. 提供方法
    1. 获取连接方法:通过数据库连接池获取连接
    2. 释放资源
    3. 获取连接池的方法

  • Druid 工具类

    /**
     * Druid 连接池的工具类
     */
    public class DruidUtils {
        // 定义成员变量 DataSoure
        private static DataSource ds;
    
    <span class="hljs-comment">//加载配置文件</span>
    <span class="hljs-keyword">static</span>{
        <span class="hljs-type">Properties</span> <span class="hljs-variable">pro</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Properties</span>();
        <span class="hljs-type">InputStream</span> <span class="hljs-variable">is</span> <span class="hljs-operator">=</span> DruidUtils.class.getClassLoader().getResourceAsStream(<span class="hljs-string">"druid.properties"</span>);
        <span class="hljs-keyword">try</span> {
            pro.load(is);
            ds = DruidDataSourceFactory.createDataSource(pro);
        } <span class="hljs-keyword">catch</span> (IOException e) {
            e.printStackTrace();
        } <span class="hljs-keyword">catch</span> (Exception e) {
            e.printStackTrace();
        }<span class="hljs-keyword">finally</span> {
            <span class="hljs-keyword">try</span> {
                is.close();
            } <span class="hljs-keyword">catch</span> (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    <span class="hljs-comment">//获取连接方法</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Connection <span class="hljs-title function_">getConnection</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException {
        <span class="hljs-keyword">return</span> ds.getConnection();
    }
    
    
    <span class="hljs-comment">//释放资源2个方法</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">close</span><span class="hljs-params">(Statement ste,Connection conn)</span>{
    

    // if (ste!=null){
    // try {
    // ste.close();
    // } catch (SQLException e) {
    // e.printStackTrace();
    // }
    // }
    //
    // if (conn!=null){
    // try {
    // conn.close();
    // } catch (SQLException e) {
    // e.printStackTrace();
    // }
    // }
    // 简化书写
    close(null,ste,conn);

    }
    
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">close</span><span class="hljs-params">(ResultSet rs,Statement ste, Connection conn)</span>{
        <span class="hljs-keyword">if</span> (rs!=<span class="hljs-literal">null</span>){
            <span class="hljs-keyword">try</span> {
                rs.close();
            } <span class="hljs-keyword">catch</span> (SQLException e) {
                e.printStackTrace();
            }
        }
    
        <span class="hljs-keyword">if</span> (ste!=<span class="hljs-literal">null</span>){
            <span class="hljs-keyword">try</span> {
                ste.close();
            } <span class="hljs-keyword">catch</span> (SQLException e) {
                e.printStackTrace();
            }
        }
    
        <span class="hljs-keyword">if</span> (conn!=<span class="hljs-literal">null</span>){
            <span class="hljs-keyword">try</span> {
                conn.close();
            } <span class="hljs-keyword">catch</span> (SQLException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    <span class="hljs-comment">//获取返回连接池对象方法</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DataSource <span class="hljs-title function_">getDataSoure</span><span class="hljs-params">()</span>{
        <span class="hljs-type">DataSource</span> <span class="hljs-variable">dss</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;
        <span class="hljs-keyword">if</span> (ds!=<span class="hljs-literal">null</span>){
            dss = ds;
        }
        <span class="hljs-keyword">return</span> dss;
    }
    

    }

工具类测试

/**
 * 使用 druid 工具类完成更改 sql 数据库数据
 */
public class DruidDemo02 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pste = null;
        // 获取连接对象
        try {
            conn = DruidUtils.getConnection();
            // 定义 sql
            String sql = "UPDATE account SET balance = ? where name = ?";
            // 获取 prepareStatement,防止 sql 注入
            pste = conn.prepareStatement(sql);
            // 给?赋值
            pste.setDouble(1,2000);
            pste.setString(2,"zhangsan");
            // 执行 sql 语句
            pste.executeUpdate();
    } <span class="hljs-keyword">catch</span> (SQLException e) {
        e.printStackTrace();
    }<span class="hljs-keyword">finally</span> {
        <span class="hljs-comment">//归还连接对象</span>
        DruidUtils.close(pste,conn);
    }
}

}


SpringJDBC--JDBCTemplate

介绍

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

步骤

  • 导入 jar 包

    • 创建 JdbcTemplate 对象。依赖于数据源 DataSource

      • JdbcTemplate template = new JdbcTemplate(ds);
    • 调用 JdbcTemplate 的方法来完成 CRUD 的操作

      • update(): 执行 DML 语句。增、删、改语句

        • queryForMap(): 查询结果将结果集封装为 map 集合,将列名作为 key,将值作为 value 将这条记录封装为一个 map 集合
          • 注意:这个方法查询的结果集长度只能是 1
        • queryForList(): 查询结果将结果集封装为 list 集合
          • 注意:将每一条记录封装为一个 Map 集合,再将 Map 集合装载到 List 集合中
        • query(): 查询结果,将结果封装为 JavaBean 对象
          • query 的参数:RowMapper
            • 一般我们使用 BeanPropertyRowMapper 实现类。可以完成数据到 JavaBean 的自动封装
            • new BeanPropertyRowMapper< 类型 >(类型.class)
        • queryForObject:查询结果,将结果封装为对象
          • 一般用于聚合函数的查询
//JdbcTemplate 快速入门
public class JdbcTempLateDemo01 {
    public static void main(String[] args) {
        // 导入 jar 包
        // 创建 JDBCTemplate 对象
        JdbcTemplate jt = new JdbcTemplate(DruidUtils.getDataSoure());
        // 调用方法
        String sql = "UPDATE account SET balance = 5000 where name = ?";
        int count = jt.update(sql, "zhangsan");
        System.out.println("修改成功,已影响"+count+"行数据");
    }
}

SpringJDBC--JDBCTemplate 练习

需求

private static JdbcTemplate jt = new JdbcTemplate(DruidUtils.getDataSoure());
  • 修改 1 号数据的 salary 为 10000

    /**
     * 修改 1 号数据的 salary 为 10000
     */
    @Test
    public void test1(){
        // 调用方法
        String sql = "UPDATE emp SET salary = ? where id = ?";
        int count = jt.update(sql, 10000,1001);
        System.out.println("修改成功,已影响"+count+"行数据");
    }
    
  • 添加一条记录

    /**
     * 添加一条记录 1015 郭靖
     */
    @Test
    public void test2(){
        String sql = "insert into emp (id,ename) value (?,?)";
        int count = jt.update(sql, 1015, "郭靖");
        System.out.println("修改成功,已影响"+count+"行数据");
    }
    
  • 删除刚才添加的记录

    /**
     * 删除刚才的数据
     */
    @Test
    public void test3(){
        String sql = "delete from emp where id = ?";
        int count = jt.update(sql, 1015);
        System.out.println("修改成功,已影响"+count+"行数据");
    }
    
  • 查询 id 为 1 的记录,将其封装为 Map 集合

    /**
     * 查询 id 为 1 的记录,将其封装为 Map 集合
     */
    @Test
    public void test4(){
        String sql = "select * from emp where id = ?";
        Map<String, Object> som = jt.queryForMap(sql, 1001);
        System.out.println(som);
    }
    
  • 查询所有记录,将其封装为 List

    /**
     * 查询所有记录,将其封装为 List
     */
    @Test
    public void test5(){
        String sql = "select * from emp";
        List<Map<String, Object>> maps = jt.queryForList(sql);
        for (Map<String, Object> map : maps) {
            System.out.println(map);
        }
    }
    
  • 查询所有记录,将其封装为 Emp 对象的 List 集合

    /**
     * 查询所有记录,将其封装为 Emp 对象的 List 集合
     */
    @Test
    public void test6(){
        String sql = "select * from emp";// 使用封装好的方法传入类的字节码对象
        List<Emp> query = jt.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
        for (Emp emp : query) {
            System.out.println(emp);
        }
    }
    
  • 查询总记录数

    /**
     * 查询总记录数
     */
    @Test
    public void test7(){
        String sql = "select count(id) from emp";//count 返回的是 long 类型数据
        Long total = jt.queryForObject(sql, long.class);
        System.out.println(total);
    }