MySQL基础知识总结

MySQL

1.简介

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

1.1 数据库分类

关系型:(SQL)

  • 通过表之间,行,列之间的关系进行数据的存储
  • MySQL,Oracle…

非关系型:(NoSQL)

  • 对象存储,通过对象自身属性来决定
  • Redis,MongDB

DBMS(数据库管理系统)

  • 作用:管理和操作数据库
  • MySQL:关系型数据库管理系统

数据库xxx语言

  • DDL 定义

  • DML 操作

  • DQL 查询

  • DCL 控制

2.操作数据库

如果表名或者字段名是特殊字符,需要带~ ~

数据库引擎

MYISAM INNODB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间大小 大,约为MYISAM2倍

常规操作:

  • MYISAM:节约空间,速度较快
  • INNODB:安全性高,支持事务,适合多表(外键)多用户(事务)操作

3.MySQL数据管理

3.1外键

方式一:在创建表的时候,增加约束

CREATE TABLE IF NOT EXISTS `student`{
`gradeid` INT(10) NOT NULL COMMENT '学生年级',
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
}ENGINE=INNODB DEFAULT CHARSET=utf-8

删除外键关系的表,先删除从表,再删除主表

方式二:创建表之后添加外键约束

ALERT TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(gradeid)
--ALERT TABLE 表 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 被引用的表(被引用的字段)

以上为物理外键。

最佳实践:不用物理外键

  • 数据库是单纯的表,只用来存储数据
  • 用程序实现外键

3.2 DML语言

3.3 添加

insert

语法:insert into 表名([字段1,字段2,字段3])values('值1'),('值2'),('值3');每个值对应一组数据中该字段对应的值

insert into student (`name`,`pwd`,`gender`) VALUES ('张三','aaa','男')

3.4 修改

--语法
--update 表名 set column_name = value,[column_name=value,...] where [条件]

条件子句中通过操作符编写
MySQL基础知识总结_第1张图片

3.5 删除

delete 命令

语法:delete from 表名 [where 条件]

Truncate 命令

完全删除一个数据库表,表的结构和索引不会变化

语法:truncate table 表名

delete与truncate的区别

  • 相同:删除数据库数据,不影响表结构

  • 不同:

    • truncate使得自增列从0开始
    • truncate不影响事务

delete删除的问题

重启数据库后的现象

  • InnoDB:自增列从1开始,(存在内存中的,断电即失)
  • MyISAM:继续从上一个自增列开始(存在文件中,不会丢失)

4.DQL查询数据

4.1 DQL

数据查询语言

select 字段名 from table

SELECT语法

SELECT[ALL|DISTINCT|DISTINCTROW|TOP]
{
    *|talbe.*|[table.]field1[AS alias1][,[table.]field2[AS alias2][,]]}
FROM table_name[as table_alias]
[left|right|inner join table_name2]--联合查询
[WHERE]--指定查询结果满足的条件
[GROUP BY]--指定结果分组
[HAVING]--过滤分组的记录需要满足的次要条件
[ORDER BY]--查询记录按一个或多个条件排序
[LIMIT m(起始位置),n(偏移长度)]

4.2 指定查询字段

SELECT studentno as 学号,studentname as 学生姓名 FROM student	as s;
-- 拼接函数: Concat(a,b)
SELECT CONCAT('姓名:',studentname) as 新名字 FROM student;

去重

SELECT DISTINCT studentno FROM result;

数据库中的表达式

--查询自增的步长
SELECT @@auto_increment_increment;
--考试成绩+1分查看
SELECT studentno,studentresult+1 as 提分后 FROM result;

4.3 where条件子句

-- != not
SELECT studentNo,studentresult From result 
WHERE NOT studentNo=1000;

模糊查询

运算符 语法 描述
Like a like b 如果a匹配b,则结果为真
In a in (a1,a2,…) a在()中的某个,结果为真
-- 张后面只有一个字符的
SELECT studentno,studentname FROM student
WHERE studentname	LIKE '张_';
-- 查询为空的
SELECT studentno,studentname FROM student
WHERE address='' or address is NULL;
-- 查询不为空的
SELECT studentno,studentname FROM student
WHERE borndate is NOT NULL;

