文章目录

  • 前言
  • 一、MySQL
  • 1、概述
  • 1)数据类型
  • 2)约束
  • 3)常用命令
  • 2、SQL语言(结构化查询语言)
  • 1)DML语句(数据操作)
  • 2)DQL语句(数据查询)
  • 1、单表查询
  • 2、多表查询
  • 3、连接子查询(对于分组后的数据再处理,因为分组后where已经执行)
  • 4、执行顺序
  • 5、数据处理函数/单行处理函数
  • 3)DDL语句(数据定义)
  • 增加字段
  • ②修改+增加约束
  • ③删除约束,表
  • 4)TCL语句(事务控制)
  • 5)TML语句(事务操作)
  • 3、存储引擎
  • 1)查看引擎:
  • 2)常见存储引擎:
  • 4、事务和锁
  • 1)事务
  • 2)锁
  • 5、索引和视图
  • 1)索引
  • 2)视图
  • 6、存储过程
  • 7、设计三范式
  • 8、逻辑运算
  • 9、常用函数
  • 二、JDBC
  • 1、概述
  • 2、连接步骤
  • 1)步骤解读
  • 2)代码实现
  • 3、封装和结构优化
  • 1)使用PreparedStatement
  • 2)工具类封装
  • 4、事务和SQL注入
  • 1)转账模拟事务
  • 2)用户登录
  • 三、`MySQL进阶`
  • 1、SQL优化
  • 2、分库分表
  • 3、存储过程
  • 4、常用函数
  • 1、时间函数
  • 总结


前言

数据库(DataBaseManagement /DBMS)是一种数据库管理系统,常见的数据库有oracle,sqlserver,mysql,DB2,数据库管理系统(DBMS)–>执行SQL–>操作数据库(磁盘文件),数据库中最基本的单元就是表,表是用来存储数据的(一个表对应一个文件)

一、MySQL

1、概述

1)数据类型

①int/Integer,整型,长度并不是指数字的长度

②varchar/char:char是存储的字符串固定长度,varchar是根据我们输入的字符串动态确定存储字符串的长度。存储时不能超出设定的长度

③float/double,浮点型数据,存储小数,可以设置长度和保留的小数位数,插入时自动保留小数位数但是小数点前面的和固定小数位数不能超过总长度,eg:insert into floatdouble values (1.223456,2.454656);,保存后的数据1.223,2.45.

④date/time/datetime:日期/时间/日期+时间,不用设置长度

spark Column判断isNaN_jdbc


⑤decimal(位数,小数点位数):存储精准的数值,对于金额等一些数据要求准确数据的

2)约束

①NOT NULL非空约束:插入的字段内容不能为空
②UNIQUE唯一约束:插入的内容不能重复
③primarykey(pk)主键约束:NOT NULL+UNIQUE
④foreignkey(fk)外键约束:从表中的字段内容来自于主表中的字段内容,删除带有外键的字段,必须先删除从表中的字段

3)常用命令

1、登录 mysql -u 用户名 -p 密码
2、查看数据库/表:show databases/tables;
3、使用数据库use:指定表名
4、查看建表语句:show create table 表名
5、表名//展示详细的表结构:show full columns from 表名

2、SQL语言(结构化查询语言)

1)DML语句(数据操作)

①插入数据insert:
格式:insert into 表名 (字段名,字段名,字段名) values(,)
②修改数据update:
格式:update 表名 set 字段名 = 值 , set 字段名 = 值
③删除值delete,truncate:
可恢复:delete from 表名 where 条件
不可恢复:truncate table 表名

2)DQL语句(数据查询)

1、单表查询

①条件查询where
(非)等值查询:=,!=,is null
模糊查询:like ,%表示任意个字符,_表示一个字符
区间查询:between a and b
范围查询:in(可以实际具体的值,也可以是另一个sql语句返回的结果)
②分组:group by 字段名,只有分组之后才能使用分组函数(count,max,min,avg,sum),having设置一定的判断条件,所以where无法使用,
③排序:order by
asc 升序(默认就是)
desc 降序
级联排序,order by 字段 排序,字段 排序

