zoukankan      html  css  js  c++  java
  • JDBC(上)

    JDBC(上)

    一、JDBC简介

    (一)JDBC定义

     

    简单总结:

    JDBCJava语言与数据库连接的中间件(一座桥梁), 它是一个规范而不是一个实现, 我们可以通过Java代码去实现对数据库中的数据进行增删改查;

     

    JDBC的工作原理:由SUNOracle)提供一套访问数据库的规范(即一组接口),并提供连接数据库的协议标准,这组协议标准称之为JDBC API然后各个数据库厂商会遵循SUNOracle的规范提供一套访问自己公司数据库服务器的程序,称之为数据库驱动。

    JDBC API是接口,而JDBC驱动才是接口的具体实现,没有驱动是无法完成数据库连接操作的。所以每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

     

    JDBC驱动:就是JDBC API的实现类。不同类型的数据库有自己的驱动程序,为了方便使用,已经这个驱动程序打成jar文件,可以直接导入到项目中。

    JDBC驱动和有JDBC驱动的区别:

    JDBC规范:

     

    有JDBC规范:

     

    (二)JDBC常见接口和类

    DriverManager类   驱动管理类   作用: 注册JDBC驱动

    Connection接口    连接对象     作用: 建立与数据库的连接

    Statement接口     SQL编译器   作用: 向数据库发送并执行sql语句

    ResultSet接口      查询的结果集对象   作用: 执行查询操作时, 对返回数据的结果进行的处理

    二、JDBC快速入门

    (一)下载JDBC驱动

    本门课我们以MySQL数据库为例,所以我们需要下载MySQLJDBC驱动程序。

    下载地址:https://dev.mysql.com/downloads/connector/j/5.1.html

    目前常用的MySQL驱动有5.* 版本和  8.*版本,二者在使用时配置上略有不同,大家可以选择其中任意一个版本使用。

     

     

     

    驱动程序下载后解压得到jar文件:

     

     

    (二)JDBC入门案例

    需求: 查询用户表中数据,将用户信息显示在控制台上

    2.1、流程分析

     

    2.2、案例准备

    创建数据库和数据表

    创建项目, 导入环境(数据库驱动)

    1. 创建folder文件, 将驱动包导入

     

    1. 创建folder文件后, 命名为lib

     

    1. 将数据库驱动拷贝到该文件下

     

    1. 右键点击jar, 点击小奶瓶

     

    当出现证明导入成功;

    2.3、案例实现

    package com.ujiuye.jdbc;

    import java.sql.Connection;

    import java.sql.DriverManager;

    import java.sql.ResultSet;

    import java.sql.Statement;

    public class JDBCDemo {

    //程序入口

    //需求: 查询用户表中数据,将用户信息显示在控制台上

    public static void main(String[] args) throws Exception {

    /**

     * JDBC的固定思路实现需要遵循六大步:(高频面试题)

     * 1. 注册驱动

     * 2. 获取连接

     * 3. 创建执行sql语句的连接对象(并定义sql语句)

     * 4. 执行sql语句

     * 5. 处理结果集

     * 6. 释放资源

     */

    //1. 注册驱动

    Class.forName("com.mysql.jdbc.Driver");

    //2. 获取连接

    /**

     * url: 连接地址

     * user: 数据库用户名

     * password: 数据库密码

     */

    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day08_jdbc", "root", "root");

    //3. 创建执行sql语句的连接对象(并定义sql语句)

    Statement st = conn.createStatement();

    //定义sql

    String sql = "select * from user";

    //4. 执行sql语句(返回结果集)

    ResultSet rs = st.executeQuery(sql);

    //5. 处理结果集

    while(rs.next()) {

    int uid = rs.getInt("uid");

    String username = rs.getString("username");

    String password = rs.getString("password");

    System.out.println(uid + " " + username + " " + password);

    }

    //6. 释放资源

    rs.close();

    st.close();

    conn.close();

    }

    }

    三、JDBC的详解

    (一)注册驱动

     

    注册驱动实际上就是把Driver类加载JVM, 并且完成类的初始化工作;

     

    (二)创建连接对象

     

    参数解析:

    DrvierManager 驱动管理器 注册驱动,数据库链接等

    getConnection(url,username,password)

    获取连接

    Url:

    主协议名:子协议名://主机名:端口号/数据库名

    jdbc:   mysql:/  /localhost:3306/  day08_jdbc

    简写:

       jdbc:mysql:///day08_jdbc

    如果在连接字符串后拼接参数, 则需要使用?隔开, 多个参数之间使用&隔开;

    该方法会尝试和数据库进行连接操作。

    测试连接对象是否能够打印出控制台

    能够成功连接数据库,获取Connection对象。连接对象

    (三)创建SQL编译器

     

    (四)执行SQL语句

     

    Statement对象

    executeQuery(String sql)

    执行查询的SQL语句。

    参数:SQL语句

    会把SQL语句传递给mysql数据库去执行

    返回结果:ResultSet对象---一张二维表格

    executeUpdate(String sql)

    执行更新的SQL语句。

    参数:SQL语句

    会把SQL语句传递给mysql数据库去执行

    返回结果:int   SQL语句执行后更新了几行数据

    execute(String sql)(了解)

    执行任意语句。

    参数:SQL语句

    Select,insert into,update,delete from

    执行select 返回true

    执行insert into,update,delete from  返回false

    (五)处理结果集

     

     

     

    (六)释放资源

     

    释放资源: 建议倒叙关闭

    四、单元测试

    JUnit单元测试是为了能够在一个类中创建多个可执行的方法,每个方法都可以独立执行,我们可以将`每个方法理解为一个主函数,一个类里面可以写多个@Test 并且互相不影响,是测试人员和开发者必须掌握的一个小技术。

    关键的注解: @Test  注意: 不要将自己创建的类名设置为Test, 否则会冲突

    使用@Test注释的导入步骤:

     

     

     

     

    测试:(一个类中创建多个单元测试方法)

     

    使用Junit单元测试需要注意事项:

    1. 单元测试的修饰符必须是public
    2. 方法不能有返回值
    3. 方法无参数
    4. 千万千万不要忘记添加@Test注解

    五、JDBC实现CRUD操作

    5.1、从数据库查询所有数据

    详细见入门案例

    5.2向数据库增加数据

     

    5.3向数据库修改数据

     

    5.4、从数据库根据ID删除数据

     

    5.5、从数据库根据ID查询某条数据

     

    5.6  定义一个方法,查询表中的数据将其封装为对象,然后装载集合,返回

     

    六、JDBC工具类封装

    6.1 完成工具类抽取

    package com.ujiuye.utils;

    import java.sql.Connection;

    import java.sql.DriverManager;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.sql.Statement;

    public class JDBCUtils {

    //注册驱动

    static {

    try {

    Class.forName("com.mysql.jdbc.Driver");

    } catch (ClassNotFoundException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    //获取连接

    public static Connection getConnection() {

    try {

    Connection conn = DriverManager.getConnection("jdbc:mysql:///day08_jdbc", "root", "root");

    return conn;

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    return null;

    }

    //释放资源

    public static void closeAll(ResultSet rs, Statement st, Connection conn) {

    //判断

    if(rs != null) {

    try {

    rs.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    if(st != null) {

    try {

    st.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    if(conn != null) {

    try {

    conn.close();

    } catch (SQLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    }

    }

    6.2 使用工具类改写以上CRUD案例

     

    七、PreparedStatement

    (一)使用工具类完成用户登录操作(模拟)

    需求:模拟用户输入账号、密码登录网站

    实现效果:

     

    package com.ujiuye.login;

    import java.sql.Connection;

    import java.sql.ResultSet;

    import java.sql.Statement;

    import java.util.Scanner;

    import com.ujiuye.utils.JDBCUtils;

    public class LoginDemo {

    public static void main(String[] args) throws Exception {

    /**

     * 需求:模拟用户输入账号、密码登录网站

     * 模拟用户登录步骤:

     * 1. 在控制台输入用户名和密码

     * 2. 根据用户名和密码查询数据库, 比对用户名和密码是否正确

     * 3. 如果正确, 证明登录成功, 提示信息: 欢迎您, XXX;

     * 4. 如果错误, 登录失败, 提示信息: 用户名或者密码错误...

     */

    //1. 在控制台输入用户名和密码

    Scanner sc = new Scanner(System.in);

    System.out.println("请输入账号:");

    String username = sc.nextLine();

    System.out.println("请输入密码:");

    String password = sc.nextLine();

    //System.out.println("用户名为" + username + " ==> 密码为: " + password);

    //2. 根据用户名和密码查询数据库, 比对用户名和密码是否正确

    //注册驱动和获取连接

    Connection conn = JDBCUtils.getConnection();

    //System.out.println(conn);

    Statement st = conn.createStatement();

    //定义sql

    String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";

    //执行sql语句

    ResultSet rs = st.executeQuery(sql);

    //处理结果集

    if(rs.next()) {

    //如果正确, 证明登录成功, 提示信息: 欢迎您, XXX;

    String name = rs.getString("username");

    System.out.println("恭喜您登录成功, 欢迎您: " + name);

    }else {

    System.out.println("用户名或者密码错误...");

    }

    }

    }

    成功效果:

     

    通过以上效果, 发现也会登录成功, 这种登录成功会出现sql注入问题;

    为什么会出现sql注入问题?

    当我们使用statement接口时, 会将控制台输入的字符串与sql语句进行一个拼接, 拼接时把字符串中的or当成了逻辑运算符进行判断, 此时 or后边跟的1=1, 恒为真(true), 所以就失去了验证用户名和密码的功能了;

    解决sql注入的问题:

    使用预处理对象(PreparedStatement )解决sql注入问题;

    StatementPreparedStatement 区别:(面试题)

    1. 使用PreparedStatement 对象虽然比Statement代码多写几行, 但是代码的可读性和维护性更好;
    2. PreparedStatement 对象比Statement对象执行效率要高;
    3. PreparedStatement 对象能够解决SQL注入问题, 安全性较高;

    (二)PreparedStatement 解决SQL注入问题

    PreparedStatement是位于java.sql包中的接口,是Statement接口的子接口。PreparedStatement对象会将SQL语句进行预编译,通过?占位符的方式进行SQL语句参数的拼接,这样就避免将字符中的内容当成SQL关键字参与编译执行,从而解决SQL注入问题。

    PreparedSatement的执行原理

    我们写的SQL语句让数据库执行,数据库不是直接执行SQL语句字符串。和Java一样,数据库需要执行编译后的SQL语句(类似Java编译后的字节码文件)。

    1Statement 对象每执行一条SQL语句都会先将这条SQL语句发送给数据库编译,数据库再执行。

     

    上面2SQL语句我们可以看到大部分内容是相同的,只是数据略有不一样。数据库每次执行都编译一次。

    如果有1万条类似的SQL语句,数据库需要编译1万次,执行1万次,显然效率就低了

    2prepareStatement() 会先将SQL语句发送给数据库预编译。 PreparedStatement 会引用着预编译后的结果。

    可以多次传入不同的参数给 PreparedStatement 对象并执行。相当于调用方法多次传入不同的参数。

     

    以上?代表 占位符

    上面预编译好一条SQL2次传入了不同的参数并执行。如果有1万条类似的插入数据的语句。数据库只需要预编译一次,传入1万次不同的参数并执行。减少了SQL语句的编译次数,提高了执行效率。

    PreparedStatement常见方法的使用:

    setInt(int index,int value)

    为?占位符,赋予int

    setString(int index,String value)

    为?占位符,赋予String

    executeQuery()

    执行查询的SQL语句。

    会把SQL语句传递给mysql数据库去执行

    返回结果:ResultSet对象---一张二维表格

    executeUpdate()

    执行更新的SQL语句。

    会把SQL语句传递给mysql数据库去执行

    返回结果:int   SQL语句执行后更新了几行数据

     

    (三)PreparedStatementCRUD操作

     

     

     

     

     

     

     

  • 相关阅读:
    解题:AHOI 2005 航线规划
    解题:SCOI 2008 天平
    解题:SCOI 2014 方伯伯运椰子
    解题:APIO 2008 免费道路
    解题:USACO15JAN Grass Cownoisseur
    669. 换硬币(dp动态规划)
    8. 旋转字符串
    147. 水仙花数
    1131. 排列中的函数
    78. 最长公共前缀
  • 原文地址:https://www.cnblogs.com/masterhxh/p/13679938.html
Copyright © 2011-2022 走看看