Druid连接池学习笔记

1. 下载Druid连接池

1.1 下载源码

https://github.com/alibaba/druid
点击Download ZIP下载源码,如果遇到墙住的情况,可以挂个加速器。
在这里插入图片描述

1.2 下载jar包

https://repo1.maven.org/maven2/com/alibaba/druid/
在这里插入图片描述
在这里插入图片描述

2. 引用jar包,添加为库文件

拷贝到lib文件夹后,点击右键->添加为库文件
在这里插入图片描述

3. 使用Druid

3.1 使用硬编码方式

    public void DruidHard() throws SQLException {

        DruidDataSource druidDataSource = new DruidDataSource();

        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://192.168.101.130:3306/atguigu");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");

        Connection connection = druidDataSource.getConnection();

        // JDBC中的标准操作步骤
        String sel_sql = "SELECT * FROM t_bank";
        PreparedStatement preparedStatement = connection.prepareStatement(sel_sql);

        ResultSet resultSet = preparedStatement.executeQuery();
        List<Map> list = new ArrayList<Map>();

        ResultSetMetaData metaData = preparedStatement.getMetaData();

        int columnCount = metaData.getColumnCount();


        while (resultSet.next()) {
            Map<String,Object> map = new HashMap<String,Object>();
            for (int i = 1; i < columnCount; i++) {
                map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
            }
            list.add(map);
        }

        System.out.println("DruidHard" + list);
        preparedStatement.close();
        connection.close();
    }

3.2 使用配置文件方式

druid.properties文件内容:

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://192.168.101.130:3306/atguigu
username=root
password=root
defaultAutoCommit=false
defaultTransactionIsolation=REPEATABLE_READ
maxActive=10
initialSize=3
    public void DruidSoft() throws Exception {

        Properties properties = new Properties();

        InputStream resourceAsStream = DruidUserPart.class.getClassLoader().getResourceAsStream("druid.properties");

        properties.load(resourceAsStream);

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        Connection connection = dataSource.getConnection();

        String sel_sql = "SELECT * FROM t_bank;";
        PreparedStatement preparedStatement = connection.prepareStatement(sel_sql);

        ResultSet resultSet = preparedStatement.executeQuery();

        List<Map> list = new ArrayList<Map>();
        ResultSetMetaData metaData = preparedStatement.getMetaData();
        int columnCount = metaData.getColumnCount();
        while (resultSet.next()) {
            Map<String,Object> map = new HashMap<String,Object>();
            for (int i = 1; i < columnCount; i++) {
                map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
            }
            list.add(map);
        }

        System.out.println("DruidSoft" + list);
        resultSet.close();
        connection.close();

    }

测试方法:

    @Test
    public void test() throws Exception {
        DruidHard();
        DruidSoft();
    }

结果显式:
在这里插入图片描述

3.3 Druid常用配置

配置缺省说明
name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this)
url连接数据库的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。在mysql下建议关闭。
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,是组合关系,并非替换关系

3.4 连接池工具类及使用案例

结构思想
将注册服务、建立连接、回收资源等标准操作封装成静态方法,供服务层调用
第一版本

package com.untifa.api.utils;

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.util.Properties;

/**
 * @Title: JdbcUtil
 * @Package: com.untifa.api.utils
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/25 - 19:52
 */
public class JdbcUtilV1 {
    private static DataSource dataSource = null;

