Mysql学习

数据库分类

关系型数据库 行列

MySQL、Oracle、Sql Server,DB2,SQLite

非关系型数据库 key value (NoSQL)Not only

  • Redis,MongDB

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

DBMS 数据库管理系统

-- 单行注释
/* 多行注释 */ 
show databases;
use school;
show tables;
describe student;
create database west;
exit;
  • DDL 数据库定义语言

  • DML 数据库操作语言

  • DQL 数据库查询语言

  • DCL 数据库控制语言

操作数据库

mysql 关键字不区分大小写

操作数据库

CREATE DATABASE [IF NOT EXISTS] school;
DROP DATABASE [IF EXISTS] hello;
USE `school`;
SHOW DATABASES;
SHOW DATABASE school;

数据库列类型

  • 数值

    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 即 65535

  • 时间日期

    date YYYY-MM-DD,日期格式

    time HH:mm:ss,时间格式

    datetime YYYY-MM-DD HH:mm:ss 最常用的时间格式

    timestamp 时间戳,1970.1.1 至今的毫秒数

    year 年份表示

     

创建 & 操作表

创建表

CREATE TABLE IF NOT EXISTS student(
    id INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
    `name` VARCHAR(5) NOT NULL DEFAULT '匿名' COMMENT '名字',
    `birthday` DATE DEFAULT NULL COMMENT '出生日期',
    PRIMARY KEY (id)
) ENGINE=INNODB  DEFAULT CHARSET=utf8;
-- 显示表的详细信息
DESC student;
-- 显示创建表或数据库的详细信息
SHOW CREATE DATABASE school;
SHOW CREATE TABLE student;

操作表

-- 重命名表
ALTER TABLE student RENAME AS student1;
-- 给表添加字段
ALTER TABLE student1 ADD age INT(11);
-- 给表修改字段
ALTER TABLE student1 MODIFY age VARCHAR(11);
ALTER TABLE student1 CHANGE age age1 INT(10);
-- 删除字段
ALTER TABLE student1 DROP age1;
-- 删除表
DROP TABLE IF EXISTS student2;

 

操作列(DML)

unsigned、zerofill、自增、非空、默认

-- 增加物理外键,不便管理
-- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREIGN KEY (作为外键的列) REFERENCES 主表 ('stu_id');
ALTER TABLE student1
ADD CONSTRAINT 'FK_id' FOREIGN KEY ('id') REFERENCES student2('stu_id');

DML 数据库操作语言

-- 添加
INSERT INTO student1 (`name`,`birthday`) VALUES ('wang','1999-1-1'),('w','1998-1-1');
-- 修改
UPDATE student1 SET `name`='狂' WHERE id = 1;
UPDATE student1 SET `name`='wang',`birthday`='1998-1-1'  WHERE id >= 4;
-- 删除 1,delete from 表
DELETE FROM student1 WHERE `name` = '匿名';
-- 删除 2,计数器会归零,不会影响事务
TRUNCATE TABLE student2

重启数据库后,delete 的现象:

  • InnoDB 自增列从 1 开始,存在内存中,断电即失

  • MyISAM 从上一个子增量开始,存在文件中,不会丢失

 

DQL 查询语言

<> 或 != (不等于)、between ... and ... 、AND、OR、Not

IS NULL,IS NOT NULL,LIKE(模糊查询,% 表 0 到任意个字符,_ 表 1 个字符)、IN(in (1001, 1002))

-- 查询的基本语言
SELECT * FROM student1;
SELECT `name` AS 名字 FROM student1;
-- 去重  distinct
SELECT DISTINCT `name` AS 名字 FROM student1;
​
-- 查询当前用户
SELECT USER()
-- 查询系统版本
SELECT VERSION()
-- 查询自增的步长
SELECT @@auto_increment_increment;
-- 用来计算表达式
SELECT 100 * 3 / 4;
​
-- 查询日期
SELECT CURRENT_DATE()
SELECT CURDATE()
SELECT NOW()
SELECT LOCALTIME()
SELECT SYSDATE()
-- now 作参数
SELECT YEAR(NOW())

联表查询

join (连接的表) on(连接条件) 连接查询

where 等值查询

