java开发工程师入门第二阶段(04-mysql数据库)

一.视图View
1.概念

可视化的表,视图当做是一个特殊的表,是指,把sql执行的结果,直接缓存到了视图中。
下次还要发起相同的sql,直接查视图。现在用的少,了解即可.
使用: 1,创建视图 2,使用视图

2.测试
create view 视图名 as  SQL语句;
select * from 视图名;
#视图:就是一个特殊的表,缓存上次的查询结果
#好处是提高了SQL的复用率,坏处是占内存无法被优化
 
#1.创建视图
CREATE VIEW emp_view AS
SELECT * FROM emp WHERE ename LIKE '%a%' #模糊查询,名字里包含a的
#2.使用视图
SELECT * FROM emp_view
二.数据库设计的三范式
1.概述

简言之就是,数据库设计对数据的存储性能,还有开发人员对数据的操作都有莫大的关系。所以建立科学的,规范的的数据库是需要满足一些规范的来优化数据数据存储方式。在关系型数据库中这些规范就可以称为范式,也是作为数据库 设计的一些规则.
关系型数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。范式越高,冗余最低,一般到三范式,再往上,表越多,可能导致查询效率下降。所以有时为了提高运行效率,可以让数据冗余.

2.分类

1NF的定义为:符合1NF的关系中的每个属性都不可再分

2NF在1NF的基础之上,消除了非主属性对于码的部分函数依赖,也就是说,表里的每个字段都要依赖于主键

3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖

3.总结

​ 三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求>性能>表结构。所以不能一味的去追求范式建立数据库。

三.SQL优化
  • 查询SQL尽量不要使用select *,而是具体字段
  • 避免在where子句中使用or来连接条件
  • 使用varchar代替char
  • 尽量使用数值替代字符串类型
  • 创建name字段的索引
  • 索引不宜太多,一般5个以内
  • 索引不适合建在有大量重复数据的字段上
  • 避免在where子句中使用!=或<>操作符
  • 批量插入性能提升
  • 复合索引最左特性
  • 不要有超过5个以上的表连接
  • inner join 、left join、right join,优先使用inner join
四:JDBC
1.概念

我们学习了数据库,数据库实现了数据的持久化,但我们最终要在程序里处理数据啊,那java代码中怎么去访问数据库读写数据呢?

这就要用到sun公司设定的一套数据库标准了,这套标准就是JDBC(Java Database Connectivity)。但它只是规范,不做具体实现。于是数据库厂商又根据JDBC标准,实现自家的驱动Driver。如:mysql驱动com.mysql.cj.jdbc.Driver,Oracle的驱动oracle.jdbc.OracleDriver。有了这套解决方案,java就可以访问数据库中的数据了。

Java中提倡面向接口开发,而最经典的接口设计莫过于JDBC数据库接口。

2.使用步骤

导入jar包(丰富的工具类)

获取和数据库的连接(用户名、密码)

通过程序执行SQL

通过程序处理结果

3.idea 创建项目并导入jar包
  • 创建stage2 Java工程
  • 创建lib目录,拷贝驱动objbc6-11.1.0.7.0到lib目录下
  • 项目引用这个外部jar包
4.案例
package cn.tedu.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//利用jdbc,操作数据库
//需求,查询部门表的所有数据
public class Test1 {
    public static void main(String[] args) throws Exception {
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取数据库的连接
        /*String url="协议://数据库的服务器的IP地址:端口号/数据库名*/
        String url= "jdbc:mysql://localhost:3306/cgb211101";
        Connection c = DriverManager.getConnection(url,"root","root");
        //3.获取传输器
        Statement s = c.createStatement();
        //4.执行SQL
        ResultSet r = s.executeQuery("select * from dept");//执行查询的SQL
        System.out.println("java程序与数据库连接成功!!!");
        //5.处理结果--遍历结果
        //next()从来判断,只要r里有数据就返回true,没有数据就返回false
        while (r.next()){
            //获取数据getXxx()
            int d1= r.getInt(1);//获取第一列的一个整数值
            String d2= r.getString(2);//获取第二列的一个整数值
            String d3= r.getString(3);//列的一个整数值
            System.out.println(d1+d2+d3);
        }
        //6.关闭资源
        r.close();//关闭结果集ResultSet
        s.close();//关闭传输器Statement
        c.close();//关闭连接Connection
    }
}
5.SQL攻击注入
/*自己准备user2表(id/name/password),准备数据
    CREATE TABLE `user2` (
          `id` int(11)  PRIMARY KEY  auto_increment,
          `name` varchar(10) default NULL,
          `password` varchar(10) default NULL
    ) ;
 */