4.4 联表查询

MySQL基础知识总结_第2张图片 MySQL基础知识总结_第3张图片
  • 根据业务需求写SQL
/*
思路:
1.分析查询字段来自哪些表,(则要使用连接查询)
2.确定使用哪种连接
3.确定交叉点(两个表中哪个数据相同)
如:学生表的 studentno=成绩表的 student
*/
--join 连接的表 on 判断条件//连接查询
--where //等值查询
  • 使用left/right join时,on和where的区别

    • on条件后会生成临时表,不管不管条件是否为真,都会返回左表所有的行(left join),返回右表所有的行(right join)
    • where在临时表生成后通过其后的条件对on生成的临时表进行过滤,left/right join的效果丢失(可以理解为inner join,只返回相关联的记录),条件(on条件+where条件)不为真的全部过滤掉,不显示
    --eg:查询时逐行查询,当符合条件时,查询出重复teacherno相对应studentno的同一条记录
    SELECT s.studentno,teacherno
    FROM student s
    LEFT JOIN teacher t
    on s.studentno=t.teacherno;
    
    MySQL基础知识总结_第4张图片
  • student表和result表概况
    student表

    result表
    MySQL基础知识总结_第5张图片

--inner join 两表的共有部分才查询出来
SELECT r.studentno,studentname,subjectno,studentResult
FROM student as s
INNER JOIN result as r
WHERE s.studentno=r.studentno;

MySQL基础知识总结_第6张图片

--left join 将左表全部查询出来
SELECT s.studentno,studentname,subjectno,studentResult
FROM student s 
LEFT JOIN result r
on s.studentno=r.studentno;
MySQL基础知识总结_第7张图片
--right join 将右表全部查询出来,如果右表的条件字段在左表中没有,则查询结果不显示右表中特有的条件字段(参加考试的所有信息)
SELECT s.studentno,studentname,subjectno,studentResult
FROM student s 
RIGHT JOIN result r
on s.studentno=r.studentno;
MySQL基础知识总结_第8张图片
--查询缺考的学生
SELECT s.studentno,studentname,subjectno,studentResult
FROM student as s
LEFT JOIN result as r
on s.studentno=r.studentno
WHERE studentResult is NULL;
--查询参加考试的同学信息:学号,学生姓名,科目名,分数
SELECT s.studentno,studentname,subjectname,studentResult
FROM student as s
RIGHT JOIN result as r
on s.studentno=r.studentno
INNER join `subject` as sub
on r.subjectno=sub.subjectno;
MySQL基础知识总结_第9张图片

分析查询步骤,将多次查询阶段拆分成多次

思路:

  1. 要查询哪些数据 select
  2. 从哪几个表中查询 from 表 xxx join 连接的表 on 交叉条件
  3. 若有多张表查询,先查询两张表,再查询剩下的

自连接

表和自身连接,把一张表拆成两张表

父类(顶级id)

categoryid categoryName
2 信息技术
3 软件开发
5 美术设计

子类

pid categoryid categoryName
3 4 数据库
2 8 办公信息
3 6 web开发
5 7 美术设计

操作:查询父类对应的子类关系

父类 子类
信息技术 办公信息
软件开发 数据库
软件开发 web开发
美术设计 ps技术
--查询父子信息,把一张表看成两张表
SELECT a.categoryname as 父栏目,b.categoryname as 子栏目
FROM category as a,category as b
WHERE a.categoryid=b.pid;
MySQL基础知识总结_第10张图片

4.5 分页和排序

limit语法:limit(起始值,pagesize)

-- LIMIT 0,5从记录0开始,显示5条记录
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY studentresult ASC
LIMIT 0,5;

order by:

-- ORDER BY:升序ASC,降序DESC
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY studentresult ASC;

4.6 子查询

where(条件的值是查询得到的)

即:where(select * from)

将子查询得到的结果作为条件在主查询中查询

