JDBC-笔记

《JDBC》笔记

回顾

  1. 理解mysql索引的作用

    -- 创建单列索引
    create index 索引名 on 表名(列名)
    
    -- 显示索引信息
    show index from 表名
    
    -- 删除索引
    drop index 索引名 on 表名
    
  2. 能够理解事务的概念

    1. 事务的四大特性 ACID
      1. 原子性
      2. 一致性
      3. 隔离性
      4. 持久性
    2. mysql操作事务的语句
    事务的操作MySQL操作事务的语句
    开启事务start transaction
    提交事务commit
    回滚事务rollback
    设置回滚点savepoint 名字
    回到回滚点rollback to 名字
    查询事务的自动提交情况select @@autocommit
    设置事务的手动提交方式set @@autocommit=1/0
  3. 会使用mysql字符串函数

    字符串函数说明
    CHAR_LENGTH(s)获取字符串长度
    CONCAT(s1,s2…sn)拼接字符串
    LOWER(s)转成小写
    UPPER(s)转成大写
    SUBSTR(s, start, length)取子字符串
    TRIM(s)去掉前后的空格
  4. 会使用mysql日期函数

    日期函数说明
    ADDDATE(d,n)给日期加天数得到新的日期
    CURDATE()获取现在的日期
    DATEDIFF(d1,d2)计算2个日期相差的天数
    NOW()获取现在的日期和时间
  5. 能够理解JDBC的概念

    1. 由一组接口组成,实现类由数据库厂商实现
    2. 我们写的代码可以访问不同的数据库

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K5fZFg9K-1592210865252)(/assets/1562312829882.png)]

  6. 如何创建连接

DriverManager类中的静态方法描述
Connection getConnection (String url, String user, String password)通过URL,用户名,密码获取连接
Connection getConnection (String url, Properties info)通过URL,属性集合获取连接
  1. 连接数据库的四个参数

    1. 用户名
    2. 密码
    3. jdbc:mysql://localhost:3306/数据库名?参数=值 或 jdbc:mysql:///数据库名
    4. 驱动:com.mysql.jdbc.Driver

学习目标

  1. 能够使用Connection接口
  2. 能够使用Statement接口
  3. 能够使用ResultSet接口
  4. 能够使用JDBC操作事务
  5. 能够编写JDBC工具类
  6. 能够完成JDBC实现登录案例
  7. 能够通过PreparedStatement完成增、删、改、查

Connection和Statement接口

目标

  1. Connection接口的作用和方法
  2. Statement接口的作用和方法

Connection接口

作用

每次访问数据库之前,第一件事情是创建连接对象,代表数据库连接对象。

  1. 由DriverManager来创建
  2. 创建语句对象:Statement

方法

Connection接口中的方法描述
Statement createStatement()通过连接对象创建语句对象

Statement接口

作用

代表要执行的SQL语句

方法

三个方法都有一个字符串的参数,参数就是要执行的SQL语句

Statement接口中的方法描述
boolean execute(String sql)(了解) 作用:执行SQL语句,可以执行任意的SQL语句,
通常用来执行DDL语句
返回值:如果有结果集返回true,如果没有结果集返回false
查询有结果集,增删改没有结果集
int executeUpdate(String sql)作用:用来执行DML中增删改操作
返回值:受影响的行数
ResultSet executeQuery(String sql)作用:用来执行DQL查询操作
返回值:查询到的结果集

释放资源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jObSpHxY-1592210865256)(assets/image-20200510092112830.png)]

  1. 需要释放的对象:关闭结果集ResultSet,语句对象Statement,连接对象Connection
  2. 释放顺序:先开的后关,后开的先关。
    1. 打开顺序:Connection -> Statement -> ResultSet
    2. 关闭顺序:ResultSet -> Statement -> Connection
  3. 写在哪里
    1. 可以放在try()代码块中,因为所有的接口都实现了AutoCloseable接口。放在try()括号中的代码必须是实现这个接口,才能自动完毕。
    2. 放在finally中去关闭

小结

  1. Connection接口的作用是什么

    创建语句对象

  2. Statement接口的作用是什么

    执行SQL语句

