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 + "\t" + username + "\t" + 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操作

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-09-16 16:40  master_hxh  阅读(135)  评论(0编辑  收藏  举报