JavaWeb01-JDBC、Druid连接池

目录

一、JDBC

1.概述

2.本质

3.好处

4.使用步骤

5.JDBC_API

(1)DriverManager(驱动管理类)

(2)Connection(数据库连接对象)

(3)Statement

(4)ResultSet(结果集对象)

(5)PreparedStatement

6.使用

(1)快速上手

(2)ResultSet使用

(3)SQL注入模拟及解决

(4)perparedStatement使用

7.关于测试类无法使用Scanner的问题解决

二、数据库连接池

1.概述

2.数据库连接池的实现

(1)标准接口:DataSource

(1)常见的数据库连接池

3.Druid数据库连接池的使用

三、综合练习

1.创建表:

2.添加数据:表中数据增

3.表中数据的删、改、查

(1)查(需要啥写啥)+存

(2)改

(3)删除


一、JDBC

1.概述

  • 全称 Java DataBase Connectivity

  • 就是使用Java语言操作关系型数据库的一套API

2.本质

  • 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口

  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包

  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动iar包中的实现类

3.好处

  • 各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发

  • 可随时替换底层数据库,访问数据库的Java代码基本不变

4.使用步骤

  • 导入对应的驱动jar包

  • 注册驱动,(mysql驱动包在v5及之后的版本,该步骤可省略)

  • 获取连接

  • 定义SQL语句

  • 获取执行SQL对象

  • 执行SQL

  • 返回结果

  • 释放资源

5.JDBC_API

(1)DriverManager(驱动管理类)

主要作用:

  • 注册驱动

  • 获取数据库连接

(2)Connection(数据库连接对象)

主要作用:

  • 获取执行SQL的对象

  • 管理事务

    • JDBC事务管理:Connection接口中定义了3个对应的方法

    • 开启事务: setAutoCommit(boolean autoCommit): true为自动提交事务; false为手动提交事务,即为开启事务

    • 提交事务commit()

    • 回滚事务: rollback()

主要方法:

  • 执行SQL对象(普通)

方法名
Statement createStatement(sql);
  • 执行SQL对象(预编译SQL):防止SQL注入

方法名
PreparedStatement prepareStatement(sql);
  • 执行存储过程的对象

方法名
CallableStatement prepareCall (sql)
(3)Statement

主要作用

  • 执行SQL语句

方法名说明
int executeUpdate(sql);执行DML、DDL语句 返回值为DML语句影响的行数 DDL语句执行后,执行成功也可能返回0
ResultSet executeQuery(sql);执行DQL语句 返回值为ResultSet结果集对象

(4)ResultSet(结果集对象)

主要作用:

  • 获取查询结果

主要方法

方法名说明
boolean next()将光标从当前位置向前移动一行 判断当前行是否为有效行(有数据)
XXX【数据类型】 getXxx(参数)获取数据 参数: int:列的编号,从1开始 String:列的名称 更多参数看jdk帮助文档

使用:

while(rs.next()){//获取数据rs.getXxx(参数);
}

(5)PreparedStatement

主要作用:

  • 预编译SQL并执行

  • 防止SQL注入

SQL注入:

SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

好处:

  • 预编译SQL,性能更高

  • 防止SQL注入:将敏感字符进行转义

注意:

  • 默认只是防止SQL注入,并没有预编译SQL提高性能

  • PreparedStatement的预编译功能默认是关闭的,需要在url后架上useServerPrepStmts=true,才会开启

6.使用