JDBC:执行DDL操作

目标

使用JDBC创建执行DDL操作

需求

建议:所有要执行的SQL语句,应该在SQLyog中确定它是正确的,才写到Java中去。

使用JDBC在MySQL的数据库中创建一张学生表

  1. id是主键,整数类型,自增长
  2. name是varchar(20),非空
  3. 性别是boolean类型
  4. 生日是date类型
/* 创建学生表
1. id是主键,整数类型,自增长
2. name是varchar(20),非空
3. 性别是boolean类型
4. 生日是date类型
*/
create table student(
     id int primary key auto_increment,
     name varchar(20) not null,
     sex boolean,  -- mysql中生成的是tinyint类型
     birthday date
);

步骤

  1. 添加mysql的驱动包
    在这里插入图片描述

  2. 创建连接

  3. 通过连接对象得到语句对象

  4. 通过语句对象发送SQL语句给服务器,执行SQL

  5. 通过语句对象发送SQL语句给服务器

  6. 释放资源

代码

package com.itheima;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 使用JDBC的DDL语句创建一张表
 */
public class Demo01DDL {

    public static void main(String[] args) throws SQLException {
        //1. 创建连接对象 (先在SQLyog中创建day22的数据库)
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/day22", "root", "root");
        //2. 通过连接对象得到语句对象
        Statement statement = connection.createStatement();
        //3. 通过语句对象执行DDL语句,注:SQL语句中不要有分号
        statement.execute("create table student( id int primary key auto_increment, name varchar(20) not null, sex boolean, birthday date)");
        //4. 释放资源,先开的后关,后开的先关
        statement.close();
        connection.close();
        //5. 如果没有异常表示执行成功, 控制台输出创建成功
        System.out.println("创建学生表成功");

    }

}

小结

执行DDL语句使用Statement接口的哪个方法?

boolean execute(String sql)

在实际的应用中很少去使用JDBC来执行DDL语句,因为建库或建表这些代码会在mysql中先写好并执行。

通常是执行DML或DQL比较多

JDBC:执行DML操作

目标

使用JDBC来实现增删改操作

需求

  1. 向学生表添加4条记录
  2. 更新其中2条记录
  3. 删除其中1条记录

接口中的方法

Statement接口中的方法描述
int executeUpdate(String sql)作用:执行增删改操作
返回值:返回影响的行数

SQL语句

-- 插入操作
insert into student (name, sex, birthday) values ('name', 'sex', 'birthday'),('name', 'sex', 'birthday'),('name', 'sex', 'birthday'),('name', 'sex', 'birthday');
-- 更新操作,修改所有女生生日为今天
update student set birthday = curdate() where sex = 0;
-- 删除id为3的用户
delete from student where id=3;

代码

package com.itheima;

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 使用JDBC来实现增删改操作
 */
public class Demo2DML {

    //执行插入操作,添加4条记录
    @Test
    public void testInsert() throws SQLException {
        //1.创建连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
        //2.得到语句对象
        Statement statement = connection.createStatement();
        //3.执行DML,boolean类型既可以使用true或false,也可以使用1或0
        int row = statement.executeUpdate("insert into student (name, sex, birthday) values ('孙悟空', true, '2011-02-12')," +
                "('猪八戒', true, '1999-12-12'),('白骨精', false, '1993-02-06'),('嫦娥', false, '1999-11-23')");
        //4.释放资源
        statement.close();
        connection.close();
        //5.打印影响的行数
        System.out.println("插入了" + row + "行记录");
    }


    @Test
    public void testUpdate() throws SQLException {
        //1.创建连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
        //2.得到语句对象
        Statement statement = connection.createStatement();
        //3.执行DML,boolean类型既可以使用true或false,也可以使用1或0
        int row = statement.executeUpdate("update student set birthday = curdate() where sex = 0");
        //4.释放资源
        statement.close();
        connection.close();
        //5.打印影响的行数
        System.out.println("修改了" + row + "行记录");
    }

