JDBC 概述

客户端操作数据库的方式

方式1: 使用第三方客户端来访问 MySQL:SQLyog
任务一_JDBC - 图1
方式2: 使用命令行

任务一_JDBC - 图2

3) 我们今天要学习的是通过 Java程序 来访问 MySQL 数据库

什么是JDBC

JDBC( Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范.

JDBC 原理

JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

任务一_JDBC - 图3

总结:
JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。

JDBC 开发

数据准备

  1. -- 创建 jdbc_user
  2. CREATE TABLE jdbc_user (
  3. id INT PRIMARY KEY AUTO_INCREMENT ,
  4. username VARCHAR(50), PASSWORD VARCHAR(50),
  5. birthday DATE
  6. );
  1. -- 添加数据
  2. INSERT INTO jdbc_user (username, PASSWORD,birthday) VALUES('admin1', '123','1991/12/24'),
  3. ('admin2','123','1995/12/24'),
  4. ('test1', '123','1998/12/24'),
  5. ('test2', '123','2000/12/24');

MySql驱动包

  1. 将MySQL驱动包添加到jar包库文件夹中,Myjar文件夹,用于存放当前项目需要的所有jar包

任务一_JDBC - 图4

  1. 任务一_JDBC - 图5在 idea中 配置jar包库的位置

  2. 创建一个新的项目jdbc_task01, 配置jar包库

任务一_JDBC - 图6

任务一_JDBC - 图7

API使用: 1.注册驱动

JDBC规范定义驱动接口: java.sql.Driver
MySql驱动包提供了实现类:
com.mysql.jdbc.Driver

加载注册驱动的方式 描述
Class.forName(数据库驱动实现类) 加载和注册数据库驱动,数据库驱动由数据库厂商MySql提供
“com.mysql.jdbc.Driver”

代码示例

  1. public class JDBCDemo01 {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. //1.注册驱动
  4. // forName 方法执行将类进行初始化
  5. Class.forName("com.mysql.jdbc.Driver");
  6. }
  7. }

为什么这样可以注册驱动?

我们知道 Class类的forName方法 ,可以将一个类初始化, 现在我们一起Driver类的 看一下源码

  1. // Driver类是MySql提供的数据库驱动类, 实现了JDBC的Driver接口 java.sql.Driver
  2. public class Driver extends NonRegisteringDriver implements java.sql.Driver {
  3. // 空参构造
  4. public Driver() throws SQLException {
  5. }
  6. //静态代码块,Class类的 forName()方法将Driver类 加载到内存, static代码块会自动执行
  7. static {
  8. try {
  9. /*
  10. DriverManager 驱动管理类registerDriver(new Driver) 注册驱动的方法注册数据库驱动
  11. */
  12. DriverManager.registerDriver(new Driver());
  13. } catch (SQLException var1) {
  14. throw new RuntimeException("Can't register driver!");
  15. }
  16. }
  17. }

注:

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

API使用: 2.获得连接

Connection 接口,代表一个连接对象 ,具体的实现类由数据库的厂商实现使用 DriverManager类的静态方法,getConnection可以获取数据库的连接

获取连接的静态方法 说明
Connection getConnection(String url, String user, String password) 通过连接字符串和用户名,密码来获取数据库连接对象

getConnection方法 3个 连接参数说明

连接参数 说明
user 登录用户名
password 登录密码
url mySql URL的格式jdbc:mysql://localhost:3306/db4

对URL的详细说明

  1. jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8

JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。 第一部分是协议 jdbc,这是固定的;
第二部分是子协议,就是数据库名称,连接mysql数据库,第二部分当然是mysql了;
第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及要使用的 数据库名称 组成。
任务一_JDBC - 图8

  1. 代码示例
    1. public class JDBCDemo02 {
    2. public static void main(String[] args) throws Exception {
    3. //1.注册驱动Class.forName("com.mysql.jdbc.Driver");
    4. //2.获取连接 url,用户名, 密码
    5. String url = "jdbc:mysql://localhost:3306/db4";
    6. Connection con = DriverManager.getConnection(url, "root", "123456");
    7. //com.mysql.jdbc.JDBC4Connection@2e3fc542 System.out.println(con);
    8. }
    9. }

    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结果集对象