-- 查询数据库结构-1的所有考试结果(学号,科目编号,成绩),降序排列
--方式一:联表查询
--在on连接条件查询出的结果中,筛选subjectname为指定结果的数据
SELECT r.studentno,r.subjectno,studentresult
FROM result r
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1';
--方式二:子查询
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname='数据库-1'
)
ORDER BY studentresult DESC;

--练习:
-- 查询课程为高等数学-2 且分数不小于80的同学的学号和姓名
--联表查询
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
where subjectname='高等数学-2'&& studentresult>=80;
-- 最后一个联表查询改造成子查询
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
WHERE studentresult>=80 AND subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname='高等数学-2';
-- 将两个联表查询都改为子查询
SELECT s.studentno,studentname
FROM student s
WHERE studentno IN (
SELECT studentno FROM result
WHERE studentresult>=80 AND subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname='高等数学-2'
)
);

4.7 过滤和分组

-- 查询按课程分组的>80的平均分,最高分,最低分,只显示平均分大于80分的
SELECT subjectname,AVG(studentresult),MAX(studentresult),min(studentresult)
FROM result r
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
GROUP BY subjectname
HAVING AVG(studentresult)>=80;

5.MySQL函数

5.1 常用函数

SELECT CURRENT_DATE;-- 日期
SELECT CURDATE();-- 日期
SELECT now();-- 时间
SELECT LOCALTIME;
SELECT SYSDATE();
SELECT SYSTEM_USER();-- 用户
SELECT USER();
SELECT VERSION()-- Mysql版本

5.2 聚合函数

SELECT COUNT(字段名)--等其他函数

5.3 MD5加密

--加密
UPDATE tb1 set pwd=MD5(pwd);
--插入时候加密
INSERT INTO tb1 VALUES(1,'Tom',MD5('123456'))
--校验
SELECT * FROM tb1 WHERE name='Tom' AND pwd=MD5('123456');

6.事务

6.1 定义

一组SQL放在一个批次中执行

事务原则(ACID)

原子性:要么都成功,要么都失败。

一致性:事务前后的数据完整性保证一致。总和不变

隔离性:不同用户同时访问数据库,每个用户单独一个事务,不能被其他事务操作干扰。

持久性:事务一旦提交就持久化到数据库,不可逆。

隔离导致的问题

脏读:一个事务读取了另外一个事务未提交的数据。

不可重复读:一个事务多次读取某一行记录,多次读取的结果不一致。

幻读:一个事务内读取到了其他事务插入的数据,前后读取结果不一致。

-- mysql默认开启事务自动提交
SET autocommit=0 /*关闭*/
SET autocommit=1 /*开启*/

-- 转账
-- 建数据库
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
use shop