    @Test
    public void testDelete() throws SQLException {
        //1.创建连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
        //2.得到语句对象
        Statement statement = connection.createStatement();
        //3.执行DML,boolean类型既可以使用true或false,也可以使用1或0
        int row = statement.executeUpdate("delete from student where id=3");
        //4.释放资源
        statement.close();
        connection.close();
        //5.打印影响的行数
        System.out.println("删除了" + row + "行记录");
    }
}

小结

增删改使用statement接口中哪个方法?

int executeUpdate(String sql)

ResultSet接口

目标

  1. ResultSet接口的执行原理
  2. 接口中方法

原理图

在这里插入图片描述

方法

ResultSet接口中的方法描述
boolean next()1. 向下移动1行
2. 如果所指的位置有数据返回true,否则返回false
数据类型 get数据类型(参数)获取这一行的数据,取值的方法有2种:
1. 通过列号取(从1开始,列号是整数类型)
2. 通过列名取(列名是一个字符串类型)

ResultSet接口中的getXxx()方法

在这里插入图片描述

常用数据类型对应表

这只是建议,并不绝对这么写

注:日期类型返回的并不是java.util.Date,而是java.sql.Date

这三个类java.sql.Date, java.sql.Time, java.sql.Timestamp 共同的父类是java.util.Date

1562314590156

小结

ResultSet接口中的方法描述
boolean next()1. 向下移动一行
2. 如果所指的行有数据,返回true,否则返回false
数据类型 getXxx(参数)获取这一行的数据,有两种方式:
1. 通过列号
2. 通过列名

JDBC:执行DQL操作

目标

使用JDBC实现DQL查询操作

需求

确保数据库中有3条以上的记录,查询所有的学员信息

查询结果

1562314881204

步骤

  1. 得到连接对象
  2. 得到语句对象
  3. 执行SQL语句后得到结果集ResultSet对象
  4. 循环遍历取出每一条记录
  5. 输出的控制台上
  6. 释放资源

代码

package com.itheima;

import java.sql.*;

/**
 * 执行DQL操作
 */
public class Demo03DQL {

    public static void main(String[] args) throws SQLException {
        //1.创建连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
        //2.获取语句对象
        Statement statement = connection.createStatement();
        //3.执行DQL,得到结果集
        ResultSet resultSet = statement.executeQuery("select * from student");
        //4.遍历结果集,输出每一行的数据
        while (resultSet.next()) {  //返回true表示有数据
            //4.1使用列号
            /*int id = resultSet.getInt(1);
            String name = resultSet.getString(2);
            boolean sex = resultSet.getBoolean(3);
            Date birthday = resultSet.getDate(4);*/
            //4.2使用列名
            int id = resultSet.getInt("id");   //也可以使用别名,必须与mysql中列名能对应的
            //String id = resultSet.getString("id");  //如果能自动转换,jdbc会自动转换
            String name = resultSet.getString("name");
            //int name = resultSet.getInt("name");  //不能转换,会报错
            boolean sex = resultSet.getBoolean("sex");
            Date birthday = resultSet.getDate("birthday");
            System.out.println("编号:" + id + ",姓名:" + name + ",性别:" + sex + ",生日:" + birthday);
        }
        //5.释放资源:结果集,语句对象,连接对象
        resultSet.close();
        statement.close();
        connection.close();
    }

}

小结

查询数据库使用Statement的哪个方法?

ResultSet executeQuery(String sql)

创建JDBC数据库工具类

目标

创建一个可以通用的Jdbc数据库工具类

需求

上面的代码中出现了很多重复的代码,可以把这些公共代码抽取出来。

正常关闭的代码

package com.itheima;

import java.sql.*;

/**
 * 执行DQL操作
 */
public class Demo03DQL {