(1)快速上手
import java.sql.*;
​
public class Demo01 {public static void main(String[] args) throws Exception {String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false";String username = "root";String password = "root";//1.注册驱动,mysql5版本及之后的版本该步骤可以省略registrationDriver();//2.获取数据库连接Connection connection = getConnection(url, username, password);//3.定义SQL语句String sql = "sqls";//4.获取执行SQL的对象Statement statement = connection.prepareStatement(sql);/*开启事务*/connection.setAutoCommit(false);
​try {//5.执行sql,根据方法会返回不同类型的值,详细可查看JDK帮助文档了解boolean execute = statement.execute(sql);//验证SQL语句是否执行成功System.out.println(execute);} catch (SQLException throwables) {throwables.printStackTrace();/*出现异常就回滚事务*/connection.rollback();}
​/*提交事务*/connection.commit();
​//6.释放资源statement.close();connection.close();
​}
​/*** 获取数据库连接* @param url:数据库连接,*           格式:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...*           如果连接的是本机服务器,且端口号为默认,可简写为:jdbc:mysql///数据库名称?参数键值对*           由于没有禁用安全连接方式,会输出警告提示,将参数配置设置为 useSSL = false 即可* @param username:数据库用户名* @param password:数据库密码* @return 连接对象* @throws SQLException: SQLException异常*/private static Connection getConnection(String url, String username, String password) throws SQLException {return DriverManager.getConnection(url, username, password);}
​private static void registrationDriver() throws ClassNotFoundException {Class.forName("com.mysql.jdbc.Driver");}
}

(2)ResultSet使用

查询user表中数据,并根据其数据创建User对象,再将所有的User对象存储到arraysList集合中

实体类User:

public class User {private Long id;private String userName;private String password;private String gmtCreate;private String gmtModified;
​public User() {}
​public User(Long id, String userName, String password, String gmtCreate, String gmtModified) {this.id = id;this.userName = userName;this.password = password;this.gmtCreate = gmtCreate;this.gmtModified = gmtModified;}
​public Long getId() {return id;}
​public void setId(Long 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;}
​public String getGmtCreate() {return gmtCreate;}
​public void setGmtCreate(String gmtCreate) {this.gmtCreate = gmtCreate;}
​public String getGmtModified() {return gmtModified;}
​public void setGmtModified(String gmtModified) {this.gmtModified = gmtModified;}
​@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +", password='" + password + '\'' +", gmtCreate='" + gmtCreate + '\'' +", gmtModified='" + gmtModified + '\'' +'}';}
}

测试

public class TestDemo {String url = "jdbc:mysql:///test?useSSL=false";String userName = "root";String password = "root";@Testpublic void Demo01 () throws Exception {Connection connection = DriverManager.getConnection(url, userName, password);
​String sql = "select * from users";
​Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql);
​ArrayList<User> arrayList = new ArrayList<>();while (resultSet.next()){
​User user = new User(resultSet.getLong("id"),resultSet.getString("user_name"),resultSet.getString("password"),resultSet.getString("gmt_create"),resultSet.getString("gmt_modified"));arrayList.add(user);}resultSet.close();statement.close();connection.close();
​arrayList.forEach(user -> System.out.println(user));}
}

(3)SQL注入模拟及解决

模拟登录:sql注入

@Testpublic void sout() throws Exception {Scanner scanner = new Scanner(System.in);System.out.println("请输入用户名");String username = scanner.nextLine();System.out.println("请输入密码");String password = "' or 'a' = 'a";
​Connection connection = DriverManager.getConnection(TestDemo.this.url,TestDemo.this.userName,TestDemo.this.password);Statement statement = connection.createStatement();
​String sql = "select * from users where user_name = '"+username+"' and password = '"+password+"'";
​ResultSet resultSet = statement.executeQuery(sql);
​if (resultSet.next()){System.out.println("登录成功");}else {System.out.println("登录失败");}
​resultSet.close();statement.close();connection.close();}
}

SQL注入本质:由于用户输入导致SQL语句发生变化,如where username = ? and ... +(or 1=1)【后面追加一个恒成立等式,就会导致where条件恒成立】

解决方式1:更多的逻辑判断

@Test
public void demo02() throws Exception {Scanner scanner = new Scanner(System.in);System.out.println("请输入用户名");String username = scanner.nextLine();System.out.println("请输入密码");String password = scanner.nextLine();
​Connection connection = DriverManager.getConnection(TestDemo.this.url,TestDemo.this.userName,TestDemo.this.password);Statement statement = connection.createStatement();
​String sql = "select * from users where user_name = '"+username+"' and password = '"+password+"'";
​ResultSet resultSet = statement.executeQuery(sql);
​while (true){boolean next = resultSet.next();if (next){if (username.equals(resultSet.getString("user_name"))){if (password.equals(resultSet.getString("password"))){System.out.println("登录成功");}else {System.out.println("密码错误");}break;}}else {System.out.println("没有此用户");break;}
​}
​resultSet.close();statement.close();connection.close();
}

解决方式2:预编译SQL