④分页:limit start,end

2、多表查询

①笛卡尔积(全连接):全连接,两个表记录条数的乘积
②外连接:表名 (outer) join 表名 on 连接条件
③内连接:主/从表名 left/right (inner) join 从/主表名 on 连接条件,
主表中的数据总是能够输出
④自连接:自己连接自己,需要设置表的别名

多个表的查询,连接条件从后往前,也可以一个一个表进行连接

3、连接子查询(对于分组后的数据再处理,因为分组后where已经执行)

将我们的查询作为一张新的表的在进行查询处理
eg:获取根据根据字段分类后再连接其他表,查询每门课程的最高分以及课程的详细信息。
select cno,sum(ifnull(grade,0)) from sc group by cno;

4、执行顺序

执行顺序:from (join…on),where,groupby having,select,orderby,limit

5、数据处理函数/单行处理函数

截取字符串:substr(字段,start,length)
去除前后空白:trim(字段)
随机数:rand(),0-1,用于获取随机数据
大小写:lower/upper(字段)
处理NULL:ifnull(字段,具体的值)
<四舍五入保留小数:round(小数,位数),0表示保留整数,-1表示保留个位数/font>

3)DDL语句(数据定义)

新建表:create table gg(next int(1) not null);
以下操作均需加上 alter table 表名

增加字段

add column 字段名 数据类型(长度,小数点) 约束;

②修改+增加约束

modify:新增约束和修改表的数据类型
格式:modify 字段名 修改的数据类型(长度) 新增的约束(not null,null,unique,primary key)
eg:alter table gg change next pre int;

change:修改表名和数据类型
格式:change 字段名 修改名 数据类型(长度)

③删除约束,表

删除表:drop table 表名
删除约束:
删除主键:drop primary key;
删除唯一约束 drop index 字段名
删除外键:drop foreign key 外键名

4)TCL语句(事务控制)

5)TML语句(事务操作)

3、存储引擎

这个名字只在MySQL中有,(Oracle也有这个机制,只是不一样罢了)。

1)查看引擎:

show  engines \G;
         mysql 5.5.36版本支持的的存储引擎有9个

2)常见存储引擎:

Ⅰ、myisam(读法:my i z meng):
            ①使用三个文件存储表:frm存储表结构,.MYD存储表据,.MYI存储索引。
            ②可以被压缩(节约内存空间),可以转化为只读表(提高检索效率????)。
            ③不支持事务(tcl);
       Ⅱ、InnoDB
            ①支持事务(tcl),外键,行级锁,数据安全;
            ②.frm文件存储表结构,tablespace(表空间,是一个虚拟的空间,逻辑概念)存储表数据
            ③级联删除(允许直接删除外键的父表的记录,并且引用这个的字段的记录也一并删除。如果直接删除字段那就更狠了)。
            ④级联更新(更改父表中字段的数据,子表的数据也一并更新。)。怎么做到。
            FOREIGN KEY (sid) REFERENCES stu(sid) ON DELETE CASCADE ON UPDATE CASCADE)
       Ⅲ、memory
            ①数据存储在内存中
            ②存储速度极快,不支持事务
            ③无法及时持久化数据,如果突然断电,无法保存数据

4、事务和锁

1)事务

①特征:隔离性,原子性,持久性,一致性
隔离性:事务与事务之间具有隔离性
原子性:事务是最小的执行单元
持久性:可以将最终的数据保存到本地磁盘中
一致性:内部的多条DML语句同时失败或者同时成功
②隔离级别
1、读未提交(read uncommited)
一个事务能读取到另一个事务未提交的事务,存在脏读现象,读取的数据可能是没用的。
2、读已提交(read commited)
一个事务可以读取已经提交的事务的内容,不能重复读:在当前事务读取到的数据可能每次都不一样。因为事务在不断提交。
3、可重复读(read repeated):默认隔离级别
可以重复读取,但是读取是开启事务前数据库的一个副本,存在幻读现象
4、序列化读(serializable read)
事务排队执行, 效率低,安全
③修改隔离级别
设置隔离级别:set global transaction isolation level serializable;
查看事务的全局隔离级别;select @@global.tx_isolation;

