数据库 ------ 基础
-
-
- [1. JDBC](#1. JDBC)
- [2. SQL 注入](#2. SQL 注入)
- [3. 模拟登录功能](#3. 模拟登录功能)
-
-
- [3.1 数据库连接池](#3.1 数据库连接池)
- [3.2 创建数据库连接工具类](#3.2 创建数据库连接工具类)
- [3.3 登录模拟实现](#3.3 登录模拟实现)
-
-
1. JDBC
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| JDBC:(Java DataBase Connectivity)Java数据库连接,Java编程语言中用于执行与数据库交互的API;Java和数据库之间的纽带 数据库驱动:指连接(Java)程序与不同类型的数据库之间的软件组件 Driver接口:Driver接口由各大数据库厂商提供各自对应的Driver接口 Connection接口:用于与数据库建立连接的对象,与数据库进行通信,并执行各种数据库操作 Statement接口: JDBC 中用于执行静态 SQL 语句并返回结果的对象 ResultSet接口: JDBC 中用于表示 SQL 查询结果集的对象 JDBC的使用步骤:加载JDBC驱动程序 🡺 建立数据库连接Connection 🡺 创建执行SQL的语句Statement 🡺 处理执行结果ResultSet 🡺 释放资源 |
- ➤ JDBC使用步骤
java
package jdcb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* JDBC 查询操作
*/
public class Demo01_Bases {
public static void main(String[] args) throws Exception {
// 早期版本:Class.forName("com.mysql.jdbc.Driver");
// 1. 加载驱动程序(jdk6及以上的版本此处可省略,DriverManager集成了Driver的自动注册)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
String url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&CharacterEncoding=utf8";
String userName = "root";
String passWord = "123456";
Connection connection = DriverManager.getConnection(url, userName, passWord);
// 3. 创建Statement对象
Statement statement = connection.createStatement();
// 4. 执行SQL语句
ResultSet resultSet = statement.executeQuery("select * from student limit 4;");
// 5. 处理结果
while (resultSet.next()){
System.out.print(resultSet.getString("name") + "\t");
System.out.print(resultSet.getInt("age") + "\t");
System.out.print(resultSet.getString("gender") + "\t");
System.out.println(resultSet.getString("birth"));
}
// 6. 释放资源(先创建后关闭)
resultSet.close();
statement.close();
connection.close();
}
}
- ▶ url 解析
textString url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&CharacterEncoding=utf8"
jdbc:mysql://
:表示使用 JDBC 连接 MySQL 数据库
localhost:3306
:表示 MySQL 数据库所在的主机和端口号
school
:表示要连接的数据库名称
serverTimezone=Asia/Shanghai
:表示服务器时区为亚洲/上海,用于确保时间日期相关操作的正确性
CharacterEncoding=utf8
:表示字符编码为 UTF-8,用于确保传输中文等非 ASCII 字符时的正确性
- ➤ JDBC接口及使用方法
- ➤ 将查询结果存入字典
java
package jdcb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* JDBC 查询操作
*/
public class Demo01_Bases {
public static void main(String[] args) throws Exception {
// 早期版本:Class.forName("com.mysql.jdbc.Driver");
// 1. 加载驱动程序(jdk6及以上的版本此处可省略,DriverManager集成了Driver的自动注册)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
String url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&CharacterEncoding=utf8";
String userName = "root";
String passWord = "123456";
Connection connection = DriverManager.getConnection(url, userName, passWord);
// 3. 创建Statement对象
Statement statement = connection.createStatement();
// 4. 执行SQL语句
ResultSet resultSet = statement.executeQuery("select * from student limit 4;");
// 5. 处理结果
List<Map<String, Object>> list = new ArrayList<>();
while (resultSet.next()){
Map<String, Object> map = new HashMap<>();
map.put("name",resultSet.getString("name"));
map.put("age",resultSet.getInt("age"));
map.put("gender",resultSet.getString("gender"));
map.put("birth",resultSet.getString("birth"));
list.add(map);
}
list.forEach(System.out::println);
// 6. 释放资源(先创建后关闭)
resultSet.close();
statement.close();
connection.close();
}
}
2. SQL 注入
|--------------------------------------------------------------------------------------------------------------------------|
| SQL 注入: 一种常见的安全漏洞(攻击者通过恶意构造的输入,向应用程序的数据库发出未经授权的查询或执行操作) 危害:攻击者可以利用 SQL 注入漏洞来绕过应用程序的身份验证、获取敏感数据、修改数据,甚至执行任意的数据库命令 |
- ➤ SQL 注入
java
String username = request.getParameter("username");
String password = request.getParameter("password");
String query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
如在以上输入
' OR '1'='1
,将会导致原始的查询被修改为SELECT * FROM users WHERE username='' OR '1'='1' AND password='' OR '1'='1'
,这将返回所有用户的记录,从而绕过身份验证
- ➤ 使用预编译语句但不使用参数化查询
java
String username = request.getParameter("username");
String password = request.getParameter("password");
String query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";
PreparedStatement statement = connection.prepareStatement(query);
参数化查询(Prepared Statement)
通过使用预编译语句和绑定参数的方式,可以确保用户输入被视为数据值而不是 SQL 代码,这样可以防止攻击者注入恶意的 SQL 语句
- ➤ 参数化查询
java
package jdcb;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* JDBC 查询操作
*/
public class Demo01_Bases {
public static void main(String[] args) throws Exception {
// 早期版本:Class.forName("com.mysql.jdbc.Driver");
// 1. 加载驱动程序(jdk6及以上的版本此处可省略,DriverManager集成了Driver的自动注册)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
String url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&CharacterEncoding=utf8";
String userName = "root";
String passWord = "123456";
Connection connection = DriverManager.getConnection(url, userName, passWord);
// 3. sql预编译
String sql = "select name,age,gender,birth from student where gender=? limit 4;";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1,"男");
// 4. 执行SQL语句
ResultSet resultSet = ps.executeQuery();
// 5. 处理结果
List<Map<String, Object>> list = new ArrayList<>();
while (resultSet.next()){
Map<String, Object> map = new HashMap<>();
map.put("name",resultSet.getString("name"));
map.put("age",resultSet.getInt("age"));
map.put("gender",resultSet.getString("gender"));
map.put("birth",resultSet.getString("birth"));
list.add(map);
}
list.forEach(System.out::println);
// 6. 释放资源(先创建后关闭)
resultSet.close();
ps.close();
connection.close();
}
}
java
package jdcb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class Demo02_Update {
public static void main(String[] args) throws Exception{
// 1. 加载驱动程序(jdk6及以上的版本此处可省略,DriverManager集成了Driver的自动注册)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
String url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&CharacterEncoding=utf8";
String userName = "root";
String passWord = "123456";
Connection connection = DriverManager.getConnection(url, userName, passWord);
// 3. sql预编译
String sql = "insert into student(name,age,gender,job,birth) values (?,?,?,?,?)";
PreparedStatement ps = connection.prepareStatement(sql);
// 赋值
ps.setString(1,"何伟");
ps.setInt(2,22);
ps.setString(3,"男");
ps.setString(4,"学生");
ps.setString(5,"2001-01-05");
// 4. 执行失去了语句
int rows = ps.executeUpdate();
System.out.println(rows);
// 5. 释放资源(先创建后关闭)
ps.close();
connection.close();
}
}
3. 模拟登录功能
3.1 数据库连接池
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 数据库连接池:一种用于管理和维护数据库连接的技术 作用:负责创建、分配、回收和监控数据库连接 原理:通过预先创建一定数量的数据库连接并将其保存在连接池中,以便在需要时可以快速获取和释放连接 意义:以减少每次请求时创建和销毁连接的开销,提高数据库操作的性能和效率 常见数据库连接池:Apache Commons DBCP,HikariCP,Druid,Tomcat JDBC Pool |
传统JDBC
使用JDBC进行数据库的操作(增删改查)时,需要经过复杂的过程才能完成
建立TCP/IP连接(三次握手) 🢂 数据库连接认证 🢂 SQL语句执行并返回结果 🢂 数据库关闭 🢂 TCP/IP连接断开(四次挥手)
如果大量的用户同时对数据库进行相关业务的访问时,将会造成数据库在创建连接,断开连接等基础操作中浪费大量内存开销,导致服务器的资源利用不恰当,甚至会发生服务器内存溢出,造成应用的使用卡顿,发生宕机等故障
而连接池避免频繁地创建和销毁数据库连接,节省了时间和资源,并且可以减轻数据库服务器的负担,提高系统的性能和稳定性,从而满足更多用户的需求
3.2 创建数据库连接工具类
JDBC创建
javaString url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&characterEncoding=utf8"; String username = "root"; String password = "123456"; Connection connection = DriverManager.getConnection(url, username, password);
HikariCP连接池创建
在所需项目resource目录下创建hikari.properties文件
在hikari.properties文件添加连接属性
textjdbcUrl=jdbc:mysql://localhost:3306/数据库名?serverTimezone=Asia/Shanghai&characterEncoding=utf8 dataSource.user=root dataSource.password=123456
javaprivate static HikariDataSource dataSource; // 数据库连接池 static { // 加载配置文件 HikariConfig config = new HikariConfig("/hikari.properties"); // 创建数据源对象(通过此对象获取连接) dataSource = new HikariDataSource(config); } // 从HikariPool中获取连接 public static Connection getHikariConnection() throws SQLException { return dataSource.getConnection(); }
3.3 登录模拟实现
- 创建maven项目Login
- 在pom.xml文件中添加mysql数据库和HikariCP数据库连接池依赖
xml
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.2</version>
</dependency>
</dependencies>
- 创建hikari.properties文件
yaml
jdbcUrl=jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&characterEncoding=utf8
dataSource.user=root
dataSource.password=123456
- 在项目中创建包和类util.DBUtil
java
package util;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
// **************************************************由数据库创建连接**************************************************
public static Connection getConnection() throws SQLException {
String url = "jdbc:mysql://localhost:3306/school?serverTimezone=Asia/Shanghai&characterEncoding=utf8";
String username = "root";
String password = "123456";
return DriverManager.getConnection(url, username, password);
}
// **************************************************由连接池创建连接**************************************************
private static HikariDataSource dataSource;
// 数据库连接池
static {
// 加载配置文件
HikariConfig config = new HikariConfig("/hikari.properties");
// 创建数据源对象(通过此对象获取连接)
dataSource = new HikariDataSource(config);
}
// 从HikariPool中获取连接
public static Connection getHikariConnection() throws SQLException {
return dataSource.getConnection();
}
}
- 在数据库MySQL中创建表
sql
create database if not exists school charset = utf8;
use school;
-- 登录
create table if not exists login
(
id bigint primary key auto_increment comment '主键ID',
username varchar(20) not null comment '用户名',
password varchar(20) not null comment '密码'
) charset = utf8;
insert into login(username, password)
values ('lyc', '123456');
- 创建登录类
java
import util.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
public class Regin {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");
String userName = scanner.nextLine();
System.out.print("请输入密码:");
String passWord = scanner.nextLine();
try {
// 简单模拟直接使用JDBC连接
Connection connection = DBUtil.getConnection();
// Connection connection = DBUtil.getHikariConnection(); // 连接池创建连接
String sql = "select id from login where username=? and password=?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1,userName);
ps.setString(2,passWord);
ResultSet rs = ps.executeQuery();
if (rs.next()){
System.out.println("登录成功!");
}else {
System.out.println("用户名或密码错误!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}