    public static void main(String[] args) {
        //1. 先选中代码 2.按ctrl+alt+t
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //1.创建连接对象
            connection = DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
            //2.获取语句对象
            statement = connection.createStatement();
            //3.执行DQL,得到结果集
            resultSet = statement.executeQuery("select * from student");
            //4.遍历结果集,输出每一行的数据
            while (resultSet.next()) {  //返回true表示有数据
                //4.1使用列号
                /*int id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                boolean sex = resultSet.getBoolean(3);
                Date birthday = resultSet.getDate(4);*/
                //4.2使用列名
                int id = resultSet.getInt("id");   //也可以使用别名,必须与mysql中列名能对应的
                //String id = resultSet.getString("id");  //如果能自动转换,jdbc会自动转换
                String name = resultSet.getString("name");
                //int name = resultSet.getInt("name");  //不能转换,会报错
                boolean sex = resultSet.getBoolean("sex");
                Date birthday = resultSet.getDate("birthday");
                System.out.println("编号:" + id + ",姓名:" + name + ",性别:" + sex + ",生日:" + birthday);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //5.释放资源:结果集,语句对象,连接对象。每个close方法都会抛出异常
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

步骤

创建类JdbcUtils包含2个方法:

  1. 将数据库的4个参数定义成常量
  2. 得到数据库的连接:getConnection()
  3. 关闭所有打开的资源:
    close(Connection conn, Statement stmt),
    close(Connection conn, Statement stmt, ResultSet rs)

代码

package com.itheima.utils;

import java.sql.*;

/**
 * 创建工具类
 * 1. 直接获取连接对象
 * 2. 释放资源
 */
public class JdbcUtils {

    /**
     * 获取连接
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql:///day22", "root", "root");
    }

    /**
     * 关闭连接
     * 查询调用这个方法
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 关闭连接
     * 增删改没有结果集
     */
    public static void close(Connection connection, Statement statement) {
       //直接调用上面的方法
        close(connection, statement, null);
    }
}

使用工具类

package com.itheima;

import com.itheima.utils.JdbcUtils;

import java.sql.*;

/**
 * 执行DQL操作
 */
public class Demo03DQL {

    public static void main(String[] args) {
        //1. 先选中代码 2.按ctrl+alt+t
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //1.创建连接对象
            connection = JdbcUtils.getConnection();
            //2.获取语句对象
            statement = connection.createStatement();
            //3.执行DQL,得到结果集
            resultSet = statement.executeQuery("select * from student");
            //4.遍历结果集,输出每一行的数据
            while (resultSet.next()) {  //返回true表示有数据
                //4.2使用列名
                int id = resultSet.getInt("id");   //也可以使用别名,必须与mysql中列名能对应的
                String name = resultSet.getString("name");
                boolean sex = resultSet.getBoolean("sex");
                Date birthday = resultSet.getDate("birthday");
                System.out.println("编号:" + id + ",姓名:" + name + ",性别:" + sex + ",生日:" + birthday);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //5.释放资源:结果集,语句对象,连接对象。每个close方法都会抛出异常
            JdbcUtils.close(connection, statement, resultSet);
        }
    }

}

小结

工具类主要有哪两个功能?

  1. 简化获取连接的代码
  2. 简化关闭连接的代码

JDBC:事务的处理

目标

使用JDBC来处理事务:实现银行转账的操作

API介绍

Connection接口中与事务有关的方法说明
void setAutoCommit(boolean autoCommit)设置事务的提交方式
true 表示自动提交
false 表示手动提交
如果要开启事务,设置为false
void commit()提交事务
void rollback()回滚事务

准备数据

-- 创建账户表:id,name,balance
create table account(
	id int primary key auto_increment,  -- 主键自动增长
	name varchar(20),  -- 账户名
	balance int   -- 账户的余额
);  
 
-- 添加数据:Jack和Rose各1000块
insert into account values(null, 'Jack',1000),(null,'Rose',1000);

select * from account;

-- 模拟Jack转账给Rose 200块钱的功能:
-- 至少要执行2条SQL语句
-- 1. 更新Jack账户,从Jack中减去200
-- 2. 更新Rose账户,给Rose加200块
-- 执行第1条
update account set balance=balance-500 where name='Jack';
-- 执行第2条,可能会出现第1条语句执行成功,第2条语句没有执行,或者执行失败的情况
update account set balance=balance+500 where name='Rose';

-- 查询转账后结果
select * from account;

-- 还原2个账户的钱为1000
update account set balance = 1000;

开发步骤

没有事务的转账情况

  1. 获取连接
  2. 获取到Statement
  3. 使用Statement执行两次更新操作
  4. 最后关闭资源

使用事务的情况

  1. 获取连接
  2. 开启事务
  3. 获取到Statement
  4. 使用Statement执行两次更新操作
  5. 正常情况下提交事务
  6. 出现异常回滚事务
  7. 最后关闭资源
package com.itheima;

import com.itheima.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 通过事务实现转账的功能
 */
public class Demo04Transaction {

    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        try {
            //1.获取连接
            connection = JdbcUtils.getConnection();
            //1.5 手动提交事务
            connection.setAutoCommit(false);
            //2.创建语句对象
            statement = connection.createStatement();
            //3.执行更新操作:Jack扣钱
            statement.executeUpdate("update account set balance=balance-500 where name='Jack'");
            //模拟出现异常的情况
            System.out.println(1 / 0);
            //4.执行更新操作:Rose加钱
            statement.executeUpdate("update account set balance=balance+500 where name='Rose'");
            //4.5 提交事务
            connection.commit();
            //5.没有异常提示转账成功
            System.out.println("转账成功");
        } catch (Exception e) {   //只要出现异常就输出转账失败
            //回滚事务
            try {
                connection.rollback();   //就算出来了异常,日志文件也是会被清除
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            //6.有异常提示转账失败
            System.out.println("转账失败");
        }
        //5.释放资源
        finally {
            JdbcUtils.close(connection, statement);
        }
    }

}

小结

Connection接口中与事务有关的方法说明
void setAutoCommit(boolean autoCommit)设置手动提交事务
设置为false就是手动提交事务
void commit()提交事务
void rollback()回滚事务

应用案例:用户登陆

目标

通过访问数据库,查询数据库中的用户,实现登录的功能

需求

  1. 有一张用户表id,name,password,添加2条用户记录
-- 建表
create table user(
	id int primary key auto_increment,
	username varchar(20) not null unique,  -- 登录名不能重复
	password varchar(32) not null
);

-- 插入记录
insert into user values(null, 'Jack','123'),(null,'Rose','456');

-- 什么时候登录成功,有记录就是登录成功
select * from user where username='Jack' and password='123';

-- 什么时候登录失败,没有查到记录
select * from user where username='Newboy' and password='890';
  1. 用户在控制台上输入用户名和密码,实现登录的功能

步骤

  1. 得到用户从控制台上输入的用户名和密码
  2. 调用下面写的登录方法来实现登录
  3. 写一个登录的方法
  4. 通过工具类得到连接
  5. 创建语句对象,使用拼接字符串的方式生成SQL语句
  6. 查询数据库,如果有记录则表示登录成功,否则登录失败
  7. 释放资源

代码

package com.itheima;

import com.itheima.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

/**
 * 实现用户的登录
 */
public class Demo05Login {

    public static void main(String[] args) throws SQLException {
        //用户输入用户名和密码
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();  //Jack
        System.out.println("请输入密码:");
        String password = scanner.nextLine();  //123

        //开始登录,使用JDBC访问数据库,本质上就是一个查询操作
        //1.获取连接
        Connection connection = JdbcUtils.getConnection();
        //2.得到语句对象
        Statement statement = connection.createStatement();
        //3.查询用户名和密码的记录
        //注:SQL语句要拼接字符串
        String sql = "select * from user where username='" + username + "' and password='" + password + "'";
        System.out.println("生成的SQL语句:" + sql);
        ResultSet resultSet = statement.executeQuery(sql);
        //4.如果有结果集返回就登录成功,因为只有一条记录,所以不需要使用while遍历,使用if就可以
        if (resultSet.next()) {
            System.out.println("登录成功,欢迎您:" + username);
        }
        //5.没有结果集登录失败
        else {
            System.out.println("登录失败,请重试");
        }
        //6.释放资源
        JdbcUtils.close(connection, statement, resultSet);
    }
}

SQL注入问题

这个程序有一个致命的bug,因为我们的SQL语句是通过拼接字符串生成的,会有SQL注入的问题。
在这里插入图片描述

问题分析

-- 如果这么写是可以查询所有的记录的
select * from user where true;

-- SQL注入生成的语句
select * from user where username='newboy' and password='a' or '1'='1'
select * from user where false and false or true

解决方法:

我们让用户输入的密码和SQL语句进行字符串拼接。用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义,以上问题称为SQL注入。

要解决SQL注入就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。

小结

登录的SQL语句如何写?

select * from user where username='用户名' and password='密码'

PreparedStatement接口的执行原理

目标

  1. 为什么要使用PreparedStatement
  2. PreparedStatement的原理

继承结构

在这里插入图片描述

通过继承结构可以知道,它的父接口是Statement,Prepared准备好的SQL语句。MySQL中的语句也是要编译以后才执行,编译是需要消耗时间的。

比父接口更强大的地方:

  1. SQL语句会预先编译,执行效率会更高。
  2. 解决SQL注入的问题,更安全
  3. SQL语句代码的可读性更好,所有要替换的参数使用占位符,占位符是?问号

PreparedSatement的执行原理

如果执行相同的SQL语句,只需要编译一次,而且是预先编译。在创建语句对象的时候就提供了SQL语句,而不是等到执行的时候才提供SQL语句。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiw38ExQ-1592210865280)(assets/image-20200510141135875.png)]

PreparedSatement的小结