2)锁

①悲观锁
1、悲观锁:
认为在任何时候数据都有可能出错,当我们操作一条数据时,就会为这个信息加上一把锁(select …for update)

共享锁:多个事务可以共享这把锁,但是只能读不能写

排他锁:一旦一个事务得到了锁(可以读和写),其他事务就无法或得锁,也就是无法进行操作。

,然后其他的所有的对这条记录的写操作都不会被执行(要确定该字段具有索引,不然全局扫描的改表中的所有数据都会加锁,)

②乐观锁
认为只有在写操作时才可能出现数据异常,不依赖mysql的锁,通常是自己利添加一个版本号字段实现,修改数据时先查询版本号,然后判断版本号是否来确定是否修改数据,所以在事务提交的时候会检查当前写的字段是否别修改(通过一个版本号,其他事务如果修改了,那么版本号+1),如果修改了(版本号不同),不会更新,返回提示信息(update table set version=version+1,amout=spark Column判断isNaN_spark Column判断isNaN_02{version})

5、索引和视图

1)索引

①索引分类:唯一索引,主键索引,单一索引,复合索引(多个字段)

②添加索引:create index 索引名 on 数据库名(字段名)

③删除索引:drop index 索引名

④实现原理:

不同存储引擎,索引存在形式不一样,在InnoDb中存在tablespace中,在MyIsam中,存在.MYI文件中。

每一条存储在磁盘上的数据库记录都有一个物理存储编号

在查找的字段如果有索引,那么会利用这个索引对象(树的结构存储字段信息)查找到与其相等的字段,返回这个字段的物理存储编号,然后获取这一条记录信息。利用B+树的数据结构,极大的减小了查找范围,提高了效率

⑤索引失效:在查询语句前面explain可以查看查询语句扫描的记录条数和方法。

以%开头的模糊查询:

explain select * from testindex where name like ‘%son’;

or条件查询,需要相关的两个字段都需要索引,才可以

explain select * from testindex where NAME = ‘jackson’ or age = 1

在where条件中索引字段参与运算/使用函数:

explain select name from testindex where substr(name,0,2) = ‘jackson’

spark Column判断isNaN_java_03

2)视图

①、创建和删除:
创建:create view 视图名 as select …
删除:drop view 视图名
②、使用:对视图的CRUD操作可以影响到原表,视图只能对应DQL语(数据查询语言)
③、作用:对于复杂并且多次使用SQL语句,我们可以将这条sql语句以视图对象的形式新建,直接使用试图对象代替SQL语句。

6、存储过程

7、设计三范式

①第一范式:每张表都必有一个主键
②第二范式:所有字段都必须依赖主键,不能产生部分依赖(多对多,联合主键)
③第三范式:所有字段都必须直接依赖主键,不能形成间接依赖(一对多,学生依赖教室,教室依赖教室房间号)

8、逻辑运算

1、case 字段 when 值 then 结果 else 其他情况 end

select (case when  age > 9999then '老小孩' else '屁小孩'  end) as age,name from crud_test;

9、常用函数

二、JDBC

1、概述

JDBC(java database collection)是java连接数据库的一套接口,只需要调用接口的方法就能操作数据库,无论是哪种数据库,都是实现了接口方法,面向接口编程。需要下载与数据库版本匹配的jar包(5.0+,8.0+)

2、连接步骤

1)步骤解读

①注册驱动(Class.forName):明确连接的是哪一个数据库操作系统。
②获取连接(getConnection):表示JVM的进程和数据库的进程之间的的通道打开了,进程之间的通信,使用完后需要关闭通道。(两个完全不同的进程的通信哦)
③获取数据库操作对象(PreparedStatement):获取数据库操作对象(专门执行sql语句的对象)
④执行sql语句(executeQuery/executeUpdate):执行sql语句(主要是DML和DQL语句);
⑤处理查询结果集 (ResultSet/int) :只有是查询语句时,才可以进行操作。
⑥释放资源(close):使用完资源后,一定要关闭资源。java和数据库之间是进程之间的通信。开启之后一定要关闭。