    static {
        Properties properties = new Properties();

        InputStream resourceAsStream = JdbcUtilV1.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getconnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void freeconnection(Connection connection) throws SQLException {
        connection.close();
    }
}

**思考:**
https://blog.csdn.net/FuTian0715/article/details/129699894
文章4.10中提到的转账例子,如何让服务层与Dao层等同一个线程的不同方法获取到相同的连接?

这就需要使用到ThreadLocal了,ThreadLocal用于保存线程的共享变量,原因是在Java中,每一个线程对象中都有一个ThreadLocalMap<ThreadLocal, Object>,其key就是一个ThreadLocal,而Object即为该线程的共享变量。而这个map是通过ThreadLocal的set和get方法操作的。对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。 1、ThreadLocal对象.get: 获取ThreadLocal中当前线程共享变量的值。 2、ThreadLocal对象.set: 设置ThreadLocal中当前线程共享变量的值。 3、ThreadLocal对象.remove: 移除ThreadLocal中当前线程共享变量的值。

第二版本

package com.untifa.api.utils;

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.util.Properties;

/**
 * @Title: JdbcUtil
 * @Package: com.untifa.api.utils
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/25 - 19:52
 */
public class JdbcUtilV2 {
    private static DataSource dataSource = null;
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    static {
        Properties properties = new Properties();

        InputStream resourceAsStream = JdbcUtilV2.class.getClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getconnection() throws SQLException {
        Connection connection = tl.get();
        if (connection == null) {
            connection = dataSource.getConnection();
            tl.set(connection);
        }
        return connection;
    }

    public static void free() throws SQLException {
        Connection connection = tl.get();
        if (connection != null) {
            tl.remove();
        }
        connection.setAutoCommit(true);
        connection.close();
    }
}

案例:
转账服务类

package com.untifa.api.transactionnew;

import com.untifa.api.utils.JdbcUtilV2;
import org.junit.Test;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @Title: BankService
 * @Package: com.untifa.api.transaction
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/23 - 23:32
 */
public class BankService {
    public void transfer(String addAcount, String subAccount, BigDecimal money) throws ClassNotFoundException, SQLException {

        Connection connection = JdbcUtilV2.getconnection();

        boolean flag = false; // 转账成功标志

        try {
            connection.setAutoCommit(false);
            BankDao bankDao = new BankDao();
            bankDao.addmoney(addAcount, money);
            bankDao.submoney(subAccount, money);
            flag = true;
            connection.commit();
        } catch (SQLException e) {
            flag = false;
            connection.rollback();
            System.out.println(":#####" + e.getMessage());
            e.printStackTrace();
            throw e;
        } finally {
            JdbcUtilV2.free();
            if (flag) {
                System.out.println("转账成功");
            } else {
                System.out.println("转账失败");
            }
        }

    }

    @Test
    public void testTransfer() throws SQLException, ClassNotFoundException {
        String addAcount = "ergouzi";
        String subAccount = "lvdandan";
        BigDecimal money = new BigDecimal("500");
        transfer(addAcount, subAccount, money);
    }
}

Dao类

package com.untifa.api.transactionnew;

import com.untifa.api.utils.JdbcUtilV2;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @Title: BankDao
 * @Package: com.untifa.api.statement
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/23 - 23:27
 */
public class BankDao {

    public void addmoney(String account, BigDecimal money) throws SQLException {

        Connection connection = JdbcUtilV2.getconnection();
        String upd_sql = "update t_bank t set t.money = t.money + ? where t.account = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(upd_sql);

        preparedStatement.setObject(1, money);
        preparedStatement.setObject(2, account);
        int i = preparedStatement.executeUpdate();
        if (i > 0) {
            System.out.println("加钱成功");
        }

        preparedStatement.close();

    }

    public void submoney(String account, BigDecimal money) throws SQLException {

        Connection connection = JdbcUtilV2.getconnection();
        String upd_sql = "update t_bank t set t.money = t.money - ? where t.account = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(upd_sql);

        preparedStatement.setObject(1, money);
        preparedStatement.setObject(2, account);
        int i = preparedStatement.executeUpdate();
        if (i > 0) {
            System.out.println("减钱成功");
        }

        preparedStatement.close();

    }

}

3.5 Dao方法封装案例

BaseDao.java

package com.untifa.api.utils;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Title: BaseDao
 * @Package: com.untifa.api.utils
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/25 - 21:23
 */
public abstract class BaseDao {

    /**
     * 非DQL语句
     * @param sql
     * @param params
     * @return
     * @throws SQLException
     */
    public int Update(String sql, Object... params) throws SQLException {

        Connection connection = JdbcUtilV2.getconnection();

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            System.out.println(params[i]);
            preparedStatement.setObject(i + 1, params[i]);
        }
        int rows = preparedStatement.executeUpdate();

        preparedStatement.close();

        if (connection.getAutoCommit()) {
            JdbcUtilV2.free();
        }

        return rows;
    }

    /**
     * DQL语句
     * 涉及到泛型、反射等技术的使用
     * @param clazz
     * @param sql
     * @param params
     * @return
     * @param <T>
     * @throws Exception
     */

    public <T> List<T> Query(Class<T> clazz, String sql, Object... params) throws Exception {

        Connection connection = JdbcUtilV2.getconnection();

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            System.out.println(params[i]);
            preparedStatement.setObject(i + 1, params[i]);
        }

        ArrayList<T> list = new ArrayList<T>();
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = preparedStatement.getMetaData();
        int columnCount = metaData.getColumnCount();

