下载压缩文件,并解压缩到目标文件夹下
配置环境变量,例如安装路径为:F:\Environment\mysql-8.0.17-winx64
,系统环境变量下path中新建填写 F:\Environment\mysql-8.0.17-winx64\bin
.
安装目录下新建并配置my.ini文件
[mysql]
default-character-set=utf8
[mysqld]
#注意将这两个路径替换成实际的安装目录
basedir=F:\Environment\mysql-8.0.17-winx64
datadir=F:\Environment\mysql-8.0.17-winx64\data
port=3306
max_connections=200
character-set-server=utf8
default-storage-engine=INNODB
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
以管理员身份启动命令提示符,运行mysqld -install
命令安装MySQL,显示成功后,再运行mysqld --initialize
,初始化数据库,此时安装目录下生成了data文件夹
以net start mysql
命令启动MySQL,启动成功后,执行mysql -u root -p
登录MySQL,此时需要密码,打开data文件夹下的一个.err
文件,找到随机密码输入登录.
6.修改密码,执行以下命令:ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpassword';
就可以重设密码,然后重启MySQL即可正常使用。
net start mysql --启动数据库服务
mysql -u root -p --连接数据库
--所有的语句都以 分号 结尾
show database; --查看所有数据库
use + 'database name' --切换数据库
show tables; --查看数据库中所有的表
describe student; --显示数据库中所有的表的信息
...
数值
数据类型 | 数据大小 | 数据说明 |
---|---|---|
tinyint | 1个字节 | 十分小的数据 |
smallint | 2个字节 | 较小的数据 |
mediumint | 3个字节 | 中等大小的数据 |
int(常用) | 4个字节 | 标准整数 |
bigint | 8个字节 | 较大的数据 |
float | 4个字节 | 单精度浮点数 |
double | 8个字节 | 双精度浮点数 |
decimal | 字符串形式的浮点数(金融计算使用) |
字符串
数据类型 | 数据大小 | 数据说明 |
---|---|---|
char | 0~255 | 字符串固定大小(容易造成空间浪费) |
varchar(常用) | 0~65535 | 可变字符串 |
tinytext | 2^8 - 1 | 微型文本 |
text(常用) | 2^16 - 1 | 文本串 |
时间日期
类型名称 | 格式 | 描述 |
---|---|---|
date | YYYY-MM-DD | 日期格式 |
time | HH:mm:ss | 时间格式 |
datetime | YYYY-MM-DD HH:mm:ss | 常用的时间格式 |
timestamp | 1970.1.1到现在的毫秒数 | 时间戳 |
每一个表,都必须存在以下五个字段!未来的项目要求,表示一个记录的存在意义
id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
要求创建一个学生表包含以下字段
学号(int)
,姓名
,密码
,性别
,生日
,家庭住址
,邮箱
。
--注意点:
--1、表名和字段名都尽量用 ``(反单引号) 括起来
--2、所有语句结尾要加逗号
create table
if
not exists `student` (
`id` int ( 4 ) not null auto_increment comment '学号',
`name` varchar ( 30 ) not null default '匿名' COMMENT '姓名',
`pwd` varchar ( 20 ) not null default '123456' comment '密码',
`sex` varchar ( 2 ) not null default '女' comment '性别',
`birthday` datetime default null comment '出生日期',
`address` varchar ( 100 ) default null COMMENT '家庭住址',
`email` varchar ( 50 ) DEFAULT null COMMENT '邮箱',
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8
格式
CREAT TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
...
`字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]
修改
-- 修改表名 ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE `student` RENAME AS `stu`
-- 增加字段 ALTER TABLE 表名 ADD `字段名` 列属性
ALTER TABLE `stu` ADD `age` INT(3) AFTER `sex`
-- 修改表的字段
-- ALTER TABLE 表名 MODIFY 字段名 列属性
ALTER TABLE stu MODIFY age VARCHAR(3) -- 修改约束
-- ALTER TABLE 表名 CHANGE 表名 新表名 列属性
ALTER TABLE stu CHANGE age sage int(3) -- 字段重命名
-- 删除表的字段
-- ALTER TABLE 表名 DROP 字段名
ALTER TABLE stu DROP sage
-- 删除表(先判断是否存在再删除)
DROP TABLE IF EXISTS `tch`
常用命令
show CREATE DATABASE school --查看创建数据库的语句
SHOW CREATE TABLE student --查看创建student数据表的定义语句
DESC student --查看student表的结构
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间大小 | 较小 | 较大(约为前者2倍) |
优点 | 节约空间,速度快 | 安全性高,多表多用户操作 |
INNODB 在数据库表中只有一个.frm
文件(MySQL8.0后没有),以及上级目录下的ibdata1
文件。
MYISAM 对应的文件
.frm
文件 --> 表结构定义文件.MYD
文件 --> 数据文件(data).MYI
文件 --> 索引文件(index)设置数据库表的字符编码
charset=utf8
-- 将学生表中的grade字段设置为外键,引用gradelist中的gradeid字段
-- 方式一 自定约束名
KEY `约束名` (`设为外键的字段号`),
constraint `约束名` foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`)
-- 示例
KEY `FK_gradeid` (`grade`),
constraint `FK_gradeid` foreign key (`grade`) references `gradelist`(`gradeid`)
-- 方式二
foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`)
alter table `表名`
add constraint `约束名` foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`);
-- 示例
ALTER TABLE `stu`
ADD constraint `FK_gradeid` FOREIGN KEY (`grade`) REFERENCES `gradelist` (`gradeID`);
以上的操作都是物理外键,数据库级别的外键,不建议使用!
阿里Java规范:[强制]不得使用外键与级联,一切外键概念必须在应用层(代码层)解决
每次做delete和update都必须考虑外键的约束,会导致开发的时候很痛苦,测试数据极为不方便。
DML语言:数据操作语言
Insert
-- 插入数据
-- 语法:INSERT INTO `表名`([`字段1`,`字段2`,...])VALUES('值1','值2',...)
-- 值与字段一一对应
INSERT INTO `gradelist`(`gradeName`)VALUES ('大一');
-- 一次插入多条数据
INSERT INTO `gradelist`(`gradeName`)VALUES ('大二'),('大三'),('大四');
update
-- 修改数据
-- 语法:UPDATE 表名 set `字段名` = '新值' [where (条件)]
UPDATE `stu` SET `name` = '路人甲' WHERE `name` = '张三';
-- 若不指定条件 默认修改所有
UPDATE `stu` SET `name` = '路人'
-- 修改多个数据
UPDATE `stu`
SET `grade` = 1,birthday = '2001-7-9' -- 修改的数据用逗号隔开
WHERE `name` = '路人甲';
delete
-- 语法 delete from 表名 [where 条件]
-- 全部删除(危险操作)
DELETE FROM `stu`
-- 删除指定数据
DELETE FROM `stu` where id = 3;
作用:完全清空一个数据库表,表的结构和索引约束不会改变
相同点:
都能够删除数据,都不会删除表结构
不同点:
TRANCETE 重新设置自增列,计数器归零TRANCATE不会影响事务
…
连接方式 | 描述 |
---|---|
Inner Join | 如果表中有一个匹配项,就返回行 |
Left Join | 从左表中返回所有值,即使在右表中没有匹配 |
Right Join | 从右表中返回所有值,即使在左表中没有匹配 |
limit(起始下标,页面大小)
-- 表示显示从第几条起的多少条数据
select..
from..
where..
...
limit 0,5 -- 显示查询的从第一条开始的五条数据
函数名 | 描述 |
---|---|
Count() | 计数 |
SUM() | 求和 |
AVG() | 求平均值 |
MAX()、MIN() | 最大、最小值 |
… | … |
count(列名),count(1),count(*) 的区别
使用方法 | 区别 |
---|---|
count(列名) | 只包括列名那一列,在统计结果的时候,会忽略列值为空 |
count(1) | 包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL |
count(*) | 包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL |
后两者本质上区别不大,都不会忽略值为NULL的数据行,在特定的使用场景下,执行效率有所不同
group by 是让排序结果按规则进行分组排列
having 与 where用途相似 用来过滤分组中不符合要求的分组
-- 代码示例:
-- 要求筛选平均分>80的学科
select SubjectName as '科目',
AVG(StudentResult) as '平均分',
MAX(StudentResult) as '最高分',
MIN(StudentResult) as '最低分'
FROM result
LEFT JOIN `subject`
ON result.SubjectNo = `subject`.SubjectNo
GROUP BY result.SubjectNo
HAVING 平均分>80
主要增强算法复杂度和不可逆性
-- ============测试MD5============
create table `testmd5` (
`id` int ( 4 ) not null,
`name` varchar ( 20 ) not null,
`pwd` varchar ( 50 ) not null,
primary key ( `id` )
) engine = innodb default charset = utf8
insert into testmd5 values (1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456')
-- 加密
UPDATE testmd5
SET pwd=MD5(pwd)
WHERE id = 1
-- 插入时加密
insert into testmd5 values (4,'小明',MD5('123456'))
-- 查询校验
SELECT *
FROM testmd5
where `name` = '小明' and pwd = MD5('123456')
-- 语法顺序
select [去重] `要查询的字段` [as '别名'] -- 联表查询时避免模棱两可
from `表名`
(Inner/left/right) join `连接的表` on 等值条件
where (具体的值,或者子查询语句)
group by (分组参照)
having (过滤分组的条件) -- 用法与where一样
order by `排序的参考字段` [ASC/DECS] -- 默认递增
limit index,count -- 列出从第index条开始的count条数据
作为单个逻辑工作单元执行的一系列操作,要么都成功,要么都失败
事务的特性(4个) 又叫ACID特性
参考博客:https://blog.csdn.net/dengjili/article/details/82468576
原子性(Atomicity):
要么都成功,要么都失败
一致性(Consistency):
事务前后的数据完整性要保证一致
持久性(Durability):
事务一旦提交不可逆,被持久化到数据库中
隔离性(Isolation):
多个用户并发访问数据库时,数据库为每个用户开启事务,不被其他事务的操作所干扰,并发事务之间相互隔离
隔离所导致的一些问题:
脏读,不可重复读,幻读。
-- mysql 默认开启事务自定提交
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认)
-- 简单流程
-- 1、手动处理事务
SET autocommit = 0 -- 关闭自动提交
-- 2、事务开启
START TRANSACTION -- 标记一个事务的开启
/* 之后的sql操作都在这同一个事务内进行 */
-- 3、提交:持久化(成功!)
COMMIT
-- 3、回滚:回到起始状态(失败!)
ROLLBACK
-- 4、事务结束
SET autocommit = 1 -- 开启自动提交
-- 拓展了解
SAVEPOINT `保存点名` --设置一个事务的保存点
ROLLBACK TO SAVEPOINT `保存点名` --若事务失败 回滚到上一个保存点
RELEASE SAVEPOINT `保存点名` -- 撤销保存点
-- =======模拟转账场景=========
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop
CREATE TABLE `account`(
`id` INT(3) NOT NULL auto_increment,
`name` VARCHAR(10) not NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE = INNODB CHARSET = utf8
INSERT INTO `account`(`name`,`money`) VALUES ('A','2000'),('B','10000')
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION -- 开启事务
UPDATE account set money = money - 500 WHERE `name` = 'A' -- A转出500
UPDATE account SET money = money + 500 WHERE `name` = 'B' -- B收款500
COMMIT; -- 提交事务
ROLLBACK; -- 回滚
set autocommit = 1;
索引(index)是帮助MySQL高效获取数据的数据结构。
在一个表中,主键索引只能有一个,而唯一索引可以有多个
主键索引(primary key)
唯一的标识,主键不可重复,只能有一个列作为主键
唯一索引(unique key)
避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
常规索引(index/key)
默认,用index/key关键字设置
全文索引(FullText)
快速定位数据位置
-- =======索引的使用=====
-- 显示所有索引信息
show index from student
-- 增加一个索引 add fulltext index `索引名`(`列名`)
alter table student add fulltext index `studentname`(`studentname`)
-- 删除索引:
DROP INDEX 索引名 ON 表名字;
-- 删除主键索引:
ALTER TABLE 表名 DROP PRIMARY KEY;
-- explain 分析sql执行状况
explain select * from student
explain select * from student where match(studentname) against ('刘')
SELECT *
FROM app_user
where `name` = '用户99999' -- 创建索引前 > 时间: 1.924s
-- 创建索引后 > 时间: 0.083s
-- 索引名 命名规范 id_表名_字段名
-- CREATE INDEX 索引名 ON 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
从测试结果可以发现索引显著提高了大量数据的查询性能
索引的数据结构
Hash类型的索引
Btree:InnoDB的默认数据结构
推荐阅读 MySQL索引背后的数据结构及算法原理
可视化窗口管理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaEaWt5D-1581391881960)(Mysql学习文件/用户管理.png)]
SQL命令
系统数据库中有一用户表即:mysql.user,
本质上还是对表数据的增删改查。
-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER sakura0817 IDENTIFIED BY '170312'
-- 修改密码(修改当前用户密码)
SET password = '170312';
-- 修改密码(修改指定用户密码)
set password FOR sakura0817 = '170312'
-- 用户重命名
RENAME USER sakura0817 TO 5akura
-- 用户授权 all privileges全部的权限 (Grant Option)无法授予
grant all privileges on *.* to 5akura
-- 查看权限
show grants for 5akura -- 查看指定用户
show grants for root@localhost -- 查看管理员
-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM 5akura
-- 删除用户
DROP USER 5akura
备份方式
模板:
mysqldump -h主机地址 -u用户名 -p密码 数据库名 表名 >导出路径
示例:
mysqldump -hlocalhost -uroot -p170312 shop >F:/文档文件/shop.sql
# 导入
登陆后
source 备份文件
当数据较复杂时,我们需要设计数据库辅助管理数据
数据冗余,浪费空间
数据库插入删除操作麻烦、产生异常[屏蔽使用物理外键]
程序的性能差
节省内存空间
保证数据库的完整性
方便我们开发系统
关于数据库的设计
数据库设计具体步骤(个人博客为例)
收集信息,分析需求
标识实体(将每个需求落地到每个关键字)
当数据较复杂时,我们需要设计数据库辅助管理数据
数据冗余,浪费空间
数据库插入删除操作麻烦、产生异常[屏蔽使用物理外键]
程序的性能差
节省内存空间
保证数据库的完整性
方便我们开发系统
关于数据库的设计
数据库设计具体步骤(个人博客为例)
收集信息,分析需求
标识实体(将每个需求落地到每个关键字)
标识实体之间的关系
为什么需要数据规范化
第一范式(1NF)
第二范式(2NF)
第三范式(3NF)
关联查询的表不得超过三张表
程序
连接访问数据库
需要通过数据库驱动
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U86KlsIb-1582618981763)(JDBC是什么.png)]
由于不同数据库的驱动都不相同,操作也各不相同
SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)规范,俗称JDBC,规范的实现由各个厂商去做,开发人员只需要掌握JDBC接口的使用即可。
create database jdbcStudy CHARACTER set utf8 COLLATE utf8_general_ci;
use jdbcStudy;
CREATE TABLE users(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users values (1,'张三','123456','[email protected]','1999-12-03'),
(2,'李四','123456','[email protected]','1997-11-13'),
(3,'王五','123456','[email protected]','2000-2-08');
package com.sakura.jdbcstudy;
import java.sql.*;
/**
* 第一个JDBC程序
*
* @author 桜
* @Date 2020/2/11
*/
public class JDBC_demo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、加载驱动
/**
* com.mysql.jdbc
* 使用新版驱动 com.mysql.cj.jdbc
*/
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法
//2、用户信息和url
/**
* ?:访问链接
* 三个参数:
* useUnicode=true 支持中文编码
* characterEncoding=utf8 字符集utf-8
* useSSL=true 使用安全链接
*/
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String userName = "root";
String passWord = "170312";
//3、连接成功,获取数据库对象(getConnection(url,username,password)方法) 返回对象为数据库
Connection connection = DriverManager.getConnection(url, userName, passWord);
//4、执行SQL对象(createStatement()方法)
Statement statement = connection.createStatement();
//5、SQL的对象去执行SQL(若有执行结果,需要查看返回结果)
String sql = "select * from users";
ResultSet resultSet = statement.executeQuery(sql);//执行sql查询语句,并返回封装好的结果集;
//解读结果集 getObject(列名)
while (resultSet.next()) {
System.out.println("id = "+resultSet.getObject("id"));
System.out.println("name = "+resultSet.getObject("NAME"));
System.out.println("password = "+resultSet.getObject("PASSWORD"));
System.out.println("email = "+resultSet.getObject("email"));
System.out.println("birth = "+resultSet.getObject("birthday"));
System.out.println("-------------------");
}
//6、关闭连接
resultSet.close();
statement.close();
connection.close();
}
}
创建驱动
//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法
package com.mysql.cj.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
//注册驱动
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
可以看到在com.mysql.cj.jdbc.Driver()类中有一个静态代码块会在加载时自动执行注册驱动,所以只需用forname()方法即可,因为对类进行反射调用,一定会引发类初始化从而执行驱动的注册。
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
// 协议/主机地址:端口号/数据库名?参数1&参数2&参数3
//mysql-->3306,Oracle-->1521
//jdbc:oracle:thin@localhost:1521:sid
Connection (代表数据库)
//能执行大多数数据库中的操作
connection.rollback();//事务回滚
connection.commit();//事务提交
connection.setAutoCommit();//设置自动提交
执行SQL的对象
//可以执行多种SQL语句
statement.executeQuery();//查询 返回查询结果集
statement.executeUpdate();// 更新,插入,删除 返回受影响行数
statement.execute();//执行所有SQL语句
statement.executeBatch();//批次处理
ResultSet(只有查询有结果集返回)
resultSet.getObject()//在不清楚列数据类型时使用
//如果知道列类型就使用指定方法get数据
getString(),getFloat(),getDate(),....
resultSet.next();//下一条
resultSet.previous();//上一条
resultSet.beforeFirst();//第一条
resultSet.afterLast();//最后一条
resultSet.absolute();//指定行
资源释放
resultSet.close();
statement.close();
connection.close();//耗费资源,用完即关
sql存在漏洞,会被攻击导致数据泄露
or
,进入数据库盗取数据。public class SQL注入 {
public static void main(String[] args) {
login(" 'or '1=1","123456");
}
public static void login(String userName, String password) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
//SQL语言
String sql = "select * from users where `NAME`= '"+userName+"' and `passWord` = '" +password+ "'";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println("NAME = "+resultSet.getString("NAME")+"--> email = " + resultSet.getString("email"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection, statement, resultSet);
}
}
}
public class TestInsert {
public static void main(String[] args) {
Connection connection =null;
PreparedStatement preparedStatement =null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//区别
//1、使用 '?'占位符代替数据作为参数
String sql = "insert into users(id, `NAME`, `passWord`, email, birthday) values(?,?,?,?,?)";
//2、预编译SQL,先写SQL,但是不执行
preparedStatement = connection.prepareStatement(sql);
//3、手动参数赋值
// preparedStatement.setObject(); 不清楚列类型时使用
/**
* 参数为(列标,具体数据)
* 1代表第一个字段,2代表第二个字段....
*/
preparedStatement.setInt(1,5);//设置id
preparedStatement.setString(2,"官宇辰");//设置name
preparedStatement.setString(3,"170312");//设置passWord
preparedStatement.setString(4,"[email protected]");//设置email
// 注意点 sql.Date 与 util.Date 不同
preparedStatement.setDate(5,new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2000-08-17").getTime()));//设置birthday
//4、执行 直接执行无需传参
int i = preparedStatement.executeUpdate();
if (i>0) {
System.out.println("操作成功");
}
} catch (SQLException | ParseException e) {
e.printStackTrace();
} finally {
//...释放资源
JdbcUtils.release(connection, preparedStatement, resultSet);
}
}
}
本质:把传入的参数当作字符,把用户非法输入的单引号用\反斜杠做了转义,就避免了参数也作为条件的一部分。
connection.setAutoCommit(false);
代码实现
public class TestTransacation02 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//关闭数据自动提交,会自动开启事务
connection.setAutoCommit(false);
String sql1 = "update account set money = money - 100 where name = 'A'"; //A转出100
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.executeUpdate();
String sql2 = "update account set money = money + 100 where name = 'B'"; //B入账100
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//业务完毕,提交事务
connection.commit();
System.out.println("转账成功");
} catch (SQLException e) {
try {
connection.rollback(); //失败回滚
System.out.println("转账失败");
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtils.release(connection, preparedStatement, resultSet);
}
}
}
产生原因:因为数据库的连接与释放 十分浪费系统资源
池化技术:预先准备一些资源,过来直接连接
编写连接池,实现一个接口 DataSource
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZN9t0Nru-1582618981766)(dbcp实现接口.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5LRonNM-1582618981767)(c3p0继承接口.png)]
优秀的开源数据源实现(使用后,项目开发中不需要编写连接数据库的代码了)
结论
无论使用什么数据源,本质都是一样,都要实现DataSource接口,方法不变,只是不同的实现方式。