//需求:利用jdbc,根据用户名和密码查询cgb2104库里的user表
//SQL注入攻击问题
private static void login() {
    try{
        Class.forName("com.mysql.jdbc.Driver");
        String url="jdbc:mysql:///cgb2104?characterEncoding=utf8";
        Connection conn = DriverManager.getConnection(url, "root", "root");
        Statement st = conn.createStatement();
// String sql ="select * from user2 where name='jack' and password='123456'";//写死了

        String user = new Scanner(System.in).nextLine();//用户输入jack'#
        String pwd = new Scanner(System.in).nextLine();
        //SQL注入攻击问题:本质上是因为SQL语句中出现了特殊符号#,改变了SQL语义
String sql ="select * from user2 where name='"+user+"' and password='"+pwd+"'";
        ResultSet rs = st.executeQuery(sql);//执行查询的SQL,返回结果集
        if(rs.next()){
            System.out.println("登录成功~");
        }else{
            System.out.println("登录失败~");
        }
        st.close();
        conn.close();
    }catch(Exception e){
        e.printStackTrace();//有异常,直接打印异常信息
        //System.out.println("执行失败。。。");//上线
    }
}
6.SQL注入的解决方案
package cn.tedu.jdbc;
import java.sql.*;
import java.util.Scanner;
public class Test7 {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url= "jdbc:mysql://localhost:3306/cgb211101";
        Connection c = DriverManager.getConnection(url,"root","root");
        System.out.println("请您输入账号:");
        String s1 = new Scanner(System.in).nextLine();
        System.out.println("请您输入密码:");
        String s2 = new Scanner(System.in).nextLine();

        //Statement s = c.createStatement();
        //String sql="select * from user where name='"+s1+"' and pwd='"+s2+"'";
        //动态拼接SQL语句
        //新的传输器,执行的SQL有新写法--sql骨架
        String sql= "select * from user where name=? and pwd=?";
        //获取新的传输器--安全/高效
        PreparedStatement s = c.prepareStatement(sql);
        s.setString(1,s1);//给第一个问号?,设置s1的值
        s.setString(2,s2);//给第二个问号?,设置s2的值
        ResultSet r = s.executeQuery();
        //处理结果集(根据用户名和密码去查,只会查出来一条记录)
        if (r.next()){//如果查到了数据,才表示数据库里面有这个用户信息
            System.out.println("登录成功");
        }else {//如果没有查到数据信息
            System.out.println("请重新输入...");
        }
        //释放资源
        r.close();
        s.close();
        c.close();
        //问题:当用户输入特殊值:小张'#时,,甚至不需要密码也能登录
        //原因:#在SQL中表示注释的意思,相当于后面的条件被注释掉了
        //select * from user where name='jack'#' and pad='123456'
        //现象叫SQL攻击/SQL注入,本质上就是因为SQL语句中出现了特殊符号#
        //导致了.SQL语义发生改变
        //createStatement传输器不安全,低效,改为prepareStatement:把特殊符号当做普通的文本符号在使用,没有注释的意思了
    }
}
7.优化: 提供jdbc的工具类
package cn.tedu.jdbc;

import java.sql.*;

//充当了jdbc的工具类,抽取一些共性代码
public class JDBCUtils {
    /**
     * 释放资源
     * @param r 结果集
     * @param s 传输器
     * @param c 连接器
     */
    static public void close(ResultSet r, PreparedStatement s,Connection c){
        if(r != null){//防止了空指针异常
            try {
                r.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {//就是怕close()执行失败导致发生了异常,进行了catch
                r = null;//手动置空,等着GC进行垃圾回收
            }
        }
        if(s != null) {//防止空指针异常
            try {
                s.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {//就是怕close()执行失败导致发生了异常,进行了catch
                s = null;//手动置空,等着GC进行垃圾回收
            }
        }
        if(c != null) {//防止空指针异常
            try {
                c.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally {//就是怕close()执行失败导致发生了异常,进行了catch
                c = null;//手动置空,等着GC进行垃圾回收
            }
        }
    }
    /**
     * 获取数据库的连接
     * @return 将给调用者返回一个和数据库连接的对象Connection
     * @throws Exception
     * static:保证资源在内存中,贮存的时间长.只会加载一次节省内存
     * public:工具类可以被所有人使用,最大的访问权限方便调用来调用
     */
    static public Connection get() throws Exception{
        //1,注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2,获取连接
        String url="jdbc:mysql://localhost:3306/cgb211101?characterEncoding=utf8";
        Connection c = DriverManager.getConnection(url, "root", "root");
        //把获取到的数据库的连接,返回给调用者
        return c;
    }
}
8.使用工具类(用新的传输器新增)
package cn.tedu.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

//利用新的传输器结合着工具类,新增一个用户信息
public class Test6 {
    public static void main(String[] args) {
       //扩大变量的作用范围:为了让try  catch  finally都能用
       Connection c = null;
       PreparedStatement p = null;
       try {
            //1,利用工具类,来获取数据库的连接
            c = JDBCUtils.get();
            //2,获取传输器,执行SQL
            String sql="insert into user values(null,?,?)";
            p = c.prepareStatement(sql);
            //给SQL绑定参数
            p.setObject(1,"jerry");
            p.setObject(2,"123");
            //3,执行SQL
            p.executeUpdate();//执行增删改的SQL,返回一个影响行数(通常不处理)
       }catch (Exception e){
           System.out.println("数据插入失败!!");
       }finally {//保证一定会被执行的代码
           //利用工具类close完成释放资源(新增业务,没有结果集,传入null就可以了)
           JDBCUtils.close(null,p,c);
       }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值