  1. SQL语句是预先编译的,创建的时候提供SQL语句,执行的时候没有SQL语句
  2. 安全性更高,没有SQL注入的问题
  3. 代码的可读性会更好

PreparedStatement中相关的方法

目标

  1. 如何得到PreparedStatement对象
  2. PreparedStatement对象有哪些方法

Connection创建PreparedStatement对象

Connection接口中的方法描述
PreparedStatement prepareStatement(String sql)通过连接对象创建预编译语句对象,
创建的时候要提供SQL语句,语句有可能有占位符
如果有占位符,后面需要替换占位符为真实的值

接口中的方法

这两个方法都没有参数,不需要提供SQL语句

PreparedStatement接口中的方法描述
int executeUpdate()实现增删改的操作
返回影响的行数
ResultSet executeQuery()实现查询的操作,返回结果集

设置占位符的方法

PreparedStatement的方法说明
void set数据类型(int 参数1,数据类型 参数2)参数1:第几个占位符(从1开始)
参数2:替换占位符的真实值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGLgMEIM-1592210865285)(assets/1562316815441.png)]

小结

PreparedStatement接口中的方法描述
int executeUpdate()实现增删改的操作
ResultSet executeQuery()实现查询的操作

PreparedStatement:执行DML操作

目标

  1. 向学生表中添加1条记录代码
  2. 将id为2的用户,姓名更新为"蜘蛛精",性别换成女
  3. 将id为4的学员删除