2)代码实现

将数据库的配置文件放在类路径下,这样可以在不改变源码的情况下,改变数据源。不同mysql版本对应的链接url不一样,
url:jdbc:mysql://192.168.31.78:3306/company?useSSL=false&serverTimezone=UTC

public class jdbc_test_process{
           public static void main(String []args){
                  Connection conn=null;
                  Statement stmt=null;
                  try{
                          //Driver driver=new com.mysql.jdbc.Driver();
                          ResourceBundle bundle =ResourceBundle.getBundle("jdbc");//
                          String driver=bundle.getString("driver");
                          String url=bundle.getString("url");
                          String user=bundle.getString("user");
                          String password=bundle.getString("password");
                          System.out.println(driver);
                          System.out.println(url);
                          System.out.println(user);
                          System.out.println(password);
                          Class.forName(driver);//Class.forName()会导致类加载,而在Driver静态方法中,创建了驱动对象
                          conn=DriverManager.getConnection(url,user,password);//获取连接
                          stmt=conn.createStatement();//获取操作对象
                          bundle=bundle.getBundle("SQL");
                          String sql=bundle.getString("DQL");
                          //String sql="delete from dept where deptno=100";
                          int count=stmt.executeUpdate(sql);//返回查结果集或者影响的记录条数

                          String select=bundle.getString("DML");
                          ResultSet rs=stmt.executeQuery(select);
                          while(rs.next()){
                                int empno = rs.getInt("empno");
                                String ename = rs.getString("ename");
                                double sal = rs.getDouble("sal");
                                System.out.printf(empno+"\t");
                                System.out.printf(ename+"\t");
                                System.out.printf(sal+"\t");
                                System.out.println();
                          }
                          System.out.println((count==1)?"True":"Flase");
                  }catch(SQLException e){
                          e.printStackTrace();
                  }catch(ClassNotFoundException e){
                          e.printStackTrace();
                  }finally{
                            try{
                                    if(stmt!=null)
                                        stmt.close();
                            }catch(SQLException e){
                                   e.printStackTrace();
                            }
                            try{
                                    if(conn!=null)
                                        conn.close();
                            }catch(SQLException e){
                                    e.printStackTrace();
                            }
                  }
           }
}

3、封装和结构优化

使用PreparedStatement操作数据库,使用占位符?,一个?代表一个具体的值,获取对象就设置执行的SQL语句,让数据库预编译,下次执行相同语句的时候,可以不用再次编译,直接运行,提高了效率,而且可以防止SQL注入问题。
通过PreparedStatement.setInt/Double/String(int index,int/double/string)…方法设置?的值

1)使用PreparedStatement

public class Ps {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");//资源绑定器获取类路径下的properties配置文件
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        System.out.println(url);
        //注解驱动
        Class.forName(driver);
        //获取连接对象
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection(url,user,password);
            ps = conn.prepareStatement("select * from dept");
            rs = ps.executeQuery();
            while(rs.next()){//遍历每一行记录
                String name = rs.getString(1);//根据columns下标获取数据
                String no = rs.getString("deptno");//根据column's name获取数据
                System.out.println("no:"+no+","+"name:"+name);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally{
            if(rs!=null) rs.close();
            if(ps!=null) ps.close();
            if(conn!=null) conn.close();
        }
    }
}

2)工具类封装

①封装类