-- 建表
CREATE TABLE account(
id 	INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
money DECIMAL(9,2) NOT NULL,
PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8-- innodb支持事务

-- 插入数据
INSERT INTO account(`name`,money)
VALUES ('A',1000.00),('B',2000.00)

-- 模拟转账的事务
SET autocommit=0;  --关闭自动提交
START TRANSACTION

UPDATE account SET money=money-500 WHERE `name`='A';
UPDATE account set money=money+500 WHERE `name`='B';

COMMIT
ROLLBACK

SET autocommit=1 --开启自动提交

7.索引

索引帮助mysql快速获取数据的数据结构。

7.1 索引分类

  • 主键索引 (PRIMARY KEY)
    • 只能有一个列作为主键,主键不可重复
  • 唯一索引 (UNIQUE KEY)
    • 避免重复列的出现,可以有多个列都为唯一索引,且唯一索引的记录可以重复
  • 常规索引 (KEY/INDEX)
  • 全文

语法

-- 显示索引信息
SHOW INDEX FROM tb1
--增加一个全文索引 (索引名) 列名
ALTER TABLE school.student ADD FULLTEXT INDEX studentname(studentname);
-- 法二:CREATE INDEX 索引名 on 表(字段)
-- 索引名:id_表名_字段名
CREATE INDEX id_app_user_name ON app_user(`name`)
--explain 分析sql,全文索引,找出建立全文索引的字段和指定字符进行匹配
EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('刘')

java中的事务代码

try(){
     
    业务代码
    commit();
}catch{
     
    rollback();
}

7.2测试索引

索引效果:

CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '',
`email` varchar(50) NOT NULL,
`phone` varchar(20) DEFAULT '',
`gender` tinyint(4) unsigned DEFAULT '0',
`password` varchar(100) NOT NULL DEFAULT '',
`age` tinyint(4) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

-- 插入100万数据.
DELIMITER $$
-- 写函数之前必须要写,标志
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`)VALUES(CONCAT('用户',i),'[email protected]','123456789',FLOOR(RAND()*2));
SET i=i+1;
END WHILE;
RETURN i;
END;

DROP FUNCTION mock_data;
SELECT mock_data() -- 执行此函数 生成一百万条数据

SELECT * FROM app_user WHERE `name`='用户10000' -- 2.034s

CREATE INDEX id_app_user_name on app_user(`name`); -- 10.910s

SELECT * FROM app_user WHERE `name`='用户10000' -- 0.084s

7.3 索引原则

  • 不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表不需要加索引
  • 索引一般在常用来查询的字段上(索引覆盖)

索引的数据结构

btree:InnoDB默认的数据结构

8.权限管理和备份

8.1权限管理

sql命令操作

用户表:mysql.user

权限管理的本质:对用户表进行crud

用户管理:

-- 创建用户
CREATE USER plancer IDENTIFIED BY '123456';

-- 修改密码
SET PASSWORD FOR plancer =PASSWORD('111111')

-- 重命名用户名
RENAME USER plancer TO plancer1

-- 用户授权 on *.*表示对所有库.表授权
GRANT ALL PRIVILEGES ON *.* TO plancer1

-- 查询权限
SHOW GRANTS FOR plancer1
SHOW GRANTS FOR root@localhost

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM plancer1

-- 删除用户
DROP USER plancer1

8.2 MySQL备份

备份原因:

  • 保护数据不丢失
  • 数据转移

备份方式

  • 拷贝物理文件
  • 在可视化工具手动导出
  • 使用命令行导出:mysqldump

可视化工具导出(Navicat Premium)

MySQL基础知识总结_第11张图片

命令行导入

#导出表
mysqldump -hlocalhost -uroot -p123456 school student >d:/a.sql
#导出多个表
mysqldump -hlocalhost -uroot -p123456 school student result >d:/b.sql
#导出数据库
mysqldump -hlocalhost -uroot -p123456 school >d:/c.sql

#导入,在登录状态下,切换到指定的数据库
source d:/a.sql
#导入方式二
mysql -u用户名 -p密码 库名 <文件物理地址

9.规范数据库设计

9.1 为什么要设计

数据库比较复杂时,就需要设计

软件开发中,关于数据库的设计

  • 分析需求
  • 设计关系图E-R图

设计数据库的步骤

例(个人博客)

  • 分析需求(要哪些表):

    • 用户表(用户登录注销,用户个人信息,写博客,创建分类
      • id,username,password,gender,age,signature
    • 分类表(文章分类,谁创建的)
      • id,category_name,create_name_id
    • 文章表(文章内容)
      • id,title,author_id,category_id,content,create_time,update_time,love
    • 评论表
      • id,blog_id,user_id,content,create_time,user_id_parent(其回复的评论id)
    • 友链表(链接信息)
      • id,link(链接名称),href(链接地址),sort(友链排序)
    • 自定义表(系统信息,某个关键的子或者字段)key:value
  • 标识实体(把需求落地到每个表的字段)

  • 标识实体之间的关系

    • 写博客:user->blog
    • 创建分类:user->category
    • 关注:user->user
    • 友链:links
    • 评论:user-user-blog

    9.2 三大范式

    为什么需要规范化?

    • 信息重复
    • 更新异常
    • 插入异常
    • 删除异常

    三大范式

    第一范式

    原子性:每个字段的值不能再拆分

    第二范式(在1NF基础上)

    针对联合主键(多个字段构成的主键):所有字段必须依赖于主键,而不能依赖于主键的一部分

    每张表只描述一件事情

MySQL基础知识总结_第12张图片

第三范式(在1NF和2NF基础上)

每个字段都和主键直接相关,而不能间接相关
MySQL基础知识总结_第13张图片

规范性和性能不可兼得

关联查询的表不超过三张表

  • 商业化的需求,性能更重要
  • 在考虑性能的时候,需要适当考虑规范性
  • 故意增加冗余字段,从多表查询变为单表查询
  • 故意增加计算列(如select count(*),添加计算列,每插入一条数据,该列加1),或者添加索引(但是索引树会占内存)

10.JDBC

10.1 数据库驱动

通过数据库的驱动把数据库和Java程序连通在一起。

10.2 JDBC

在数据库驱动和应用程序之间的规范,工程师只需要面向JDBC接口编程。
MySQL基础知识总结_第14张图片

10.3 第一个JDBC程序

1.创建测试数据库

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`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')

2.引入jar包:mysql-connector-java-5.1.47.jar
MySQL基础知识总结_第15张图片
3.编写java程序

public class jdbcFirstDemo {
     
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
     
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");//加载后,Driver放到类模板,激活Driver的静态代码块,就注册了一个Driver
        //2.用户信息和url
        String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
        String username="root";
        String password="123456";
        //3.连接成功,数据库对象 Connection代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.执行sql的对象 Statement 执行sql的对象
        Statement statement = connection.createStatement();
        //5.执行sql的对象去执行sql,可能存在结果,则查看返回结果
        String sql="select * from users";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()){
     
            System.out.println("id=" + resultSet.getObject("id"));
            System.out.println("name=" + resultSet.getObject("NAME"));
            System.out.println("pwd=" + 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();
    }
}

JDBC程序步骤总结:

1.加载驱动

2.url,username,password

3.获取数据库对象 DriverManager

4.新建执行sql的statement对象

5.新建sql语句,并用statement执行sql,显示返回的resultSet

6.释放连接

所用类简介

DriverManager

Class.forName("com.mysql.jdbc.Driver");//加载驱动
Connection connection = DriverManager.getConnection(url, username, password);
//connection 代表数据库
//功能:数据库设置自动提交;事务提交;事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit();

URL

String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
//mysql --3306
// 格式:协议://主机地址/数据库?参数1&参数2&参数3

Statement 执行SQL的对象 PrepareStatement 执行sql的对象

statement.executeQuery();//执行查询
statement.execute();//执行增删改查
statement.executeUpdate();//执行增,删,改

ResultSet 查询的结果集:返回了所有的查询结果

获得指定数据类型

resultSet.getObject();//不知道列类型情况下使用,知道列类型就使用具体的列类型

遍历,指针

resultSet.next();//移动到下一个数据
resultSet.previous();//前一个
resultSet.beforeFirst();//最前面
resultSet.afterLast();//最后面
resultSet.absolute(row);//移动到指定行

释放资源

按照资源声明倒序依次关闭

resultSet.close();
statement.close();
connection.close();

10.4 statement对象

提取公共方法,将连接到数据库和获取连接,释放连接抽取到公共工具类

1、提取公共参数driver、url、username、password

2、通过类加载器导入配置文件流getResourceAsStream,参数载入文件流properties.load(in),为每个公共参数赋值

3、加载驱动

4、获取连接和释放连接的函数

public class JdbcUtils {
     
    private static String driver=null;
    private static String url=null;
    private static String username=null;
    private static String password=null;

    static{
     
        try {
     
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);

            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");

            //1.驱动只加载一次
            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
     
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
     
        return DriverManager.getConnection(url,username,password);
    }
    //释放连接
    public static void release(Connection con, Statement st,ResultSet rs){
     
        if (rs!=null){
     
            try {
     
                rs.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
        if (st!=null){
     
            try {
     
                st.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
        if (con!=null){
     
            try {
     
                con.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
    }
}

对于不同的sql任务,只需要改变sql语句,不同任务的业务代码用同一个模板。

1、提取公共参数Connection、Statement、ResultSet

2、建立连接和创建statement

3、写sql,并用statement执行sql,对产生的ResultSet进行显示

4、调用工具类的方法释放连接

测试插入数据:

public class TestInsert {
     
    public static void main(String[] args) {
     
        Connection con=null;
        Statement st=null;
        ResultSet rs=null;

        try {
     
            con= JdbcUtils.getConnection();//第一次调用类静态方法,就读取了数据库配置文件(执行静态代码块)
            st=con.createStatement();
            String sql="INSERT INTO users(id,NAME,PASSWORD,email,birthday)" +
                    "VALUES(4,'plancer','123456','[email protected]','1997-10-10')";
            int i = st.executeUpdate(sql);
            if (i>0){
     
                System.out.println("插入数据成功");
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

测试删除数据:

public class TestDelete {
     

        public static void main(String[] args) {
     
            Connection con=null;
            Statement st=null;
            ResultSet rs=null;

            try {
     
                con= JdbcUtils.getConnection();//第一次调用类静态方法,就读取了数据库配置文件(执行静态代码块)
                st=con.createStatement();
                String sql="DELETE from users where id=4";
                int i = st.executeUpdate(sql);
                if (i>0){
     
                    System.out.println("删除数据成功");
                }
            } catch (SQLException e) {
     
                e.printStackTrace();
            }finally {
     
                JdbcUtils.release(con,st,rs);
            }
        }
}

更改数据:

public class TestUpdate {
     
    public static void main(String[] args) {
     
        Connection con=null;
        Statement st=null;
        ResultSet rs=null;

        try {
     
            con= JdbcUtils.getConnection();//第一次调用类静态方法,就读取了数据库配置文件(执行静态代码块)
            st=con.createStatement();
            String sql="UPDATE users set NAME ='lancer',email='[email protected]' where id=3";
            int i = st.executeUpdate(sql);
            if (i>0){
     
                System.out.println("更改数据成功");
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

查询数据:

public class TestSelect {
     
    public static void main(String[] args) {
     
        Connection con=null;
        Statement st=null;
        ResultSet rs=null;
        try {
     
            con=JdbcUtils.getConnection();
            st = con.createStatement();

            //SQL
            String sql="select * from users where id=1";
            rs = st.executeQuery(sql);

            while (rs.next()){
     
                System.out.println(rs.getString("NAME"));
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

SQL注入

sql存在漏洞,被攻击导致数据泄露,本质:sql会被拼接,拼接为name=' ' or '1=1'
1=1为true,这样,非合法的用户名和密码也能查询数据库中所有的结果,导致数据泄露。

sql注入格式:pwd输入为:'or’1=1

测试代码:

public class SQL注入 {
     
    public static void main(String[] args) {
     
        login(" 'or'1=1"," 'or '1=1");

    }
    //登录业务
    public static void login(String name,String password){
     
        Connection con=null;
        Statement st=null;
        ResultSet rs=null;
        try {
     
            con= JdbcUtils.getConnection();
            st = con.createStatement();

            //SQL
            String sql="select * from users where `name` ='"+name+"' and `password`='"+password+"'";
            rs = st.executeQuery(sql);

            while (rs.next()){
     
                System.out.println(rs.getString("NAME"));
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

10.5、PreparedStatement对象

PreparedStatement可以防止SQL注入,且效率更高。

select测试代码:

public class TestSelect {
     
    public static void main(String[] args) {
     
        Connection con=null;
        PreparedStatement st=null;
        ResultSet rs=null;
        try {
     
            con = JdbcUtils.getConnection();
            String sql="select * from users where id = ?";
            st= con.prepareStatement(sql);
            st.setInt(1,4);
            rs= st.executeQuery();

            while (rs.next()){
     
                System.out.println(rs.getString("NAME"));
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

防止sql注入

public class 防止SQL注入 {
     
    public static void main(String[] args) {
     
        login(" 'or'1=1"," 'or '1=1");

    }
    //登录业务
    public static void login(String name,String password){
     
        Connection con=null;
        PreparedStatement st=null;
        ResultSet rs=null;
        try {
     
            /*
            预编译防止sql注入的本质:
            把传递过来的参数当做字符(个别),而不是字符串(整体)
            如果有转义字符',则将之转义
             */
            con= JdbcUtils.getConnection();
            String sql="select * from users where `name` =? and `password`=?";
            st = con.prepareStatement(sql);
            st.setString(1,name);
            st.setString(2,password);

            rs = st.executeQuery();

            while (rs.next()){
     
                System.out.println(rs.getString("NAME"));
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(con,st,rs);
        }
    }
}

10.6 IDEA连接数据库

1.连接数据库
MySQL基础知识总结_第16张图片
2.配置用户名,密码,测试连接
MySQL基础知识总结_第17张图片
连接错误情况:
MySQL基础知识总结_第18张图片
3.选择对应数据库
MySQL基础知识总结_第19张图片

10.7、JDBC操作事务

public class TestTransaction {
     
    public static void main(String[] args) {
     
        Connection con=null;
        try {
     

             con= JdbcUtils.getConnection();
             con.setAutoCommit(false);//关闭自动提交,自动开启事务
             String sql1="update account set money=money-100 where name ='A'";
             PreparedStatement st1 = con.prepareStatement(sql1);
             st1.executeUpdate();

             int x=1/0;

             String sql2="update account set money=money+100 where name ='B'";
             PreparedStatement st2 = con.prepareStatement(sql2);
             st2.executeUpdate();

             con.commit();
            System.out.println("success");
        } catch (SQLException e) {
     
            //默认自动回滚
            e.printStackTrace();
        }
    }
}

10.8、数据库连接池

池化技术:由于连接-释放浪费系统资源,所以准备预先资源,过来就连接准备好的

最小连接数

最大连接数

等待超时:

编写连接池,实现DataSource接口

开源数据源实现

  • DBCP

  • C3P0

  • Druid

DBCP

用到的jar包:

commons-dbcp-1.4、commons-pool-1.6

操作步骤:

1、导入jar包
MySQL基础知识总结_第20张图片
2、src下配置properties文件
MySQL基础知识总结_第21张图片

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&uesSSL=true
username=root
password=123456

#
initialSize=10

#最大连接数量
maxActive=50

#
maxIdle=20

#
minIdle=5

#
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED

3、创建工具类,读取配置文件,工厂模式创建数据源

public class JdbcUtils_DBCP {
     


   private static DataSource dataSource=null;
    static{
     
        try {
     //由那个类的加载器加载配置文件到输入流都可以,JdbcUtils可替换
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpdb.properties");
            Properties properties = new Properties();
            properties.load(in);

            //工厂模式创建数据源,而不需要如自定义配置中在代码中手动设置url,name,pwd等
            dataSource=BasicDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
     
        return dataSource.getConnection();//自定义配置是用DriverManager.getConnection();
    }
    //释放连接
    public static void release(Connection con, Statement st, ResultSet rs){
     
        if (rs!=null){
     
            try {
     
                rs.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
        if (st!=null){
     
            try {
     
                st.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
        if (con!=null){
     
            try {
     
                con.close();
            } catch (SQLException e) {
     
                e.printStackTrace();
            }
        }
    }
}

4、测试DBCP,通过JdbcUtils_DBCP获取Connection

public class TestDBCP {
     
    public static void main(String[] args) {
     
        Connection con=null;
        PreparedStatement st=null;

        try {
     
            con= JdbcUtils_DBCP.getConnection();
            //编写sql,得到预编译statement
            String sql="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";
            st=con.prepareStatement(sql);
            //参数赋值
            st.setInt(1,5);
            st.setString(2,"lancer1");
            st.setString(3,"123456");
            st.setString(4,"[email protected]");
            st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

            //执行
            int i = st.executeUpdate();
            if (i>0){
     
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
     
            e.printStackTrace();
        }
    }
}

C3P0

用到的jar包

c3p0-0.9.55、mchange-commons-java-0.2.19

1、添加两个jar包到lib目录

2、src目录下添加c3p0.xml配置文件

3、建立c3p0Util,通过new ComboPooledDataSource(“MySQL”)的方式创建数据源(MySQL为配置文件中某个配置的名称)

4、测试c3p0,只需要通过c3p0Util获取Connection(本质上是DataSource返回的connection)和释放连接。

总结

更换数据源,DataSource接口不会变,方法不变,本质上只是更换数据源的获取方式。

你可能感兴趣的:(MySQL,mysql,数据库,sql,java)