代码

package com.itheima;

import com.itheima.utils.JdbcUtils;
import org.junit.Test;

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

/**
 * 1. 向学生表中添加1条记录代码
 * 2. 将id为2的用户,姓名更新为"蜘蛛精",性别换成女
 * 3. 将id为4的学员删除
 */
public class Demo06Prepared {

    @Test
    public void testInsert() throws SQLException {
        //1.创建连接对象
        Connection connection = JdbcUtils.getConnection();
        //2.创建预编译的语句对象,提供了SQL语句
        PreparedStatement ps = connection.prepareStatement("insert into student (name, sex, birthday) values (?, ?, ?)");
        //3.替换占位符为真实的值
        ps.setString(1, "二郎神");
        ps.setBoolean(2, true);
        ps.setDate(3, Date.valueOf("2011-02-20"));   //注:这是java.sql.Date类中静态方法
        //4.执行SQL语句
        int row = ps.executeUpdate();   //没有SQL语句
        //5.释放资源
        JdbcUtils.close(connection, ps);
        System.out.println("插入了" + row + "条记录");
    }

    //将id为2的用户,姓名更新为"蜘蛛精",性别换成女
    @Test
    public void testUpdate() throws SQLException {
        //1.创建连接对象
        Connection connection = JdbcUtils.getConnection();
        //2.创建预编译的语句对象,提供了SQL语句
        PreparedStatement ps = connection.prepareStatement("update student set name=?, sex=? where id = ?");
        //3.替换占位符为真实的值
        ps.setString(1, "蜘蛛精");
        ps.setBoolean(2, false);
        ps.setInt(3, 2);
        //4.执行SQL语句
        int row = ps.executeUpdate();   //没有SQL语句
        //5.释放资源
        JdbcUtils.close(connection, ps);
        System.out.println("更新了" + row + "条记录");
    }