(4)perparedStatement使用
  • 获取PerparedStatement对象

    • 使用Connection的prepareStatement(sql)

    • SQL语句中的参数值,使用?占位符替代

  • 设置参数

    • setXxx【数据类型】(int ?的位置编号,参数值)

    • ?位置从1开始

  • 执行SQL

    • 主要方法

    • 方法名返回值类型说明
      execute()boolean可执行所有sql语句,返回值为是否执行成功
      executeUpdate()int执行数据操纵语言DML或者没有返回值类型的SQL,如DDL
      executeQuery()ResultSet执行DQL,返回ResultSet对象

@Testpublic void sout() throws Exception {Scanner scanner = new Scanner(System.in);System.out.println("请输入用户名");String username = scanner.nextLine();System.out.println("请输入密码");String password = scanner.nextLine();
​Connection connection = DriverManager.getConnection(TestDemo.this.url,TestDemo.this.userName,TestDemo.this.password);
​
​String sql = "select * from users where user_name=? and password=?";
​PreparedStatement preparedStatement = connection.prepareStatement(sql);//设置?的值preparedStatement.setString(1,username);preparedStatement.setString(2,password);
​ResultSet resultSet = preparedStatement.executeQuery();
​if (resultSet.next()){System.out.println("登录成功");}else {System.out.println("登录失败");}
​resultSet.close();preparedStatement.close();connection.close();}
}

7.关于测试类无法使用Scanner的问题解决

  • 点击Help

  • 选择Edit Custom VM Options...

-Deditable.java.test.console=true
  • 之后重启idea即可

二、数据库连接池

1.概述

  • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;

  • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏

好处:

  • 资源重用

  • 提升系统响应速度

  • 避免数据库连接遗漏

2.数据库连接池的实现

(1)标准接口:DataSource

官方(SUN)提供的数据库连接池标准接口,由第三方组织实现此接口。

功能:

  • 获取连接:getConnection()

(1)常见的数据库连接池
  • DBCP

  • C3P0

  • Druid(德鲁伊)

    • Druid连接池是阿里巴巴开源的数据库连接池项目

    • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

3.Druid数据库连接池的使用

  • 导入jar包:druid

  • 定义配置文件

  • 加载配置文件

  • 获取数据库连接池对象

  • 获取连接

配置文件:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test?useSSL=false&useServerPrepStmts=true
username=root
password=root
#初始化连接数量
initialSize=5
#最大连接数量
maxActive=10
#最大等待时间(ms)
maxWait=3000

java代码:

@Test
public void connectionPool() throws Exception {//加载配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\druid.properties"));
​//创建连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//获取数据库连接final Connection connection = dataSource.getConnection();
​System.out.println(connection);
​
}

三、综合练习

主要目标:

  • 建表:

  • 添加数据:

  • 表中数据的增、删、改、查

  • 表中数据的存储

  • 使用数据库连接池

1.创建表:

这玩意后期不会纯手敲的,除非业务需要

-- auto-generated definition
create table product
(id           bigint auto_increment comment '商品ID'primary key,name         varchar(20)                        not null comment '商品名称',price        decimal(10, 2)                     not null comment '商品价格',category     int      default 1                 not null comment '商品分类',gmt_modified datetime default CURRENT_TIMESTAMP not null comment '最后修改日期',gmt_create   datetime default CURRENT_TIMESTAMP not null comment '创建日期',constraint product_name_uindexunique (name)
)comment '商品表';

2.添加数据:表中数据增

id设置主键和自增约束可不写

public class Practice {public static void main(String[] args) throws Exception {
​//加载配置文件Properties properties = new Properties();properties.load(new FileInputStream("JDBC\\src\\practice\\druidDemo.properties"));
​//获取连接池连接对象final Connection connection = DruidDataSourceFactory.createDataSource(properties).getConnection();
​String sql = "insert into product (name,price,category)" +"values(?,?,?)";Random random = new Random();
​
​final PreparedStatement preparedStatement = connection.prepareStatement(sql);for (int i = 1; i <= 40; i++) {int integerPart = random.nextInt(10001);int decimalPart = random.nextInt(100);preparedStatement.setString(1,"商品"+i);if (decimalPart<10){preparedStatement.setString(2,integerPart+".0"+decimalPart);}else{preparedStatement.setString(2,integerPart+"."+decimalPart);}preparedStatement.setInt(3,1);try {preparedStatement.execute();System.out.println("第"+i+"条数据添加成功");} catch (SQLException e) {System.out.println("第"+i+"条数据添加失败");e.printStackTrace();}
​}
​preparedStatement.close();connection.close();
​}
}

3.表中数据的删、改、查

