mysql基本使用
什么是数据库?
数据库是按照数据结构来组织、存储和管理数据的仓库。
什么是数据库管理系统(DBMS)?
数据库管理系统(DBMS)是用于创建、管理和维护数据库的软件。
什么是SQL?
SQL(Structured Query Language)是一种用于管理和操作数据库的语言。
什么是MySQL?
MySQL是一种开源的关系型数据库管理系统。
关系型数据库和非关系型数据库的区别?
关系型数据库使用表格来存储数据,每个表格由行和列组成。非关系型数据库(如MongoDB)使用键值对来存储数据,每个键值对由一个键和一个值组成。
基本命令
连接MySQL
mysql -u root -p
查看数据库
show databases;
创建数据库
create database database_name;
使用数据库
use database_name;
查看数据库中的表
show tables;
查看表的结构
desc table_name;
操作数据库
操作数据库
-- 创建数据库
CREATE DATABASE [if not exists] database_name;
-- 删除数据库
DROP DATABASE [if exists] database_name;
-- 选择数据库
USE database_name;
-- 如果操作的表名或字段名为特殊字符,需要用反引号括起来
USE `database_name`;
-- 查看数据库
SHOW DATABASES;
-- 查看当前数据库
SELECT DATABASE();
-- 查看数据库的创建信息
SHOW CREATE DATABASE database_name;
数据库的列类型
数值类型
- TINYINT 十分小的数据 1字节
- SMALLINT 较小的数据 2字节
- MEDIUMINT 中等大小的数据 3字节
- INT 标准的整数 4字节
- BIGINT 较大的数据 8字节
- FLOAT 浮点数 4字节
- DOUBLE 浮点数 8字节
- DECIMAL 字符串类型的浮点数 用于金融计算
日期时间类型
- DATE 日期 ‘2022-01-01’ YYYY-MM-DD
- TIME 时间 ‘12:00:00’ HH:mm:ss
- DATETIME 日期时间 ‘2022-01-01 12:00:00’ YYYY-MM-DD HH:mm:ss
- TIMESTAMP 时间戳 表示从 1970-01-01 00:00:00 到现在的毫秒数
- YEAR 年份 ‘2022’
字符串类型
- CHAR 字符串固定大小 ‘abc’ 0~255
- VARCHAR 字符串可变大小 ‘abc’ 0~65535
- TINYINT 微型文本 ‘abc’ 2^8-1
- TEXT 文本串 ‘abc’ 2^16-1
- BLOB 二进制形式存储数据 2^16-1
数据库的字段属性
- NULL 字段值可以为空
- NOT NULL 字段值不能为空
- DEFAULT 默认值
- PRIMARY KEY 主键,唯一且非空
- UNIQUE 唯一值
- AUTO_INCREMENT 自动增长
- COMMENT 注释
- ZEROFILL 零填充
- UNSIGNED 无符号
创建数据库表
CREATE TABLE 表名(
`字段名` 字段类型 [列属性] [注释],
`字段名` 字段类型 [列属性] [注释],
···
`字段名` 字段类型 [列属性] [注释]
)[表类型][字符集][注释];
示例
CREATE TABLE `users`(
`id` INT NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` VARCHAR(255) NOT NULL COMMENT '用户名',
`password` VARCHAR(255) NOT NULL COMMENT '密码',
`age` INT NOT NULL COMMENT '年龄',
`email` VARCHAR(255) NOT NULL COMMENT '邮箱',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
相关的常用命令
show create table 表名; 查看创建表的语句
desc 表名; 查看表结构
show tables; 查看当前数据库中的所有表
show tables like ‘表名’; 查看当前数据库中符合要求的表
show databases; 查看所有数据库
show create database 数据库名; 查看创建数据库的语句
数据表的类型
- InnoDB:支持事务、外键、行级锁,适合高并发读写操作
- MyISAM:不支持事务和外键,适合读多写少的操作,支持全文索引
- MEMORY:存储在内存中,适合临时表和缓存表
- CSV:以CSV格式存储数据,适合数据导出和导入
- ARCHIVE:适合存储大量历史数据,只支持插入和查询操作
数据库的字符集
- utf8mb4:支持存储emoji表情符号,是utf8的超集
- utf8:支持存储大部分的汉字和英文,但不支持存储emoji表情符号
- gbk:支持存储简体中文,但不支持存储繁体中文和英文
- latin1:支持存储英文和部分西欧语言,但不支持存储中文和日文
修改表结构
- 添加列:ALTER TABLE 表名 ADD 列名 数据类型;
- 删除列:ALTER TABLE 表名 DROP 列名;
- 修改列名和数据类型:ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型;
- 修改表名:ALTER TABLE 旧表名 RENAME TO 新表名;
删除表
- 删除表:DROP TABLE 表名;
- 删除表并重新创建:TRUNCATE TABLE 表名;
MySql数据管理
外键
外键是用于建立和加强两个表数据之间的链接的一种关系。它是一种约束,用于保证数据的一致性和完整性。外键约束可以防止无效数据的插入,例如,如果表A中的某个值在表B中没有对应的值,那么插入操作将会失败。
在建表时添加外键约束的语法如下:
CREATE TABLE 表名 (
列名 数据类型,
...
CONSTRAINT 外键名 FOREIGN KEY (列名) REFERENCES 参考表名(参考列名)
);
使用修改表语法添加外键约束的语法如下:
ALTER TABLE 表名
ADD CONSTRAINT 外键名
FOREIGN KEY (列名) REFERENCES 参考表名(参考列名);
插入数据
INSERT INTO 表名 (列1, 列2, 列3, …)
VALUES (值1, 值2, 值3, …);
INSERT INTO 表名 (列1, 列2, 列3, …)
VALUES (值1, 值2, 值3, …),
(值4, 值5, 值6, …),
…;
INSERT INTO students (id, name, age, gender, class_id)
VALUES (1, '张三', 18, '男', 1),
(2, '李四', 19, '女', 2),
(3, '王五', 20, '男', 1),
(4, '赵六', 21, '女', 2);
更新数据
UPDATE 表名
SET 列1 = 值1, 列2 = 值2, …
WHERE 条件;
条件
- 等于:=
- 不等于:!= 或 <>
- 大于:>
- 小于:<
- 大于等于:>=
- 小于等于:<=
- 在某个范围内:BETWEEN 值1 AND 值2
- 不在某个范围内:NOT BETWEEN 值1 AND 值2
- 属于某个集合:IN (值1, 值2, …)
- 不属于某个集合:NOT IN (值1, 值2, …)
- 匹配字符串的开头:LIKE ‘值%’ (%表示任意数量字符, _表示任意一个字符)
UPDATE students
SET age = 22
WHERE name = '张三';
删除数据和清空表
删除数据
DELETE FROM 表名 WHERE 条件;
清空表
TRUNCATE TABLE 表名;
DELETE FROM students WHERE name = '张三';
TRUNCATE TABLE students;
Delete from TABLE 和 TRUNCATE TABLE 的区别
这两个语句都可以清空表,但是DELETE from table不会重设自增列,但是truncate table会重设自增列。
查询的全部语法
SELECT DISTINCT * | 列1, 列2, 列3, …
FROM 表名
[WHERE 条件]
[GROUP BY 列1, 列2, … [HAVING 条件]]
[HAVING 条件]
[ORDER BY 列1, 列2, … [ASC | DESC]]
[LIMIT [OFFSET,] 行数];
SELECT * FROM students;
SELECT id, name FROM students;
SELECT * FROM students WHERE age > 18;
SELECT * FROM students WHERE age > 18 AND gender = '男';
SELECT * FROM students WHERE age > 18 OR gender = '男';
SELECT * FROM students WHERE NOT gender = '男';
SELECT * FROM students WHERE name LIKE '李%';
SELECT * FROM students WHERE name LIKE '李_';
SELECT * FROM students WHERE name LIKE '_华';
SELECT * FROM students WHERE name LIKE '%华';
SELECT * FROM students WHERE age BETWEEN 18 AND 25;
SELECT * FROM students WHERE age NOT BETWEEN 18 AND 25;
SELECT * FROM students WHERE id IN (1, 3, 8);
SELECT * FROM students WHERE id NOT IN (2, 5, 7);
SELECT * FROM students ORDER BY age;
SELECT * FROM students ORDER BY age DESC;
SELECT * FROM students ORDER BY age ASC, name DESC;
SELECT * FROM students LIMIT 3;
SELECT * FROM students LIMIT 0, 3;
SELECT * FROM students LIMIT 3, 3;
SELECT * FROM students LIMIT 6, 3;
查询时使用别名
SELECT id AS 学号, name AS 姓名, age AS 年龄 FROM students;
查询时使用聚合函数
SELECT COUNT(*) FROM students;
SELECT COUNT(*) FROM students WHERE gender = '男';
SELECT AVG(age) FROM students;
SELECT SUM(age) FROM students;
SELECT MAX(age) FROM students; -- 查询年龄最大值
SELECT MIN(age) FROM students; -- 查询年龄最小值
查询时使用分组
SELECT gender, COUNT(*) FROM students GROUP BY gender;
SELECT gender, AVG(age) FROM students GROUP BY gender;
SELECT gender, COUNT(*) FROM students GROUP BY gender HAVING gender = '男';
查询时使用子查询
SELECT * FROM students WHERE age > (SELECT AVG(age) FROM students);
查询时使用连接查询
SELECT * FROM students, classes;
SELECT * FROM students, classes WHERE students.class_id = classes.id;
SELECT * FROM students AS s, classes AS c WHERE s.class_id = c.id; -- 使用别名
SELECT s.id, s.name, c.name FROM students AS s, classes AS c WHERE s.class_id = c.id;
内连接
SELECT * FROM students INNER JOIN classes ON students.class_id = classes.id;
左连接
SELECT * FROM students LEFT JOIN classes ON students.class_id = classes.id;
右连接
SELECT * FROM students RIGHT JOIN classes ON students.class_id = classes.id;
全连接
SELECT * FROM students LEFT JOIN classes ON students.class_id = classes.id
UNION
SELECT * FROM students RIGHT JOIN classes ON students.class_id = classes.id;
自连接
SELECT a.name, b.name FROM students AS a, students AS b WHERE a.addr = b.addr;
这几种连接的区别
- 内连接:只显示两个表中匹配的记录
- 左连接:显示左表中的所有记录,右表中没有匹配的记录时,显示NULL
- 右连接:显示右表中的所有记录,左表中没有匹配的记录时,显示NULL
- 全连接:显示两个表中的所有记录,没有匹配的记录时,显示NULL
查询时使用联合查询
SELECT * FROM students WHERE gender = '男'
UNION
SELECT * FROM students WHERE age < 20;
查询时使用正则表达式
SELECT * FROM students WHERE name REGEXP '^李';
SELECT * FROM students WHERE name REGEXP '亮$';
SELECT * FROM students WHERE name REGEXP '国|伟';
SELECT * FROM students WHERE name REGEXP '[uvw]';
查询时使用通配符
SELECT * FROM students WHERE name LIKE '李_';
SELECT * FROM students WHERE name LIKE '李%';
查询时使用排序
SELECT * FROM students ORDER BY age;
SELECT * FROM students ORDER BY age DESC;
SELECT * FROM students ORDER BY age, gender;
查询时使用分页
SELECT * FROM students LIMIT 0, 3;
SELECT * FROM students LIMIT 3, 3;
mysql中的常用函数
字符串函数
SELECT CONCAT('hello', 'world'); # 拼接字符串
、SELECT LENGTH('hello'); # 获取字符串长度
SELECT UPPER('hello'); # 转换为大写
SELECT LOWER('HELLO'); # 转换为小写
SELECT SUBSTRING('hello', 1, 3); # 截取字符串
SELECT REPLACE('hello', 'l', 'w'); # 替换字符串
数学函数
SELECT ABS(-1); # 绝对值
SELECT CEIL(3.14); # 向上取整
SELECT FLOOR(3.14); # 向下取整
SELECT ROUND(3.14); # 四舍五入
SELECT RAND(); # 生成随机数
SELECT POW(2, 3); # 幂运算
SELECT SQRT(4); # 平方根
SELECT TRUNCATE(3.1415926, 3); # 截断小数位数
日期函数
SELECT NOW(); # 获取当前日期和时间
SELECT CURDATE(); # 获取当前日期
SELECT CURTIME(); # 获取当前时间
SELECT DATE(NOW()); # 获取日期部分
SELECT TIME(NOW()); # 获取时间部分
SELECT YEAR(NOW()); # 获取年份
SELECT MONTH(NOW()); # 获取月份
SELECT DAY(NOW()); # 获取日期
SELECT HOUR(NOW()); # 获取小时
SELECT MINUTE(NOW()); # 获取分钟
SELECT SECOND(NOW()); # 获取秒数
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY); # 日期加法
SELECT DATEDIFF(NOW(), '2020-01-01'); # 日期差值
聚合函数
SELECT COUNT(*) FROM table_name; # 统计行数 ,忽略所有的NULL值
SELECT SUM(column_name) FROM table_name; # 求和
SELECT AVG(column_name) FROM table_name; # 平均值
SELECT MAX(column_name) FROM table_name; # 最大值
SELECT MIN(column_name) FROM table_name; # 最小值
事务
事务是指一组SQL语句的集合,它们要么全部执行成功,要么全部执行失败。事务的四个特性:原子性、一致性、隔离性、持久性(ACID)。
事务的ACID特性
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部完成,要么全部不完成,不可能只执行一部分。
- 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性(Durability):一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即使数据库发生故障也不应该对其有任何影响。
事务相关的一些问题
- 脏读(Dirty Read):一个事务读取了另一个事务尚未提交的数据。
- 不可重复读(Non-Repeatable Read):一个事务读取了另一事务已经提交的数据,但是在一个事务两次读取之间,另一个事务修改了数据。
- 幻读(Phantom Read):一个事务读取了另一事务已经提交的数据,但是在一个事务两次读取之间,另一个事务插入了新数据。
- 丢失更新(Lost Update):两个事务同时修改同一条记录,后提交的事务会覆盖先提交的事务的修改。
事务执行
SET AUTOCOMMIT = 0; # 关闭自动提交
SET AUTOCOMMIT = 1; # 开启自动提交
START TRANSACTION; # 开始事务
COMMIT; # 提交事务
ROLLBACK; # 回滚事务
索引
索引是数据库中用于提高查询效率的数据结构。索引可以加快数据检索的速度,但是会降低数据插入、更新和删除的速度,因为每次修改数据时,索引也需要更新。
索引类型
- 主键索引(Primary Key):主键索引是一种特殊的唯一索引,它用于唯一标识表中的每一行。主键索引不能包含NULL值。
- 唯一索引(Unique Index):唯一索引用于确保索引列中的值是唯一的。唯一索引可以包含NULL值。
- 普通索引(Normal Index):普通索引是MySQL中最常见的索引类型,它用于提高查询速度。
- 全文索引(Full-Text Index):全文索引用于提高全文搜索的速度。
- 组合索引(Composite Index):组合索引是多个列的索引,它可以提高多个列的查询速度。
索引创建
CREATE INDEX index_name ON table_name (column_name); # 创建普通索引
CREATE UNIQUE INDEX index_name ON table_name (column_name); # 创建唯一索引
CREATE INDEX index_name ON table_name (column1, column2); # 创建组合索引
分析查询语句
EXPLAIN SELECT * FROM table_name WHERE column_name = 'value'; # 分析查询语句
索引原则
- 最左前缀原则:组合索引中,查询条件必须从最左边的列开始,否则索引不会被使用。
- 覆盖索引:索引中包含了查询需要的所有列,那么查询时可以直接从索引中获取数据,而不需要查询表中的数据。
- 索引选择性:索引的选择性是指索引列中不同值的数量与总行数的比值。选择性越高,索引的效率越高。
- 索引维护:索引会占用额外的存储空间,并且每次插入、更新和删除数据时,索引也需要更新。因此,需要定期维护索引,例如重建索引。
数据库用户管理
创建用户
CREATE USER 'username'@'host' IDENTIFIED BY 'password'; # 创建用户
重命名
RENAME USER 'old_username'@'host' TO 'new_username'@'host'; # 重命名用户
授予权限
GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'host'; # 授予权限
刷新权限
FLUSH PRIVILEGES; # 刷新权限
撤销权限
REVOKE ALL PRIVILEGES ON database_name.* FROM 'username'@'host'; # 撤销权限
删除用户
DROP USER 'username'@'host'; # 删除用户
修改密码
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password'; # 修改密码
查看用户权限
SHOW GRANTS FOR 'username'@'host'; # 查看用户权限
数据库备份与恢复
备份
mysqldump -uusername -ppassword database_name > backup.sql # 备份数据库
恢复
# 在命令行中登录时,切换到准备恢复的数据库执行
source backup.sql # 恢复数据库
#在命令行中未登录时执行
mysql -u username -ppassword database_name < backup.sql # 恢复数据库
如何设计一个数据库
步骤
- 需求分析:确定需要存储的数据类型和关系,以及数据之间的关系。
- 概念设计:将需求分析的结果转化为概念模型,如ER图。
- 逻辑设计:将概念模型转化为逻辑模型,如关系模型。
- 物理设计:将逻辑模型转化为物理模型,如数据库表结构。
- 实施:根据物理模型创建数据库表,并插入数据。
- 测试:测试数据库的性能和稳定性,确保满足需求。
设计的三大范式
- 第一范式(1NF):要求表中的每个字段都是不可分割的基本数据项,即每个字段都是原子性的。
- 第二范式(2NF):在满足第一范式的基础上,要求表中的每个非主属性都完全依赖于主键,即每张表仅做一件事情。
- 第三范式(3NF):在满足第二范式的基础上,要求表中的每个非主属性都不依赖于其他非主属性,即每列数据需要和主键直接相关。
JDBC
数据库驱动
数据库驱动是连接Java应用程序和数据库之间的桥梁,它提供了一种标准的方法来访问和操作数据库。不同的数据库厂商会提供自己的数据库驱动,以便Java应用程序可以连接到他们提供的数据库。
使用JDBC(需导入mysql-connector-java-8.0.29.jar包)
下载地址:https://downloads.mysql.com/archives/c-j/
- 加载驱动:使用
Class.forName()
方法加载驱动类。 - 建立连接:使用
DriverManager.getConnection()
方法建立数据库连接。 - 创建Statement对象:使用
Connection.createStatement()
方法创建Statement对象。 - 执行SQL语句:使用Statement对象的
executeQuery()
、executeUpdate()
等方法执行SQL语句。 - 处理结果:根据SQL语句的类型,使用ResultSet对象处理查询结果或更新结果。
- 关闭连接:使用
Connection.close()
方法关闭数据库连接。
示例
import java.sql.*;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 添加数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 创建连接到数据库
String url = "jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url,user,password);
// 创建执行sql的对象
Statement statement = conn.createStatement();
// 使用执行sql的对象 来执行sql
String sql = "select * from studentpre;";
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println(id + " " + name + " " + age);
}
// 关闭连接
conn.close();
statement.close();
resultSet.close();
}
}
写一个使用JDBC的工具类
// 方式一
public class JDBCUtils {
private static String url;
private static String username;
private static String password;
private static String driver;
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("d:\\test\\jdbc.properties"));
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
Class.forName(driver);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
public static void close(ResultSet resultSet, Statement statement, Connection connection){
try {
if (resultSet != null){
resultSet.close();
}
if (statement != null){
statement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void close(Statement statement, Connection connection){
close(null,statement,connection);
}
}
// 方式二
import java.io.*;
import java.sql.*;
import java.util.*;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String user = null;
private static String password = null;
static {
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
try {
prop.load(inputStream);
driver = prop.getProperty("driver");
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
Class.forName(driver);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
// 释放资源
public static void release(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if(resultSet != null) {
resultSet.close();
}
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
}
}
使用PreparedStatement代替Statement进行查询,以防止SQL注入
public class JdbcTest {
public static void main(String[] args) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
String sql = "select * from studentpre where id = ?";
// 预编译SQL,防止SQL注入
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 6);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("name") +
resultSet.getInt("age") +
resultSet.getInt("id"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
使用事务
public class JdbcTest {
public static void main(String[] args) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
// 关闭自动提交,并开启事务
connection.setAutoCommit(false);
String sql = "insert into studentpre values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 6);
preparedStatement.setString(2, "张三");
preparedStatement.setInt(3, 18);
preparedStatement.executeUpdate();
int i = 1 / 0;
preparedStatement.setInt(1, 7);
preparedStatement.setString(2, "李四");
preparedStatement.setInt(3, 19);
preparedStatement.executeUpdate();
// 提交事务
connection.commit();
} catch (SQLException e) {
// 回滚事务
connection.rollback();
throw new RuntimeException(e);
} finally {
JdbcUtils.release(connection, preparedStatement, resultSet);
}
}
}
数据库连接池
1. 数据库连接池简介
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。数据库连接池在初始化时将创建多个数据库连接并将它们存储在一个池中。当应用程序需要访问数据库时,可以从池中获取一个可用的连接,使用完毕后再将连接返回到池中,而不是关闭连接。这样可以减少数据库连接的创建和销毁的开销,提高应用程序的性能。
2. 数据库连接池的作用
- 提高性能:数据库连接池可以减少数据库连接的创建和销毁的开销,提高应用程序的性能。
- 资源管理:数据库连接池可以管理数据库连接,避免数据库连接过多导致资源耗尽的问题。
- 连接复用:数据库连接池允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个,这样可以减少数据库连接的创建和销毁的开销。
- 连接监控:数据库连接池可以对数据库连接进行监控,及时发现和解决连接问题。
3. 数据库连接池的实现
数据库连接池的实现通常包括以下几个步骤:
- 初始化连接池:在应用程序启动时,初始化连接池,创建多个数据库连接并将它们存储在一个池中。
- 获取连接:当应用程序需要访问数据库时,可以从连接池中获取一个可用的连接。
- 使用连接:应用程序使用获取到的连接进行数据库操作。
- 释放连接:使用完毕后,将连接返回到连接池中,而不是关闭连接。
- 关闭连接池:在应用程序关闭时,关闭连接池,释放所有数据库连接。
4. 常见的数据库连接池
- DBCP(Database Connection Pool):DBCP是Apache Commons DBCP项目中的一个数据库连接池实现,它是一个轻量级的数据库连接池,支持连接池的配置和监控。
- C3P0:C3P0是一个开源的JDBC连接池实现,它支持连接池的配置和监控,并且提供了多种连接池的配置选项。
- HikariCP:HikariCP是一个高性能的JDBC连接池实现,它具有非常低的延迟和较高的吞吐量,并且支持连接池的配置和监控。
- Druid:Druid是一个高性能的JDBC连接池实现,它具有非常低的延迟和较高的吞吐量,并且提供了多种连接池的配置选项,包括监控、SQL解析等功能。
使用C3P0连接池
- 导入C3P0的jar包(下载地址:https://sourceforge.net/projects/c3p0/)
- 配置C3P0的配置文件c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<!--mysql数据库连接的各项参数-->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/school</property>
<property name="user">root</property>
<property name="password">123456</property>
<!--配置数据库连接池的初始连接数、最小链接数、获取连接数、最大连接数、最大空闲时间-->
<property name="initialPoolSize">10</property>
<property name="minPoolSize">10</property>
<property name="acquireIncrement">5</property>
<property name="maxPoolSize">100</property>
<property name="maxIdleTime">30</property>
</default-config>
</c3p0-config>
- 在代码中使用C3P0连接池
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class C3P0Utils {
private static DataSource dataSource;
static {
try {
dataSource = new ComboPooledDataSource();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 释放资源
public static void release(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if(resultSet != null) {
resultSet.close();
}
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
}
}
import java.sql.*;
public class JdbcTest {
public static void main(String[] args) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = C3P0Utils.getConnection();
connection.setAutoCommit(false); // 关闭自动提交并开启事务
String sql = "insert into studentpre values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(2, "李白");
preparedStatement.setInt(3, 1000);
preparedStatement.setInt(1, 11);
preparedStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
connection.rollback();
System.out.println("没有提交成功,事务回滚");
throw new RuntimeException(e);
} finally {
C3P0Utils.release(connection,preparedStatement,resultSet);
}
}
}
笔记总结于视频:https://www.bilibili.com/video/BV1NJ411J79W?spm_id_from=333.788.videopod.episodes&vd_source=16bf0c507e4a78c3ca31a05dff1bee4e