public class DbUtil {
    private  static  String driver;
    private  static  String url;
    private  static  String user;
    private  static  String password;
    private static ResourceBundle bundle;
    static{
        bundle = ResourceBundle.getBundle("jdbc");
        driver = bundle.getString("driver");
        url = bundle.getString("url");
        user = bundle.getString("user");
        password = bundle.getString("password");
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){
        try {
            return DriverManager.getConnection(url,user,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void close(Connection conn, PreparedStatement ps){
        close(conn,ps,null);
    }

    public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
        if(conn!=null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(ps!=null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(rs!=null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

②测试封装类

public class TestUtil {
    public static void main(String[] args) throws SQLException {
        Connection conn = DbUtil.getConnection();//注册驱动,获取连接
        PreparedStatement ps = conn.prepareStatement("select * from emp where ename = ?");//获取操作对象
        ps.setString(1,"clark");//设置属性值
        ResultSet rs = ps.executeQuery();//处理查询结果集
        while(rs.next()){
            String ename = rs.getString("ename");
            double salary = rs.getDouble("sal");
            String  date= new SimpleDateFormat("yyyy-MM-dd").format(rs.getDate("hiredate"));
            System.out.println("ename:"+ename+","+"salary:"+salary+","+"date:"+date);
        }

        DbUtil.close(conn,ps,rs);//关闭连接
    }
}

4、事务和SQL注入

1)转账模拟事务

/**
 * 张三向李四转账12块,
 */
public class TestTransaction {
    public static void main(String[] args) throws SQLException {
        Connection conn = DbUtil.getConnection();//注册驱动,获取连接
        PreparedStatement zs = null;
        PreparedStatement ls = null;
        conn.setAutoCommit(false);//关闭自动提交
        double amount = 12.00;
        try{
            zs = conn.prepareStatement("update trans set money=money-? where `name` = 'zs'");//
           // int a = 1/0;//抛出运行时异常
            ls = conn.prepareStatement("update trans set money=money+? where `name` = 'ls'");//
            zs.setDouble(1,amount);
            ls.setDouble(1,amount);
            zs.executeUpdate();
            ls.executeUpdate();
            System.out.println("交易成功");
            conn.commit();
        }catch(Exception e){
            System.out.println(e.getMessage());
            System.out.println("有内鬼,终止交易");
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally{
            DbUtil.close(conn,zs);//关闭连接
            DbUtil.close(null,ls,null);
        }
    }
}

2)用户登录

selct * from user where user = ${user} and password = ${password}
当用户输入的user值或者password值后面加上 or true时,会出现恶意登录情况,因为statement只是对参数进行字符串拼接,而PreparedStatement使用?占位符表示一个具体的值,mysql提前对语句进行编译,执行时参数所表示只是一个值

三、MySQL进阶

1、SQL优化

1)对于经常查询的字段使用索引

2)select只取需要的数据,拒绝使用*

3)避免索引失效

①在模糊查询的开头使用%,会走全表扫描
②避免使用in/not in,会走全表扫描(如果连续使用between,不连续使用exist子查询)
③避免使用or(使用UNIION)
④尽量避免进行null值的判断:is null,(使用0/1默认值)
⑤尽量避免在where条件中等号的左侧进行表达式、函数操作(在右侧使用)
⑥避免使用where 1=1的条件
⑦查询条件不能用 <> 或者 !=
⑧where条件仅包含复合索引非前置列,MYSQL复合索引使用最左匹配原则
⑨隐式类型转换造成不使用索引,varchar = int
⑩order by 条件要与where中条件一致,否则order by不会利用索引进行排序

4)查询优化

①使用where提交过滤,避免使用having
②group by默认会根据分组的字段排序,如果不需要排序,可以手动声明 order by null
③在select中使用表的别名
④使用临时表

2、分库分表

3、存储过程

4、常用函数

1、时间函数

用来查询指定年月日的数据 ①DATE_FORMAT (datetime ,FormatCodes )
FormatCodes:%Y-%m-%d
②year(date),month(date),day(date),获取日期时间中的年月日,

总结

1、NULL无法参与运算,运算结构都是NULL,统计时是0,也就是不会统计,IFNULL(字段,具体的值)
2、ordery by index,可以根据列名的下标排序(可以是随机小数,随机获取数据)
3、关键字:
not:取反
in:某个集合
distinct 某个字段去重,如过在所有字段的前面,那么是联合去重
union:合并两个查询结果的列,记录条数必须相同,
explain:解释这条语句,可以查看select语句的扫描方式和扫描到的记录条数
4、JDBC:连接步骤,事务,SQL注入,封装类