数据库学习笔记(四)—— JDBC基础 + Dao-entity


前言

🦁	entity+Dao  模型——非常重要
Dao——表名Dao——对某一个表进行增删改查操作——之后会简化为接口
entity——与数据库中的实体表对应(表名、属性、方法)

🐅IDEA自带Database

JDBC基础

(1) JDBC原理

  • JDBC(Java Database Connectivity):Java连接数据库的技术。所有Java程序都需要用到JDBC,主流框架对JDBC进行了封装,实际上底层一定用到了JDBC。
    JDBC API主要位于JDK中的java.sql包中,之后扩展的内容位于javax.sql包中。(x代表拓展,原生+拓展时JDBC的所有内容)

  • JDBC处于Java Application(Java应用程序) 与 各个(数据库)Oracle、MySQL、SQL Server之间,即JDBC API + JDBC Driver Manager+ Oracle JDBC Driver(驱动程序) ……

    其中驱动程序由不同数据库的厂商自己根据JDBC的规范开发的 —— ∈ 面向接口编程
    JDBC Driver Manager 定义规范标准,生产不同的驱动时不确定将连接什么数据库 —— 反射机制
    在这里插入图片描述

(2) JDBC 在IDEA配置

  1. mysql 5.7 用8.0版本的驱动可以,5.1版本也可以,5.5、5.6、5.7都不可以。
    这里我的MySQL5.7,JDBC5.1.38。
    打开IDEA ,新建项目,在项目下新建文件夹lib(lib文件夹通常用于存放.jar包)将下载好的JDBC复制,paste到lib文件夹下。
    在这里插入图片描述
    (External Libraries中存放的是项目已经引用的,此时该项目中只引用由jdk13.——版本或项目不同不一样)

  2. 将JDBC引用入项目
    右键复制进lib内的文件,选择Add as Library
    在这里插入图片描述
    将jar放入改项目,可以选择放入哪里(全局、该项目、模块)
    在这里插入图片描述
    => 成功后可以打开
    在这里插入图片描述

  3. 补全
    当做好Java应用程序、数据库表、完成JDBC Driver引用,则只需要补全 JDBC API和JDBC Driver Marager即成功连接应用程序和数据库。

4. 其余部分

①Java应用程序
② 数据库
在这里插入图片描述
在这里插入图片描述

(3)预编译

1. SQL注入

JDBC代码中的查询练习改成如下代码:

List<Student> studentList = studentDao.query("' or 1=1 or '");

可以发现sql语句和查询结果为下图所示:
在这里插入图片描述
因为JDBC查询使用拼接字符串的形式组织sql语句,这样当用户的名字为’ or 1=1 or '时,组成恒成立的sql语句,就可以查询出所有信息。这就是SQL注入,使用预编译可以避免。

2.预编译概念

在这里插入图片描述 ① 预编译的原理——先将sql语句模板发送给数据库进行编译成函数,然后再将数据当参数传递给数据库,这样数据中的关键字如or 1=1就不会被理解为sql语句的一部分,就避免了SQL注入。

② 预编译的优点——使用预编译还可以提高sql的执行效率。相同的sql语句在数据库只会编译一次。但是可以多次调用执行。

  • Statement —— 字符串拼接完成SQL语句,不安全
  • PreparedStatement 是 Statement 的一个子类。
  • 预编译 先编译,后传入参数
3 .预编译的使用
1. 使用PreparedStatement替代Statement。参数使用?占位符。 2. 创建PreparedStatement对象时将sql语句发送到数据库。 3. 使用setter方法为参数赋值。
  • 核心代码:
preparedStatement = conn.prepareStatement("insert into student (stu_name, stu_age) values (?,?)");
preparedStatement.setString(1,"david");
preparedStatement.setInt(2,20);
ret = preparedStatement.executeUpdate();

1>preparedStatement = conn.prepareStatement(“insert into student (stu_name, stu_age) values (?,?)”);
= > conn先执行prepareStatement,把SQL语句insert into student (stu_name, stu_age) values (?,?) 发送到服务器preparedStatement

2> preparedStatement.setString(1,“david”);
preparedStatement.setInt(2,20);
= > 设置两个值