实体类:后面会有优化,也不会手敲的~

public class Product {private Long id;private String name;private BigDecimal bigDecimal;private Integer category;private Timestamp gmtCreate;private Timestamp gmtModified;
​public Product() {}
​public Product(Long id, String name, BigDecimal bigDecimal, Integer category, Timestamp gmtCreate, Timestamp gmtModified) {this.id = id;this.name = name;this.bigDecimal = bigDecimal;this.category = category;this.gmtCreate = gmtCreate;this.gmtModified = gmtModified;}
​public Long getId() {return id;}
​public void setId(Long id) {this.id = id;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public BigDecimal getBigDecimal() {return bigDecimal;}
​public void setBigDecimal(BigDecimal bigDecimal) {this.bigDecimal = bigDecimal;}
​public Integer getCategory() {return category;}
​public void setCategory(Integer category) {this.category = category;}
​public Timestamp getGmtCreate() {return gmtCreate;}
​public void setGmtCreate(Timestamp gmtCreate) {this.gmtCreate = gmtCreate;}
​public Timestamp getGmtModified() {return gmtModified;}
​public void setGmtModified(Timestamp gmtModified) {this.gmtModified = gmtModified;}
​@Overridepublic String toString() {return "Product{" +"id=" + id +", name='" + name + '\'' +", bigDecimal=" + bigDecimal +", category=" + category +", gmtCreate=" + gmtCreate +", gmtModified=" + gmtModified +'}';}
}
(1)查(需要啥写啥)+存
        //查询所有String sql = "select * from product";final PreparedStatement preparedStatement = connection.prepareStatement(sql);ResultSet resultSet = preparedStatement.executeQuery();ArrayList<Product> productArrayList = new ArrayList<>();while (resultSet.next()){Product product = new Product(resultSet.getLong(1),resultSet.getString(2),resultSet.getBigDecimal(3),resultSet.getInt(4),resultSet.getTimestamp(5),resultSet.getTimestamp(6));productArrayList.add(product);}
​productArrayList.forEach(p -> System.out.println(p));
​resultSet.close();preparedStatement.close();connection.close();
        //根据条件查String sql = "select * from product where id = ?";final PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setLong(1,10126);ResultSet resultSet = preparedStatement.executeQuery();ArrayList<Product> productArrayList = new ArrayList<>();while (resultSet.next()){Product product = new Product(resultSet.getLong(1),resultSet.getString(2),resultSet.getBigDecimal(3),resultSet.getInt(4),resultSet.getTimestamp(5),resultSet.getTimestamp(6));productArrayList.add(product);}
​productArrayList.forEach(p -> System.out.println(p));
​resultSet.close();preparedStatement.close();connection.close();
(2)改
public class Practice {public static void main(String[] args) throws Exception {
​//加载配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\practice\\druidDemo.properties"));
​//获取连接池连接对象final Connection connection = DruidDataSourceFactory.createDataSource(properties).getConnection();//输入sql语句String sql = sqls();
​
​
​
​final PreparedStatement preparedStatement = connection.prepareStatement(sql);//设置参数parameterSetting(preparedStatement);
​//执行sql//execute(),可执行所有SQL语句//executeUpdate(),执行DML(返回受影响的行数)或者无返回值的SQL语句,如DDL//executeQuery(),DQL,返回ResultSet对象preparedStatement.executeUpdate();
​//查询专用//query(preparedStatement);
​preparedStatement.close();connection.close();
​}
​private static void parameterSetting(PreparedStatement preparedStatement) throws SQLException {preparedStatement.setInt(1,3);preparedStatement.setLong(2,10126);}
​private static void query(PreparedStatement preparedStatement) throws SQLException {
​ResultSet resultSet = preparedStatement.executeQuery();
​ArrayList<Product> productArrayList = new ArrayList<>();while (resultSet.next()){Product product = new Product(resultSet.getLong(1),resultSet.getString(2),resultSet.getBigDecimal(3),resultSet.getInt(4),resultSet.getTimestamp(5),resultSet.getTimestamp(6));productArrayList.add(product);}
​productArrayList.forEach(p -> System.out.println(p));
​resultSet.close();}
​private static String sqls() {//查询所有
//        String sql = "select * from product";//根据条件查
//        String sql = "select * from product where id = ?";//根据条件改return "update product set category = ? where id = ?";}
}
(3)删除

改SQL,preparedStatement.set一下就行了

String sql = "delete from product where id = ?";

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452171.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫urllib详解

前言 学习爬虫&#xff0c;最初的操作便是模拟浏览器向服务器发出请求&#xff0c;那么我们需要从哪个地方做起呢&#xff1f;请求需要我们自己来构造吗&#xff1f;需要关心请求这个数据结构的实现吗&#xff1f;需要了解 HTTP、TCP、IP 层的网络传输通信吗&#xff1f;需要知…

【Python基础021】Python中的何如实现文件的读写

Python中文件的读写在程序运行过程中是一个非常重要的操作&#xff0c;我们通常会将一些大量的临时数据暂时存放到一个临时文件&#xff0c;这就需要用到文件的读取与写入功能。话不多说&#xff0c;我们直接上才艺。 1、文本文件和二进制文件 讲文件读写前&#xff0c;先说说…

Leetcode 热门百题斩(第三天)

介绍 针对leetcode的热门一百题&#xff0c;解决大多数实习生面试的基本算法题。通过我自己的思路和多种方法&#xff0c;供大家参考。 1.两数之和&#xff08;题号&#xff1a;1) 方法一 最先想到的就是两个for去遍历匹配。 class Solution {public int[] twoSum(int[]…

进程中线程使用率偏高问题排查

1. top命令查看CPU使用率高的进程 2. top -H -p 15931(进程PID) 查看进程下的线程 3. printf "%x\n" 17503(线程PID) 线程PID 10进制转16进制 0x445f 4. jstack -l 15931(JVM进程PID) 导出java进程栈信息&#xff0c;里面包含线程nid0x445f和所在的类&#xff0…

ansible的常用模块配置说明及批量部署服务

ansible的常用模块配置说明及批量部署服务 ansible的常用模块配置说明&#xff0c;在远程服务器批量配置清华大学的仓库文件&#xff0c;批量部署nginx&#xff0c;并启动服务。 ansible知识点&#xff1a; 一、Ansible特点&#xff1a; 1、部署简单&#xff0c;只需在主控端…

生物发酵展同期论坛|2024节能环保绿色低碳发展论坛

“十四五”规划中提出&#xff0c;提高工业、能源领城智能化与信息 化融合&#xff0c;明确“低碳经济”新的战略目标&#xff0c;热能产业是能源产 业和民生保障的重要组成部分&#xff0c;也是二氧化碳排放量大的行业 之一&#xff0c;产业高效、清洁、低碳、灵活、智能化水平…

Rust 第一个rust程序Hello Rust️

文章目录 前言一、vscode 安装rust相关插件二、Cargo New三、vscode调试rustLLDB 前言 Rust学习系列。今天就让我们掌握第一个rust程序。Hello Rust &#x1f980;️。 在上一篇文章我们在macOS成功安装了rust。 一、vscode 安装rust相关插件 以下是一些常用的 Rust 开发插件…

Docker基础与持续集成

docker 基础知识&#xff1a; docker与虚拟机 !左边为虚拟机&#xff0c;右边为docker环境 – Server :物理机服务器Host OS &#xff1a;构建的操作系统Hypervisor &#xff1a;一种虚拟机软件&#xff0c;装了之后才能虚拟化操作系统Guest OS &#xff1a;虚拟化的操作系统…

AI应用开发-git开源项目的一些问题及镜像解决办法

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

python爬虫之豆瓣首页图片爬取

网址&#xff1a;https://movie.douban.com/ import requests from lxml import etree import re url https://movie.douban.com headers {User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/5…

小埋的解密游戏的题解

题目描述 小埋最近在玩一个解密游戏&#xff0c;这个游戏的解密方法是这样的&#xff0c;这个游戏会给你提供 个数,让我们求出这 个数里面&#xff0c;有多少个连续的数的平均数大于某个给定的数 。这个数可能会很大&#xff0c;所以我们要输出这个数对 的取模结果。现在小…

【脑电信号处理与特征提取】P7-涂毅恒:运用机器学习技术和脑电进行大脑解码

运用机器学习技术和脑电进行大脑解码 科学研究中的大脑解码 比如2019年在Nature上一篇文章&#xff0c;来自UCSF的Chang院士的课题组&#xff0c;利用大脑活动解码语言&#xff0c;帮助一些患者恢复语言功能。 大脑解码的重要步骤 大脑解码最重要的两步就是信号采集和信号…