        while (resultSet.next()) {

            T t = clazz.newInstance();
            for (int i = 1; i <= columnCount; i++) {
                Field field = clazz.getDeclaredField(metaData.getColumnLabel(i));

                field.setAccessible(true);
                System.out.println("111\t" + field.toString());
                System.out.println("222\t" +resultSet.getObject(i));
                field.set(t,resultSet.getObject(i));
            }

            list.add(t);
        }
        resultSet.close();
        preparedStatement.close();

        if (connection.getAutoCommit()) {
            JdbcUtilV2.free();
        }

        return list;
    }
}

JavaBean对应的类t_bank.java

package com.untifa.api.utils;

import java.math.BigDecimal;

/**
 * @Title: t_user
 * @Package: com.untifa.api.utils
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/25 - 22:58
 */
public class t_bank {
    private int id;
    private String account;
    private BigDecimal money;

    public t_bank() {
    }

    public t_bank(int id, String account, BigDecimal money) {
        this.id = id;
        this.account = account;
        this.money = money;
    }

    public int getId() {
        return id;
    }

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

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public BigDecimal getMoney() {
        return money;
    }

    public void setMoney(BigDecimal money) {
        this.money = money;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        t_bank t_bank = (t_bank) o;

        if (id != t_bank.id) return false;
        if (!account.equals(t_bank.account)) return false;
        return money.equals(t_bank.money);
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + account.hashCode();
        result = 31 * result + money.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "t_bank{" +
                "id=" + id +
                ", account='" + account + '\'' +
                ", money=" + money +
                '}';
    }

}

测试业务类JdbcCurdPart.java

package com.untifa.api.utils;

import org.junit.Test;

import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Title: JdbcCurdPart
 * @Package: com.untifa.api.utils
 * @Description:
 * @Author: untifa
 * @Date: 2023/3/25 - 20:13
 */
public class JdbcCurdPart extends BaseDao{

    @Test
    public void sel_test() throws Exception {
        Connection connection = JdbcUtilV2.getconnection();

        String sel_sql = "SELECT * FROM t_bank";

        List<t_bank> list = Query(t_bank.class, sel_sql);

        System.out.println("####" + list);

        connection.commit();

        JdbcUtilV1.freeconnection(connection);

    }

    @Test
    public void upd_test() throws SQLException {
        Connection connection = JdbcUtilV2.getconnection();

        String upd_sql = "UPDATE t_bank t SET t.money = ? ;";
        int update = Update(upd_sql, BigDecimal.valueOf(20000));
        System.out.println("影响行数:" + update);
        connection.commit();
    }
}

sel_test()测试结果
在这里插入图片描述
在这里插入图片描述

upd_test()测试结果
在这里插入图片描述
在这里插入图片描述

注意:
在测试查询的过程中报错,这是因为JavaBean中的money类型与数据库中money类型不匹配导致,转换时会报异常,将数据库中money的类型改为DECIMAL类型后,查询就不在报错了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Druid连接池是一种高效、可扩展的Java数据库连接池,官方文档详细地介绍了Druid连接池的功能、配置和使用方法。 首先,文档介绍了Druid连接池的特点。Druid连接池具有高度可配置性,可以通过配置文件或者代码来设置连接池的参数,以适应不同的场景和需求。它还支持监控统计功能,可以实时监控连接池的使用情况,并提供详细信息和统计报表。此外,Druid连接池还支持防止恶意攻击、SQL注入等安全措施,以保护数据库的安全。 接下来,文档介绍了Druid连接池的配置方法。我们可以通过在配置文件中设置各种参数来配置连接池,例如设置初始化连接数、最大连接数、最小空闲连接数等。我们还可以配置连接的生命周期和验证策略,以及SQL统计功能等。Druid连接池还支持使用代码来动态配置连接池,这样可以更灵活地调整连接池的参数。 然后,文档介绍了使用Druid连接池的方法。我们可以通过通过简单的几行代码来获取连接,如"DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);"。获取连接后,可以使用该连接来执行SQL操作,并在完成后释放连接。Druid连接池还支持连接的自动扩展和收缩功能,可以根据连接的需求动态地增加或释放连接。 最后,文档介绍了Druid连接池的监控统计功能。我们可以通过配置一些参数来开启监控功能,并可以通过配置URL来访问监控的信息。监控信息包括连接数量、连接状态、执行的SQL语句等详细信息,以便我们能够全面了解连接池的使用情况,及时发现和解决问题。 总而言之,Druid连接池官方文档详细介绍了Druid连接池的功能、配置和使用方法,帮助用户更好地了解和使用Druid连接池,提高系统的数据库访问效率和安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值