3>ret = preparedStatement.executeUpdate();
= > 调用executeUpdate()时,把值发送到数据库中
此时把SQL语句发送到数据库,数据库对SQL语句进行预编译。遇到?时,将这里看作方法的参数,把值中的参数(1、2)替换到?处运行。

注意:在给参数赋值的时候,下标是从1开始。

(4)JDBC连接数据库的六个步骤

1.步骤内容

在这里插入图片描述

  1. 注册驱动 (仅仅做一次)
  2. 建立连接(Connection)
  3. 创建运行SQL的语句(Statement)
  4. 运行语句
  5. 处理运行结果(ResultSet)
  6. 释放资源

Statement可以是DML、DQL。 当Statement是DML时,返回影响条数;当Statement是DQL时,返回ResultSet。 ResultSet依存于connection连接。
当connection连接关闭后,Statement与ResultSet都要被销毁。临时变量
所以当取得ResultSet不可以直接被使用,需要转存到ArrayList中。

2. ❤ 操作 ❤ 👶
1>. 注册驱动 (仅仅做一次)

反射

try {
    //注册驱动 (仅仅做一次)
    Class.forName(driver);//  **反射**     
    } catch (ClassNotFoundException e) {
            e.printStackTrace();
         }
2>. 建立连接(Connection)


在这里插入图片描述
高版本需要在url后加参数,没有参数时间、文本会出现问题(时间不正确、乱码…)

        String driver ="";//不同数据库、相同数据库不同版本的driver不同
        String url="";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="";//自己数据库的密码

        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            Connection connection=DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
            
        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

——连接数据库Scott用户

3>. 创建运行S QL的语句(Statement)
4>. 运行语句

        String driver ="";//不同数据库、相同数据库不同版本的driver不同
        String url="";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="123456";//自己数据库的密码

        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            Connection connection=DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
            //创建运行SQL的语句(Statement)
            PreparedStatement statement=connection.prepareStatement("insert into student (student_name,student_no,sex) values(?,?,?)");
            statement.setObject(1 ,"king");
            statement.setObject(2 ,"2022228");
            statement.setObject(3 ,"男");

            //运行语句
            int ret = statement.executeUpdate();
    
            
        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();

注意:
executeQuary——DQL查询操作,返回结果集resultSet ;executeUpdate—— DML增删改,返回resultInt,影响条数

5>. 处理运行结果(ResultSet)
注意: 处理运行结果(ResultSet)——只有查询操作时有,进行增删改操作时没有这一步
6>. 释放资源

①需要关闭的资源:connection、statement、(resultset)
在这里插入图片描述
②在try catch中不适宜关闭,应finally中关闭资源。
因为connection、statement的作用范围为: 蓝色区域
在这里插入图片描述
无法在范围外的区域关闭。
更改作用范围:
在这里插入图片描述

③ 释放

   ……
  }finally {
            //释放资源 (connection、statement、resultset)
            try {  
            //对象不存在关不上,需要加try/catch
                connection.close();  //?
                statement.close();
            }catch (SQLException throwables){
                throwables.printStackTrace();
            }

        }
细节修改

细节修改
① 多重catch最后一定要加一个父类
② 返回结果return
int ret=-1;
因为0和1为正常的返回结果

结果
import java.sql.*;

public class Text {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        String driver ="com.mysql.jdbc.Driver";
                //不同数据库、相同数据库不同版本的driver不同
        String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="123456";//自己数据库的密码

        Connection connection = null;
        PreparedStatement statement = null;
        int ret=-1;
        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection=DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("insert into student (student_name,student_no,sex) values(?,?,?)");
            statement.setObject(1 ,"king");
            statement.setObject(2 ,"2022228");
            statement.setObject(3 ,"男");

            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步

        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (Exception e) {  //多重catch最后一定要加一个父类
            e.printStackTrace();
        }finally {
            //释放资源 (connection、statement、resultset)
            try {//对象不存在关不上,需要加try/catch
                connection.close();
                statement.close();
            }catch (SQLException throwables){
                throwables.printStackTrace();
            }

        }
        return ret;
    }
}


在这里插入图片描述
在这里插入图片描述

补充

可能出现字符乱码的情况,如图
在这里插入图片描述
在这里插入图片描述

3. 📕 Dao+entity📕 🧑
1>.package 构建。包括插入、删除、修改以及查询方法