-- Inner join on/where 返回左右表匹配的笛卡尔积
-- Left join on 返回左表有,即使右表没有的笛卡尔积
-- Right join on 返回右表有,即使左表没有的笛卡尔积
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult` 
FROM student AS s INNER JOIN result AS r
WHERE s.studentno = r.studentno

自连接

-- 一张表拆成两张表
SELECT A.`categoryname` AS 父,  B.`categoryname` ASFROM `category` AS A, `category` AS B
WHERE B.pid = A.`categoryid`

子查询

SELECT a.`studentno`,`studentname`,r.`studentresult`
FROM student AS a
INNER JOIN result AS r  
ON a.`studentno` = r.`studentno`
WHERE r.`studentresult` > 50 AND `subjectno` = (
    SELECT `subjectno` FROM `subject` WHERE `subjectname` = '高等数学 -2');

聚合函数

-- count 函数
/*
    列名为主键,count(列名) 比 count(1) 快,不为主键则相反
    多列且无主键,count(1) 效率优于 count(*)
    有主键,count(主键) 最优
    只有一列,count(*) 最优
*/
-- 忽略字段的所有 null 值
SELECT COUNT(`birthday`) FROM `student1`
-- 不忽略 null 值
SELECT COUNT(*) FROM `student1`
SELECT COUNT(1) FROM `student1`
​
-- SUM, AVG, MAX, MIN

select

select [all | distinct]
{* | table.* | [table.field1 [as alias1] [,table.field2 [as alias2]] [,...]]}
from table_name [as table_alias]
    [left | right | inner join table_name2 on 等值判断]  -- 联合查询
    [where ...]  -- 具体的值 或者 子查询
    [group by ...]  -- 通过某个字段分组
    [having ...]    -- 过滤分组信息,条件和where一样
    [order by ...]  -- 通过某个字段排序,升序or降序
    [limit startIndex, pagesize]  -- 显示从哪到哪的查询记录

事务

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

事务原则 ACID:

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

一致性:事务前后的数据完整性保持一致

持久性:事务一旦提交则不可逆,被持久化到数据库中

隔离性:事务互不干扰,相互隔离

隔离级别:

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

不可重复读:某个事务读取数据时,多次结果不一样,场合不对(修改)

虚读(幻读):某个事务读取数据时,别的事务插入一行,前后读取不一致(插入)

-- 关闭自动提交
SET autocommit = 0;
-- 事务开启
START TRANSACTION;
UPDATE act SET money = money - 500 WHERE `name`='a';
UPDATE act SET money = money + 500 WHERE `name`='b';
-- 提交,持久化
COMMIT;
-- 回滚
ROLLBACK;
-- 事务结束,开启自动提交
SET autocommit = 1;

索引

主键索引 primary key:唯一标识、主键不可重复

唯一索引 unique key:避免重复的列出现,多个列可标识为唯一索引

常规索引 key / index:index 或 key 关键字定义索引

全文索引 fulltext : 引擎支持

alter table table1 add key / index 索引名 (列名)

create key / index 索引名 on table(列名)

索引加在常用来查询的字段上,默认 Btree

-- 导出数据库的表
mysqldump -hlocalhost -uroot -p123456 school grade >D://a.sql
-- 登录,导入数据库的表
source D://a.sql

范式

第一范式:无重复的列 (原子性)

第二范式:属性完全依赖于主键,消除部分子函数依赖(完全依赖,非部分依赖)只描述一件事情

第三范式:属性不依赖于其他非主属性,消除传递依赖(直接依赖,非间接依赖)

规范性 和 性能 不可兼得

JDBC

JDBC 是 Java 数据库操作规范,java 安装数据库驱动,来操作数据库

import java.sql.*;
​
public class jdbc1 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1. 加载驱动
        Class.forName("com.mysql.jdbc.Driver");
        
        // 2. 新建 url 和 用户登录信息
        // 协议:// 主机地址: 端口号 / 数据库名? 参数 1& 参数 2& 参数 3
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&usessl=true";
        String name = "root";
        String pwd = "wang";
​
        // 3. 建立连接,数据库对象
        Connection connection = DriverManager.getConnection(url, name, pwd);
        // 4. 新建执行 sql 的对象
        Statement statement = connection.createStatement();
        // 5.sql 语句,执行并返回结果集
        String sql = "select * from users";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            System.out.println(resultSet.getInt("id"));
            System.out.println(resultSet.getObject("NAME"));
            System.out.println(resultSet.getObject("PASSWORD"));
        }
        // 6. 释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

增、删、改均用 statement.executeUpdate(),查找用 statement.executeQuery();

prepareStatement 可防止 mysql 注入问题,把传进来的参数当作字符来处理

// prepareStatement
String sql1 = "insert into users(id, `NAME`, `PASSWORD`, `email`,`birthday`) values (?,?,?,?,?)";
// 预编译 sql
PreparedStatement preparedStatement = connection.prepareStatement(sql1);
// 再设置参数
preparedStatement.setInt(1, 4);
preparedStatement.setString(2, "zhaoliu");
preparedStatement.setString(3, "123456");
preparedStatement.setString(4, "88888@qq.com");
preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));
int i = preparedStatement.executeUpdate();
if(i > 0) {
    System.out.println("插入成功!");
}

Java 中 处理事务,只需要前期 关闭自动提交,后期会自动恢复

Connection connection = DriverManager.getConnection(url, name, pwd);
// 关闭自动提交,开启事务
connection.setAutoCommit(false);
String sql1 = "update act set money = money - 50 where `name` ='a'";
String sql2 = "update act set money = money + 50 where `name` ='b'";
PreparedStatement ps1 = connection.prepareStatement(sql1);
PreparedStatement ps2 = connection.prepareStatement(sql2);
ps1.executeUpdate();
ps2.executeUpdate();
// 事务提交,事后会自动恢复 自动提交
connection.commit();
// 关闭资源,事务失败的话默认也会回滚
ps2.close();
ps1.close();
connection.close();

数据库连接池

编写连接池,实现 DataSource 接口,getConnection 方法不会变

设置最小连接数、最大连接数、等待超时 100ms

连接池:准备一些预先的资源,等待连接,如 DBCP、C3P0、Druid