    //将id为4的学员删除
    @Test
    public void testDelete() throws SQLException {
        //1.创建连接对象
        Connection connection = JdbcUtils.getConnection();
        //2.创建预编译的语句对象,提供了SQL语句
        PreparedStatement ps = connection.prepareStatement("delete from student where id=?");
        //3.替换占位符为真实的值
        ps.setInt(1, 4);
        //4.执行SQL语句
        int row = ps.executeUpdate();   //没有SQL语句
        //5.释放资源
        JdbcUtils.close(connection, ps);
        System.out.println("删除" + row + "条记录");
    }
}

小结

执行DML使用哪个方法?

int executeUpdate()

案例:使用预编译语句改写登录程序

目标

改写前面的登录案例,解决SQL注入的问题

执行效果

1562317207959

代码

package com.itheima;

import com.itheima.utils.JdbcUtils;

import java.sql.*;
import java.util.Scanner;

/**
 * 实现用户的登录
 */
public class Demo07Login {

    public static void main(String[] args) throws SQLException {
        //用户输入用户名和密码
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();  //Jack
        System.out.println("请输入密码:");
        String password = scanner.nextLine();  //123

        //1.获取连接
        Connection connection = JdbcUtils.getConnection();
        //2.得到预编译语句对象,注:占位符外面没有单引号
        PreparedStatement preparedStatement = connection.prepareStatement("select * from user where username=? and password=?");
        //3.替换占位符
        preparedStatement.setString(1, username);
        preparedStatement.setString(2, password);
        //4.执行查询操作
        ResultSet resultSet = preparedStatement.executeQuery();  //没有SQL语句的参数
        if (resultSet.next()) {  //如果有记录表示登录成功
            System.out.println("登录成功,欢迎您:" + username);
        }
        else {  //登录失败
            System.out.println("登录失败,请重试");
        }
        //5.释放资源
        JdbcUtils.close(connection, preparedStatement, resultSet);
    }
}

小结

预编译语句可以有效的避免SQL注入的问题

案例:执行DQL封装成集合的操作

目标

  1. 表与类之间的关系

  2. 将查询的多条记录封装成List<Student>集合

表与类之间的关系

如果结果集关闭,结果集中的数据就不能使用了。在DAO层将结果集中的数据重新封装到一个新的对象中,就可以在DAO层放心的关闭结果集,以后只需要使用重新封装的这个对象即可。

  • 如果是一条记录,封装成实体类对象
  • 如果是多条记录,封装成一个集合

降低了与数据库的耦合度

这种映射关系称为ORM:Object Relational Mapping 对象关系映射

在这里插入图片描述

案例:查询多条记录

需求:

查询所有的学生类,封装成List<Student>返回

执行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-537m68Iq-1592210865293)(assets/image-20200510150525749.png)]

开发步骤:

  1. 创建一个集合用于封装所有的记录
  2. 得到连接对象
  3. 得到语句对象,SQL语句没有占位符
  4. 得到结果集,每次循环封装一个学生对象
  5. 把封装好的学生数据放到集合中
  6. 关闭连接
  7. 以后使用数据,循环输出集合中学生对象

代码

package com.itheima.entity;

import java.sql.Date;