在这里插入图片描述

1>>插入🚩
public int insert(){//插入方法
        String driver ="com.mysql.jdbc.Driver";
        //不同数据库、相同数据库不同版本的driver不同
        String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="123456";//自己数据库的密码

        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection= DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("insert into student (student_name,student_no,sex) values(?,?,?)");
            statement.setObject(1 ,"lily");
            statement.setObject(2 ,"202205");
            statement.setObject(3 ,"女");
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            //释放资源 (connection、statement、resultset)
            try {//对象不存在关不上,需要加try/catch
                connection.close();
                statement.close();
            }catch (SQLException throwables){
                throwables.printStackTrace();
            }
        }
        return ret;
    }

2>>修改

public int update(){ //修改方法
        String driver ="com.mysql.jdbc.Driver";
        //不同数据库、相同数据库不同版本的driver不同
        String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="123456";//自己数据库的密码

        Connection connection = null;
        PreparedStatement statement = null;
        int ret =-1;
        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection= DriverManager.getConnection (url,name,pass);//建立连接需要四个参数
            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("update student set address = ? where id = ?");
            statement.setObject(1 ,"北京市");
            statement.setObject(2 ,"4");
            //运行语句
            ret = statement.executeUpdate();
            System.out.println(ret);
            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            //释放资源 (connection、statement、resultset)
            try {//对象不存在关不上,需要加try/catch
                connection.close();
                statement.close();
            }catch (SQLException throwables){
                throwables.printStackTrace();
            }
        }
        return ret;

    }

3>>删除 略

4>> 查询🚩
  • 存放空间
    ① 查询的返回值类型为 List 结果集,存放着一个模型
    在这里插入图片描述
    entiey(类——实体 属性——列 类与类之间的关系——实体之间的关系 对应)
    生成表和对应的getter&setter方法(与数据库中一一对应)
    在这里插入图片描述
    toString()方法重写,打印数据而不是内存地址
    在这里插入图片描述
    【见测试调用部分】

② 封装数据

  • 查询代码
    ① column label——列名;column index——列的下标
    在这里插入图片描述
    ②核心代码
    每次结果集有记录,将记录实例化对象,把记录中的对应项添加到类的属性中(列与属性时对应的)——封装完成代表一个学生
    将学生放入结果集,最终结果集是查询结果
    在这里插入图片描述
    public List<Student> queryAllStudent(){//查询方法

        String driver ="com.mysql.jdbc.Driver";
        //不同数据库、相同数据库不同版本的driver不同
        String url="jdbc:mysql://localhost:3306/scott?useSSL=false";//连接what数据库
        String name="root";//登录用户,一般是hoot
        String pass="123456";//自己数据库的密码

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs =null;
        List<Student> list = new ArrayList<>();//list加泛型

        try {
            //注册驱动 (仅仅做一次)
            Class.forName(driver);//反射
            //建立连接(Connection)
            connection= DriverManager.getConnection (url,name,pass);//建立连接需要四个参数

            //创建运行SQL的语句(Statement)
            statement=connection.prepareStatement("select * from student");

            //运行语句
            rs = statement.executeQuery();

            //处理运行结果(ResultSet)——只有查询时有,进行增删改操作时没有这一步
            while (rs.next()){//不知道记录条数,不知循环次数——while。结果集的指针可以向下移动一步时
                Student student = new Student();//实例化对象
                //把rs中的每一个值都放入Student中
                student.setId(rs.getInt(1));
                student.setStudent_name(rs.getString("student_name"));

                list.add(student);
            }

        }catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (Exception e) { //多重catch,最后要加一个父类
            e.printStackTrace();
        }finally {
            //释放资源 (connection、statement、resultset)
            try {//对象不存在关不上,需要加try/catch
                connection.close();
                statement.close();
            }catch (SQLException throwables){
                throwables.printStackTrace();
            }
        }
        return list;
    }
2>. 测试调用

forEach
在这里插入图片描述
此时打印出来的是对象的内存地址,要打印对象本身——重写toString() 方法
Text.java中测试

import dao.StudentDao;

public class Text {
    public static void main(String[] args) {
        StudentDao studentDao = new StudentDao();
        studentDao.queryAllStudent().forEach(System.out::println);

    }
}

结果在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值