代码示例

  1. public class JDBCDemo03 {
  2. public static void main(String[] args) throws Exception {
  3. //1.注册驱动
  4. Class.forName("com.mysql.jdbc.Driver");
  5. //2.获取连接 url,用户名, 密码
  6. String url = "jdbc:mysql://localhost:3306/db4";
  7. Connection con = DriverManager.getConnection(url, "root", "123456");
  8. //3.获取 Statement对象
  9. Statement statement = con.createStatement();
  10. //4.执行创建表操作
  11. String sql = "create table test01(id int, name varchar(20),age int);";
  12. //5.增删改操作 使用executeUpdate,增加一张表
  13. int i = statement.executeUpdate(sql);
  14. //6.返回值是受影响的函数
  15. System.out.println(i);
  16. //7.关闭流
  17. statement.close();
  18. con.close();
  19. }
  20. }

API 使用: 4.处理结果集

只有在进行查询操作的时候, 才会处理结果集代码示例

  1. public class JDBCDemo04 {
  2. public static void main(String[] args) throws SQLException {
  3. //1.注册驱动 可以省略
  4. //2.获取连接
  5. String url = "jdbc:mysql://localhost:3306/db4";
  6. Connection con = DriverManager.getConnection(url, "root", "123456");
  7. //3.获取 Statement对象
  8. Statement statement = con.createStatement();
  9. String sql = "select * from jdbc_user";
  10. //执行查询操作,返回的是一个 ResultSet 结果对象
  11. ResultSet resultSet = statement.executeQuery(sql);
  12. //4.处理结果集 resultSet
  13. }
  14. }

ResultSet接口

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

ResultSet接口方法 说明


boolean next()

1. 游标向下一行
1. 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false


xxx getXxx( String or int)

1. 通过列名,参数是 String 类型。返回不同的类型
1. 通过列号,参数是整数,从 1 开始。返回不同的类型

任务一_JDBC - 图9

代码示例

  1. public class JDBCDemo04 {
  2. public static void main(String[] args) throws SQLException {
  3. //1.注册驱动 可以省略
  4. //2.获取连接
  5. String url = "jdbc:mysql://localhost:3306/db4";
  6. Connection con = DriverManager.getConnection(url, "root", "123456");
  7. //3.获取 Statement对象
  8. Statement statement = con.createStatement();
  9. String sql = "select * from jdbc_user";
  10. //执行查询操作,返回的是一个 ResultSet 结果对象
  11. ResultSet resultSet = statement.executeQuery(sql);
  12. //4.处理结果集
  13. //next 方法判断是否还有下一条数据
  14. //boolean next = resultSet.next(); System.out.println(next);
  15. //getXXX 方法获取数据 两种方式
  16. //int id = resultSet.getInt("id");//列名
  17. //System.out.println(id);
  18. //int anInt = resultSet.getInt(1);//列号
  19. //System.out.println(anInt);
  20. //使用while循环
  21. while(resultSet.next()){
  22. //获取id
  23. int id = resultSet.getInt("id");
  24. //获取姓名
  25. String username = resultSet.getString("username");
  26. //获取生日
  27. Date birthday = resultSet.getDate("birthday");
  28. System.out.println(id + " = " +username + " : " + birthday);
  29. }
  30. //关闭连接
  31. resultSet.close();
  32. statement.close();
  33. con.close();
  34. }
  35. }

API 使用: 5.释放资源

  1. 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
  2. 释放原则:先开的后关,后开的先关。ResultSet ==> Statement ==> Connection
  3. 放在哪个代码块中:finally 块

