【MySQL_JDBC】

JDBC

  • JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范.
  • JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
    在这里插入图片描述
  • JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。

JDBC 开发

  1. 将MySQL驱动包添加到jar包库文件夹中,Myjar文件夹,用于存放当前项目需要的所有jar包
    在这里插入图片描述

  2. 在 idea中 配置jar包库的位置
    在这里插入图片描述

  3. 创建一个新的项目jdbc_task01, 配置jar包库
    在这里插入图片描述

API使用: 1.注册驱动

  • JDBC规范定义驱动接口: java.sql.Driver
  • MySql驱动包提供了实现类: com.mysql.jdbc.Driver
加载注册驱动的方式描述
Class.forName(数据库驱动实现类)加载和注册数据库驱动,数据库驱动由数据库厂商MySql提供"com.mysql.jdbc.Driver"
public class RegisterJDBC {
    public static void main(String[] args) {
        // 利用反射的方式注册mysql驱动
        Class.forName("com.mysql.jdbc.Driver");
    }
}
// Driver类是MySql提供的数据库驱动类, 实现了JDBC的Driver接口 java.sql.Driver
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
	// 空参构造
    public Driver() throws SQLException {
    }
	//静态代码块,Class类的 forName()方法将Driver类 加载到内存, static代码块会自动执行
    static {
        try {
        /* 
        	DriverManager 驱动管理类 
        	registerDriver(new Driver) 注册驱动的方法 
        	注册数据库驱动 					 
        */
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

注意:从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。 Class.forName 这句话可以省略。

API使用: 2.获得连接

  • Connection 接口,代表一个连接对象 ,具体的实现类由数据库的厂商实现
  • 使用 DriverManager类的静态方法,getConnection可以获取数据库的连接
获取连接的静态方法说明
Connection getConnection(String url, String user,String password)通过连接字符串和用户名,密码来获取数据库连接对象
  1. getConnection方法 3个 连接参数说明
连接参数说明
user登录用户名
password登录密码
urlmySql URL的格式: jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8
  1. URL的详细说明
    JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。
    第一部分是协议 jdbc,这是固定的;
    第二部分是子协议,就是数据库名称,连接mysql数据库,第二部分当然是mysql了;
    第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及要使用的 数据库名称 组成。
public class RegisterJDBC {
    public static void main(String[] args) throws Exception {
        // 利用反射的方式注册mysql驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 获取连接
        String url = "jdbc:mysql://localhost:3306/db4?characterEncoding=utf-8";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        System.out.println(connection); // com.mysql.jdbc.JDBC4Connection@7fa98a66
    }
}

API 使用: 3.获取语句执行平台

  • 通过Connection 的 createStatement方法 获取sql语句执行对象
Connection接口中的方法说明
Statement createStatement()创建 SQL语句执行对象
  • Statement : 代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。
Statement类 常用方法说明
int executeUpdate(String sql);执行insert update delete语句.返回int类型,代表受影响的行数
ResultSet executeQuery(String sql);执行select语句, 返回ResultSet结果集对象
public class RegisterJDBC {
    public static void main(String[] args) throws Exception {
        // 1.利用反射的方式注册mysql驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 2.获取连接
        String url = "jdbc:mysql://localhost:3306/db4?characterEncoding=utf-8";
        Connection connection = DriverManager.getConnection(url, "root", "123456");
        System.out.println(connection);

        // 3.获取语句执行平台
        Statement statement = connection.createStatement();
        // 4.执行创建表操作
        String sql = "create table test01(id int, name varchar(20),age int);";
        // 5.增删改操作 使用executeUpdate,增加一张表
        int i = statement.executeUpdate(sql);
        // 6.返回值是受影响的行数
        System.out.println(i);
        // 7.关闭流
        statement.close();
        connection.close();
    }
}

API 使用: 4.处理结果集

  • 只有在进行查询操作的时候, 才会处理结果集
ResultSet接口

封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。

ResultSet接口方法说明
boolean next()游标向下一行; 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false
xxx getXxx( String or int)通过列名,参数是 String 类型。返回不同的类型;通过列号,参数是整数,从 1 开始。返回不同的类型
public class JDBCDemo01 {
    public static void main(String[] args) throws Exception {
        // 1.注册驱动(可省略)

        // 2.获取连接
        String url = "jdbc:mysql://localhost:3306/db4";
        Connection connection = DriverManager.getConnection(url, "root", "123456");

        // 3.获取语句执行平台 statement
        Statement statement = connection.createStatement();

        // 4.执行查询操作
        String sql = "select * from jdbc_user;";
        ResultSet resultSet = statement.executeQuery(sql);

        // 5.处理结果集
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("PASSWORD");
            Date birthday = resultSet.getDate("birthday");
            System.out.println(id + "  " + username + "  " + password + "  " + birthday);
        }
        
		// 6.关闭连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

JDBC实现增删改查

JDBC工具类

public class JDBCUtils {
    // 1. 定义字符串常量, 记录获取连接所需要的信息
    private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/db4?characterEncoding=utf-8";
    private static final String USER = "root";
    private static final String PASSWORD = "123456";

    // 2. 静态代码块, 注册驱动
    static {
        try {
            Class.forName(DRIVER_NAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // 3.获取连接的静态方法
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(URL, USER, PASSWORD);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    // 4.关闭资源的方法
    public static void close(Connection connection, Statement statement) {
        if (statement != null && connection != null) {
            try {
                statement.close();
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        close(connection, statement);
    }
}

DML操作

向表中插入一条数据

public class TestInsert {
    public static void main(String[] args) {
        // 1.获取连接
        Connection connection = JDBCUtils.getConnection();

        // 2.获取statement
        Statement statement = null;
        try {
            statement = connection.createStatement();
            String sql = "insert into jdbc_user values(null,'张百万','123','2020/1/1');";
            int result = statement.executeUpdate(sql);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(connection, statement);
        }
    }
}

修改表中的数据

public class TestUpdate {
    public static void main(String[] args) {
        Connection connection = JDBCUtils.getConnection();
        Statement statement = null;
        try {
            statement = connection.createStatement();
            String sql = "update jdbc_user set username = '广坤' where id = 1;";
            int result = statement.executeUpdate(sql);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(connection, statement);
        }
    }
}

删除表中id为3和4的数据

public class TestDelete {
    public static void main(String[] args) {
        Connection connection = JDBCUtils.getConnection();
        Statement statement = null;
        try {
            statement = connection.createStatement();
            String sql = "delete from jdbc_user where id in (3, 4);";
            int result = statement.executeUpdate(sql);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(connection, statement);
        }
    }
}

DQL操作

查询姓名为张百万的一条记录

public class TestSelect {
    public static void main(String[] args) throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        Statement statement = connection.createStatement();
        String sql = "select * from jdbc_user where username = '张百万';";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            String password = resultSet.getString("password");
            Date birthday = resultSet.getDate("birthday");
            System.out.println(id + "  " + username + "  " + password + "  " + birthday);
        }
    }
}

SQL注入问题

sql注入案例:用户登陆

  • 需求
    用户在控制台上输入用户名和密码, 然后使用 Statement 字符串拼接的方式 实现用户的登录。
  • 步骤
  1. 得到用户从控制台上输入的用户名和密码来查询数据库
  2. 写一个登录的方法
    a) 通过工具类得到连接
    b) 创建语句对象,使用拼接字符串的方式生成 SQL 语句
    c) 查询数据库,如果有记录则表示登录成功,否则登录失败
    d) 释放资源
public class TestLogin01 {
    public static void main(String[] args) throws SQLException {
        //1.获取连接
        Connection con = JDBCUtils.getConnection();

        //2.获取Statement对象
        Statement statement = con.createStatement();

        //3.获取用户输入的用户名和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名: ");
        String name = sc.nextLine();

        System.out.println("请输入密码: ");
        String pass = sc.nextLine();

        //4.拼接SQL语句
        String sql = "select * from jdbc_user where username = '" + name + "' and password = '" + pass +"'";
        System.out.println(sql);

        //5.执行查询 获取结果集对象
        ResultSet resultSet = statement.executeQuery(sql);

        //6.处理结果集
        if(resultSet.next()){

            System.out.println("登录成功! 欢迎您: " + name);
        }else{

            System.out.println("登录失败! ");
        }
        
        //7.关闭流
        JDBCUtils.close(con,statement,resultSet);
    }
}

当用户输入123’ or ‘1’=’1也是可以登录成功的
我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了 原有SQL 真正的意义,以上问题称为 SQL 注入 .
在这里插入图片描述
要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进 行简单的字符串拼接。

预处理对象

PreparedStatement 接口

  • PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象.
  • 预编译: 是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
  • 因为有预先编译的功能,提高 SQL 的执行效率。
  • 可以有效的防止 SQL 注入的问题,安全性更高
  1. 获通过Connection创建PreparedStatement对象
Connection 接口中的方法说明
PreparedStatement prepareStatement(String sql)指定预编译的 SQL 语句,SQL 语句中使用占位符 ? 创建一个语句对象
  1. PreparedStatement接口常用方法
常用方法说明
int executeUpdate();执行insert update delete语句.
ResultSet executeQuery();执行select语句. 返回结果集对象 Resulet
  1. 使用PreparedStatement的步骤

a.编写 SQL 语句,未知内容使用?占位:

"SELECT * FROM jdbc_user WHERE username=? AND password=?";

b.获得 PreparedStatement 对象
c.设置实际参数:setXxx( 占位符的位置, 真实的值)
d.执行参数化 SQL 语句
e.关闭资源

setXxx重载方法说明
void setDouble(int parameterIndex, double x)将指定参数设置为给定 Java double 值。
void setInt(int parameterIndex, int x)将指定参数设置为给定 Java int 值。
void setString(int parameterIndex, String x)将指定参数设置为给定 Java String 值。
void setObject(int parameterIndex, Object x)使用给定对象设置指定参数的值。
public class TestLogin02 {

    /*
    * SQL注入
    *   用户输入的用户名和密码 与我们编写的SQL进行了拼接,用户输入的内容成为了SQL语法的一部分,
    *   用户会利用这里漏洞 输入一些其他的字符串,改变SQL原有的意思
    *
    * 如果解决
    *   要解决SQL注入 就不能让用户输入的数据和我们的SQL进行直接的拼接
    *
    * 预处理对象 PrepareStatement 他是 Statement接口的子接口
    *   使用预处理对象 他有预编译的功能,提高SQL的执行效率
    *   使用预处理对象 通过占位符的方式 设置参数 可以有效的防止SQL注入
    *
    *
    * */
    public static void main(String[] args) throws SQLException {

        //1.获取连接
        Connection con = JDBCUtils.getConnection();

        //2.获取PrepareStatement 预处理对象
        //使用 ? 占位符的方式来设置参数
        String sql = "select * from jdbc_user where username = ? and password = ?";
        PreparedStatement ps = con.prepareStatement(sql);

        //3.获取用户输入的用户名和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名: ");
        String name = sc.nextLine();

        System.out.println("请输入密码: ");
        String pass = sc.nextLine();

        //4.设置参数 使用setXXX(占位符的位置(整数),要设置的值)的方法设置占位符的参数
        ps.setString(1,name); // 设置第一个问号值 为 name
        ps.setString(2,pass);

        //5.执行查询
        ResultSet resultSet = ps.executeQuery();

        //6.处理结果集
        //6.处理结果集
        if(resultSet.next()){

            System.out.println("登录成功! 欢迎您: " + name);
        }else{

            System.out.println("登录失败! ");
        }

        //7.关闭流
        JDBCUtils.close(con,ps,resultSet);
    }
}

PreparedStatement 执行原理

在这里插入图片描述

Statement 与 PreparedStatement的区别

  1. Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
  2. PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
  3. PrepareStatement可以减少编译次数提高数据库性能。

JDBC 控制事务

事务相关API

方法说明
void setAutoCommit(boolean autoCommit)参数是 true 或 false 如果设置为 false,表示关闭自动提交,相
void commit()提交事务
void rollback()回滚事务

步骤

  1. 获取连接
  2. 开启事务
  3. 获取到 PreparedStatement , 执行两次更新操作
  4. 正常情况下提交事务
  5. 出现异常回滚事务
  6. 最后关闭资源
public class TestJDBCTransaction {

    //使用JDBC操作事务
    public static void main(String[] args) {

        Connection con = null;
        PreparedStatement ps = null;

        try {
            //1.获取连接
            con = JDBCUtils.getConnection();

            //2.开启事务
            con.setAutoCommit(false);  //手动提交事务

            //3.获取预处理对象 执行SQL (两次修改操作)
            //3.1 tom账户 - 500
            ps = con.prepareStatement("update account set money = money - ? where name = ?");
            ps.setDouble(1,500.0);
            ps.setString(2,"tom");
            ps.executeUpdate();

            //模拟 tom转账之后出现异常
            System.out.println(1 / 0);

            //3.2 jack账户 + 500
            ps = con.prepareStatement("update account set money = money + ? where name = ?");
            ps.setDouble(1,500.0);
            ps.setString(2,"jack");
            ps.executeUpdate();

            //4.提交事务 (正常情况)
            con.commit();
            System.out.println("转账成功! !");
        } catch (SQLException e) {
            e.printStackTrace();
            //5.出现异常就回滚事务
            try {
                con.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        } finally {
            //6.释放资源
            JDBCUtils.close(con,ps);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值