public class Student {
    //建议属性名与表中列名相同,如果列名是多个单词:user_name,那么属性名:userName
    private int id;
    private String name;
    private boolean sex;
    private Date birthday;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                ", birthday=" + birthday +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isSex() {
        return sex;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

package com.itheima;

import com.itheima.entity.Student;
import com.itheima.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 将表中所有的记录封装成一个集合
 */
public class Demo08List {

    public static void main(String[] args) throws SQLException {
        //1.创建连接对象
        Connection connection = JdbcUtils.getConnection();
        //2.创建预编译的语句对象
        PreparedStatement preparedStatement = connection.prepareStatement("select * from student");
        //3.执行查询操作
        ResultSet resultSet = preparedStatement.executeQuery();
        //4.遍历整个结果集
        //创建一个集合
        List<Student> students = new ArrayList<>();
        while (resultSet.next()) {
            //5.每条记录封装成一个学生对象
            Student student = new Student();
            student.setId(resultSet.getInt("id"));
            student.setName(resultSet.getString("name"));
            student.setBirthday(resultSet.getDate("birthday"));
            student.setSex(resultSet.getBoolean("sex"));
            //6.将学生对象添加到集合中
            students.add(student);
        }
        //7.释放资源,关闭连接 (结果集不可用)
        JdbcUtils.close(connection,preparedStatement, resultSet);

        //8.后期可以使用集合,其实就是从数据库中查询出来的数据
        students.forEach((student -> System.out.println(student)));
    }

}

小结

表与类之间的对应关系是怎样的?

  1. 表结构->类结构
  2. 每条记录->对象
  3. 字段名->属性名

学习总结

  1. 能够使用Connection接口

    Connection接口中的方法描述
    Statement createStatement()创建语句对象,没有SQL参数
    PreparedStatement prepareStatement(String sql)创建预编译的语句对象,有SQL参数
  2. 能够使用Statement接口

    以下三个方法都是有SQL语句的参数

    Statement接口中的方法描述
    boolean execute(String sql)作用:可以执行任意的SQL
    返回值:如果有结果集返回true,没有就返回false
    int executeUpdate(String sql)作用:执行增删改
    返回值:影响的行数
    ResultSet executeQuery(String sql)作用:执行查询操作
    返回值:结果集
  3. 能够使用ResultSet接口

    ResultSet接口中的方法描述
    boolean next()1. 向下移动一行
    2. 如果当前行有数据,返回true,否则返回false
    数据类型 getXxx(参数)从结果集中获取数据
    1. 通过列号
    2. 通过列名
  4. 能够使用JDBC操作事务

    Connection接口中与事务有关的方法说明
    void setAutoCommit(boolean autoCommit)设置为false,表示手动提交事务
    void commit()提交事务
    void rollback()回滚事务
  5. 能够编写JDBC工具类

    1. 得到数据库的连接:getConnection()
    2. 关闭所有打开的资源:
      close(Connection conn, Statement stmt)
      close(Connection conn, Statement stmt, ResultSet rs)
  6. 能够完成JDBC实现登录案例

  7. 能够通过PreparedStatement完成增、删、改、查

方法没有SQL参数:

PreparedStatement接口中的方法描述
int executeUpdate()实现增删改的操作,返回影响的行数
ResultSet executeQuery()实现查询的操作,返回结果集

作业

完成作业文件夹中:PreparedStatement练习

int executeUpdate(String sql) | 作用:执行增删改
返回值:影响的行数 |
| ResultSet executeQuery(String sql) | 作用:执行查询操作
返回值:结果集 |

  1. 能够使用ResultSet接口

    ResultSet接口中的方法描述
    boolean next()1. 向下移动一行
    2. 如果当前行有数据,返回true,否则返回false
    数据类型 getXxx(参数)从结果集中获取数据
    1. 通过列号
    2. 通过列名
  2. 能够使用JDBC操作事务

    Connection接口中与事务有关的方法说明
    void setAutoCommit(boolean autoCommit)设置为false,表示手动提交事务
    void commit()提交事务
    void rollback()回滚事务
  3. 能够编写JDBC工具类

    1. 得到数据库的连接:getConnection()
    2. 关闭所有打开的资源:
      close(Connection conn, Statement stmt)
      close(Connection conn, Statement stmt, ResultSet rs)
  4. 能够完成JDBC实现登录案例

  5. 能够通过PreparedStatement完成增、删、改、查

方法没有SQL参数:

PreparedStatement接口中的方法描述
int executeUpdate()实现增删改的操作,返回影响的行数
ResultSet executeQuery()实现查询的操作,返回结果集
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dukai954

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值