与IO流一样,使用后的东西都需要关闭!关闭的顺序是先开后关, 先得到的后关闭,后得到的先关闭
任务一_JDBC - 图10
代码示例

  1. public class JDBCDemo05 {
  2. public static void main(String[] args) {
  3. Connection connection = null;
  4. Statement statement = null;
  5. ResultSet resultSet = null;
  6. try {
  7. //1.注册驱动(省略)
  8. //2.获取连接
  9. String url = "jdbc:mysql://localhost:3306/db4";
  10. connection = DriverManager.getConnection(url, "root", "123456");
  11. //3.获取 Statement对象
  12. statement = connection.createStatement();
  13. String sql = "select * from jdbc_user";
  14. resultSet = statement.executeQuery(sql);
  15. } catch (SQLException e) {
  16. e.printStackTrace();
  17. } finally {
  18. /**
  19. • 开启顺序: connection ==> statement => resultSet
  20. • 关闭顺序: resultSet ==> statement ==> connection
  21. */
  22. try {
  23. connection.close();
  24. resultSet.close();
  25. statement.close();
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }

步骤总结

  1. 获取驱动(可以省略)
  2. 获取连接
  3. 获取Statement对象
  4. 处理结果集(只在查询时处理)
  5. 释放资源

    JDBC实现增删改查

    JDBC工具类

    什么时候自己创建工具类?
    如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
    “获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
    工具类包含的内容

    1. 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
    2. 得到数据库的连接:getConnection()
    3. 关闭所有打开的资源:

代码示例

  1. package com.lagou.utils;
  2. import java.sql.*;
  3. /**
  4. * JDBC工具类
  5. */
  6. public class JDBCUtils {
  7. //1. 将连接信息定义为 字符串常量
  8. public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
  9. public static final String URL = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
  10. public static final String USER = "root";
  11. public static final String PASSWORD = "123456";
  12. //2.静态代码块
  13. static{
  14. try {
  15. //1.注册驱动
  16. Class.forName(DRIVERNAME);
  17. } catch (ClassNotFoundException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. //3.获取连接的 静态方法
  22. public static Connection getConnection(){
  23. try {
  24. //获取连接对象 并返回
  25. Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
  26. return connection;
  27. } catch (SQLException e) {
  28. e.printStackTrace();
  29. return null;
  30. }
  31. }
  32. //4.关闭资源的方法
  33. public static void close(Connection con, Statement statement){
  34. if(con != null && statement != null){
  35. try {
  36. statement.close();
  37. con.close();
  38. } catch (SQLException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. }
  43. public static void close(Connection con, Statement statement, ResultSet resultSet){
  44. if(con != null && statement != null){
  45. try {
  46. resultSet.close();
  47. statement.close();
  48. con.close();
  49. } catch (SQLException e) {
  50. e.printStackTrace();
  51. }
  52. }
  53. }
  54. }

DML操作

插入记录

解决插入中文乱码问题.
jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8 characterEncoding=UTF-8 指定字符的编码、解码格式。

代码示例

  1. package com.lagou.jdbc02;
  2. import com.lagou.utils.JDBCUtils;
  3. import org.junit.Test;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. public class TestDML {
  8. /*
  9. * 插入数据
  10. * */
  11. @Test
  12. public void testInsert() throws SQLException {
  13. //1.通过JDBCUtils工具类 获取连接
  14. Connection con = JDBCUtils.getConnection();
  15. //2.获取Statement对象
  16. Statement statement = con.createStatement();
  17. //2.1 编写SQL
  18. String sql = "insert into jdbc_user values(null,'张百万','123','2020/11/11')";
  19. //2.2 执行SQL
  20. int i = statement.executeUpdate(sql);
  21. System.out.println(i);
  22. //3.关闭流
  23. JDBCUtils.close(con,statement);
  24. }
  25. /*
  26. * 更新操作 根据id修改用户名
  27. * */
  28. @Test
  29. public void testUpdate() throws SQLException {
  30. Connection connection = JDBCUtils.getConnection();
  31. Statement statement = connection.createStatement();
  32. String sql = "update jdbc_user set username = '刘能' where id = 1";
  33. statement.executeUpdate(sql);
  34. JDBCUtils.close(connection,statement);
  35. }
  36. /*
  37. * 删除操作
  38. * 删除 id为 1 和 2 的数据
  39. *
  40. * */
  41. @Test
  42. public void testDelete() throws SQLException {
  43. Connection connection = JDBCUtils.getConnection();
  44. Statement statement = connection.createStatement();
  45. String sql = "delete from jdbc_user where id in(1,2)";
  46. statement.executeUpdate(sql);
  47. JDBCUtils.close(connection,statement);
  48. }
  49. }
  1. /*
  2. * 插入数据
  3. * */
  4. @Test
  5. public void testInsert() throws SQLException {
  6. //1.通过JDBCUtils工具类 获取连接
  7. Connection con = JDBCUtils.getConnection();
  8. //2.获取Statement对象
  9. Statement statement = con.createStatement();
  10. //2.1 编写SQL
  11. String sql = "insert into jdbc_user values(null,'张百万','123','2020/11/11')";
  12. //2.2 执行SQL
  13. int i = statement.executeUpdate(sql);
  14. System.out.println(i);
  15. //3.关闭流
  16. JDBCUtils.close(con,statement);
  17. }

更新记录

根据ID 需改用户名称

  1. /*
  2. * 更新操作 根据id修改用户名
  3. * */
  4. @Test
  5. public void testUpdate() throws SQLException {
  6. Connection connection = JDBCUtils.getConnection();
  7. Statement statement = connection.createStatement();
  8. String sql = "update jdbc_user set username = '刘能' where id = 1";
  9. statement.executeUpdate(sql);
  10. JDBCUtils.close(connection,statement);
  11. }

删除记录

删除id为 3 和 4 的记录

  1. /*
  2. * 删除操作
  3. * 删除 id为 1 和 2 的数据
  4. *
  5. * */
  6. @Test
  7. public void testDelete() throws SQLException {
  8. Connection connection = JDBCUtils.getConnection();
  9. Statement statement = connection.createStatement();
  10. String sql = "delete from jdbc_user where id in(1,2)";
  11. statement.executeUpdate(sql);
  12. JDBCUtils.close(connection,statement);
  13. }

DQL操作

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

  1. package com.lagou.jdbc02;
  2. import com.lagou.utils.JDBCUtils;
  3. import java.sql.*;
  4. public class TestDQL {
  5. // 查询姓名为张百万的一条记录
  6. public static void main(String[] args) throws SQLException {
  7. //1.获取连接
  8. Connection connection = JDBCUtils.getConnection();
  9. //2.创建Statement对象
  10. Statement statement = connection.createStatement();
  11. //3. 编写SQL
  12. String sql = "select * from jdbc_user where username = '张百万'";
  13. ResultSet resultSet = statement.executeQuery(sql);
  14. //4.处理结果集
  15. while(resultSet.next()){
  16. // 通过列名的方式获取
  17. int id = resultSet.getInt("id");
  18. String username = resultSet.getString("username");
  19. String password = resultSet.getString("password");
  20. Date birthday = resultSet.getDate("birthday");
  21. System.out.println(id + " : " + username + " : " + password + " : " + birthday );
  22. }
  23. //5.释放资源
  24. JDBCUtils.close(connection,statement,resultSet);
  25. }
  26. }

SQL注入问题

Sql注入演示

  1. 向jdbc_user表中 插入两条数据

    1. # 插入2条数据
    2. INSERT INTO jdbc_user VALUES(NULL,'jack','123456','2020/2/24');
    3. INSERT INTO jdbc_user VALUES(NULL,'tom','123456','2020/2/24');
  2. SQL注入演示

    1. # SQL注入演示
    2. -- 填写一个错误的密码
    3. SELECT * FROM jdbc_user WHERE username = 'tom' AND PASSWORD = '123' OR '1' = '1';

    如果这是一个登陆操作,那么用户就登陆成功了.显然这不是我们想要看到的结果

    sql注入案例:用户登陆

    需求
    用户在控制台上输入用户名和密码, 然后使用 Statement 字符串拼接的方式 实现用户的登录。
    步骤

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

Sql注入方式: 123’ or ‘1’=’1

代码示例

  1. package com.lagou.jdbc03;
  2. import com.lagou.utils.JDBCUtils;
  3. import java.sql.Connection;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. import java.util.Scanner;
  8. public class TestLogin01 {
  9. /**
  10. * 用户登录案例
  11. * @param args
  12. */
  13. public static void main(String[] args) throws SQLException {
  14. //1.获取连接
  15. Connection con = JDBCUtils.getConnection();
  16. //2.获取Statement对象
  17. Statement statement = con.createStatement();
  18. //3.获取用户输入的用户名和密码
  19. Scanner sc = new Scanner(System.in);
  20. System.out.println("请输入用户名: ");
  21. String name = sc.nextLine();
  22. System.out.println("请输入密码: ");
  23. String pass = sc.nextLine();
  24. //4.拼接SQL语句
  25. String sql = "select * from jdbc_user where username = '" + name + "' and password = '" + pass +"'";
  26. System.out.println(sql);
  27. //5.执行查询 获取结果集对象
  28. ResultSet resultSet = statement.executeQuery(sql);
  29. //6.处理结果集
  30. if(resultSet.next()){
  31. System.out.println("登录成功! 欢迎您: " + name);
  32. }else{
  33. System.out.println("登录失败! ");
  34. }
  35. //7.关闭流
  36. JDBCUtils.close(con,statement,resultSet);
  37. }
  38. }

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

如何实现的注入
根据用户输入的数据,拼接处的字符串
任务一_JDBC - 图11

select * from jdbc_user where username = ‘abc’ and password = ‘abc’ or ‘1’=’1’

name=’abc’ and password=’abc’ 为 假 ‘1’=’1’ 真

相当于 select * from user where true=true; 查询了所有记录

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

预处理对象

PreparedStatement 接口介绍

PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象.
预编译: 是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

PreparedStatement 特 点

因为有预先编译的功能,提高 SQL 的执行效率。可以有效的防止 SQL 注入的问题,安全性更高

获取PreparedStatement对象

通过Connection创建PreparedStatement对象

Connection 接口中的方法 说明


PreparedStatement prepareStatement(String sql)
指定预编译的 SQL 语句,
SQL 语句中使用占位符 ? 创建一个语句对象

PreparedStatement接口常用方法

常用方法 说明
int executeUpdate(); 执行insert update delete语句.
ResultSet executeQuery(); 执行select语句. 返回结果集对象 Resulet
  1. 使用PreparedStatement的步骤
    1. 编写 SQL 语句,未知内容使用?占位:

“SELECT * FROM jdbc_user WHERE username=? AND password=?”;

  1. 获得 PreparedStatement 对象 3) 设置实际参数:setXxx( 占位符的位置, 真实的值) 4) 执行参数化 SQL 语句 5)

关闭资源

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) 使用给定对象设置指定参数的值。

使用PreparedStatement完成登录案例

使用 PreparedStatement 预处理对象,可以有效的避免SQL注入
任务一_JDBC - 图12

步骤:
1.获取数据库连接对象
2.编写SQL 使用? 占位符方式
3.获取预处理对象 (预编译对象会将Sql发送给数据库 进行预编译)
4.提示用户输入用户名 & 密码
5.设置实际参数:setXxx(占位符的位置, 真实的值)
6.执行查询获取结果集
7.判断是否查询到数据
8.关闭资源

  1. package com.lagou.jdbc03;
  2. import com.lagou.utils.JDBCUtils;
  3. import java.sql.*;
  4. import java.util.Scanner;
  5. public class TestLogin02 {
  6. /*
  7. * SQL注入
  8. * 用户输入的用户名和密码 与我们编写的SQL进行了拼接,用户输入的内容成为了SQL语法的一部分,
  9. * 用户会利用这里漏洞 输入一些其他的字符串,改变SQL原有的意思
  10. *
  11. * 如果解决
  12. * 要解决SQL注入 就不能让用户输入的数据和我们的SQL进行直接的拼接
  13. *
  14. * 预处理对象 PrepareStatement 他是 Statement接口的子接口
  15. * 使用预处理对象 他有预编译的功能,提高SQL的执行效率
  16. * 使用预处理对象 通过占位符的方式 设置参数 可以有效的防止SQL注入
  17. *
  18. *
  19. * */
  20. public static void main(String[] args) throws SQLException {
  21. //1.获取连接
  22. Connection con = JDBCUtils.getConnection();
  23. //2.获取PrepareStatement 预处理对象
  24. //使用 ? 占位符的方式来设置参数
  25. String sql = "select * from jdbc_user where username = ? and password = ?";
  26. PreparedStatement ps = con.prepareStatement(sql);
  27. //3.获取用户输入的用户名和密码
  28. Scanner sc = new Scanner(System.in);
  29. System.out.println("请输入用户名: ");
  30. String name = sc.nextLine();
  31. System.out.println("请输入密码: ");
  32. String pass = sc.nextLine();
  33. //4.设置参数 使用setXXX(占位符的位置(整数),要设置的值)的方法设置占位符的参数
  34. ps.setString(1,name); // 设置第一个问号值 为 name
  35. ps.setString(2,pass);
  36. //5.执行查询
  37. ResultSet resultSet = ps.executeQuery();
  38. //6.处理结果集
  39. //6.处理结果集
  40. if(resultSet.next()){
  41. System.out.println("登录成功! 欢迎您: " + name);
  42. }else{
  43. System.out.println("登录失败! ");
  44. }
  45. //7.关闭流
  46. JDBCUtils.close(con,ps,resultSet);
  47. }
  48. }

PreparedStatement的执行原理

分别使用 Statement对象 和 PreparedStatement对象进行插入操作代码示例

  1. package com.lagou.jdbc03;
  2. import com.lagou.utils.JDBCUtils;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. public class TestPS {
  8. public static void main(String[] args) throws SQLException {
  9. Connection connection = JDBCUtils.getConnection();
  10. //获取Statement
  11. Statement statement = connection.createStatement();
  12. //向数据库插入两条数据
  13. statement.executeUpdate("insert into jdbc_user values(null,'张三','123456','2000/12/26')");
  14. statement.executeUpdate("insert into jdbc_user values(null,'李四','654321','1900/12/26')");
  15. //获取预处理对象
  16. PreparedStatement ps = connection.prepareStatement("insert into jdbc_user values(?,?,?,?)");
  17. //先插入第一条数据
  18. ps.setObject(1,null);
  19. ps.setString(2,"小斌");
  20. ps.setString(3,"qwer");
  21. ps.setString(4,"1999/11/11");
  22. //执行插入
  23. ps.executeUpdate();
  24. //插入第二条数据
  25. ps.setObject(1,null);
  26. ps.setString(2,"长海");
  27. ps.setString(3,"asdf");
  28. ps.setString(4,"2000/11/11");
  29. //执行插入
  30. ps.executeUpdate();
  31. //释放资源
  32. statement.close();
  33. ps.close();
  34. connection.close();
  35. }
  36. }

任务一_JDBC - 图13

Statement 与 PreparedStatement的区别?

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

    JDBC 控制事务

    之前我们是使用 MySQL 的命令来操作事务。接下来我们使用 JDBC 来操作银行转账的事务。

    数据准备

    1. -- 创建账户表
    2. CREATE TABLE account(
    3. --
    4. id INT PRIMARY KEY AUTO_INCREMENT,
    5. --
    6. NAME VARCHAR(10),
    7. -- 转账金额
    8. money DOUBLE
    9. );
    10. -- 添加两个用户
    11. INSERT INTO account (NAME, money) VALUES ('tom', 1000), ('jack', 1000);

事务相关API
我们使用 Connection中的方法实现事务管理

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

开发步骤

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

    代码示例

    ```java package com.lagou.jdbc04;

import com.lagou.utils.JDBCUtils;

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

public class TestJDBCTransaction {

  1. //使用JDBC操作事务
  2. public static void main(String[] args) {
  3. Connection con = null;
  4. PreparedStatement ps = null;
  5. try {
  6. //1.获取连接
  7. con = JDBCUtils.getConnection();
  8. //2.开启事务
  9. con.setAutoCommit(false); //手动提交事务
  10. //3.获取预处理对象 执行SQL (两次修改操作)
  11. //3.1 tom账户 - 500
  12. ps = con.prepareStatement("update account set money = money - ? where name = ?");
  13. ps.setDouble(1,500.0);
  14. ps.setString(2,"tom");
  15. ps.executeUpdate();
  16. //模拟 tom转账之后出现异常
  17. System.out.println(1 / 0);
  18. //3.2 jack账户 + 500
  19. ps = con.prepareStatement("update account set money = money + ? where name = ?");
  20. ps.setDouble(1,500.0);
  21. ps.setString(2,"jack");
  22. ps.executeUpdate();
  23. //4.提交事务 (正常情况)
  24. con.commit();
  25. System.out.println("转账成功! !");
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. //5.出现异常就回滚事务
  29. try {
  30. con.rollback();
  31. } catch (SQLException ex) {
  32. ex.printStackTrace();
  33. }
  34. } finally {
  35. //6.释放资源
  36. JDBCUtils.close(con,ps);
  37. }
  38. }

} ```