JDBC技术和XML-JDBC

JDBC概述

什么是JDBC

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

JDBC原理

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

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

JDBC开发

API使用: 1.注册驱动

  • JDBC规范定义驱动接口: java.sql.Driver
  • MySql驱动包提供了实现类: com.mysql.jdbc.Driver
加载注册驱动的方式 描述
Class.forName(数据库驱动实现类) 加载和注册数据库驱动,数据库驱动由数据库厂商MySql提供”com.mysql.jdbc.Driver”
  • 代码示例
public class JDBCDemo01 { 
    public static void main(String[] args) throws ClassNotFoundException { 
        //1.注册驱动 
        // forName 方法执行将类进行初始化 
        Class.forName("com.mysql.jdbc.Driver"); 
    } 
}
复制代码
  • 注:
    JDBC3开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。 Class.forName这句话可以省略。

API使用: 2.获得连接

  • Connection接口,代表一个连接对象,具体的实现类由数据库的厂商实现
  • 使用DriverManager类的静态方法,getConnection可以获取数据库的连接
获取连接的静态方法 说明
Connection getConnection(String url, String user, String password) 通过连接字符串和用户名,密码来获取数据库连接对象
  • 1) getConnection方法3个连接参数说明
连接参数 说明
user 登录用户名
password 登录密码
url mySql URL的格式
jdbc:mysql://localhost:3306/db4
  • 2) 对URL的详细说明

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

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

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

API 使用: 4.处理结果集

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

ResultSet接口

  • 作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
ResultSet接口方法 说明
boolean next() 1) 游标向下一行
2) 返回boolean类型,如果还有下一条记录,返回true,否则返回 false
xxx getXxx( String or int) 1) 通过列名,参数是String类型。返回不同的类型
2) 通过列号,参数是整数,从1开始。返回不同的类型

API 使用: 5.释放资源

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

  • 与IO流一样,使用后的东西都需要关闭!关闭的顺序是先开后关, 先得到的后关闭,后得到的先关闭

步骤总结

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

JDBC实现增删改查

JDBC工具类

  • 什么时候自己创建工具类?
    • 如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
    • “获得数据库连接”操作,将在以后的增删改查所有功能中都存在,可以封装工具类JDBCUtils。提供获取连接对象的方法,从而达到代码的重复利用。
  • 工具类包含的内容
      1. 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
      1. 得到数据库的连接:getConnection()
      1. 关闭所有打开的资源:

DML操作

插入记录

  • 解决插入中文乱码问题
// jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8 
// characterEncoding=UTF-8 指定字符的编码、解码格式。
复制代码
  • 代码示例
/** 
* 插入数据 
* @throws SQLException 
*/ 
@Test 
public void testInsert() throws SQLException { 

    //1.通过工具类获取连接 
    Connection connection = JDBCUtils.getConnection(); 
    
    //2.获取Statement 
    Statement statement = connection.createStatement(); 
    
    //2.1 编写Sql
    String sql = "insert into jdbc_user values(null,'张百万','123','2020/1/1')"; 
    
    //2.2 执行Sql 
    int i = statement.executeUpdate(sql); 
    System.out.println(i); 
    
    //3.关闭流 
    JDBCUtils.close(connection,statement); 
}
复制代码

更新记录

  • 根据ID需改用户名称
/**
* 修改 id 为1 的用户名为 广坤 
*/ 
@Test 
public void testUpdate() throws SQLException { 

    Connection connection = JDBCUtils.getConnection(); 

    Statement statement = connection.createStatement(); 

    String sql = "update jdbc_user set username = '广坤' where id = 1"; 
    statement.executeUpdate(sql); 

    JDBCUtils.close(connection,statement); 
}
复制代码

删除记录

  • 删除id为3和4的记录
/**
* 删除id 为 3 和 4的记录 
* @throws SQLException 
*/ 
@Test 
public void testDelete() throws SQLException { 

    Connection connection = JDBCUtils.getConnection(); 

    Statement statement = connection.createStatement(); 
    statement.executeUpdate("delete from jdbc_user where id in(3,4)"); 

    JDBCUtils.close(connection,statement); 
}
复制代码

DQL操作

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

public class TestJDBC02 { 
    public static void main(String[] args) throws SQLException { 

        //1.获取连接对象 
        Connection connection = JDBCUtils.getConnection(); 
    
        //2.获取Statement对象 
        Statement statement = connection.createStatement(); 
    
        String sql = "SELECT * FROM jdbc_user WHERE username = '张百万';"; 
        ResultSet resultSet = statement.executeQuery(sql); 
    
        //3.处理结果集 
        while(resultSet.next()){ 
            //通过列名 获取字段信息 
            int id = resultSet.getInt("id"); 
            String username = resultSet.getString("username"); 
            String password = resultSet.getString("password"); 
            String birthday = resultSet.getString("birthday"); 
        
            System.out.println(id+" "+username+" " + password +" " + birthday); 
         }
     
         //4.释放资源 
         JDBCUtils.close(connection,statement,resultSet); 
    } 
}
复制代码

SQL注入问题

Sql注入演示

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

# 插入2条数据 
INSERT INTO jdbc_user VALUES(NULL,'jack','123456','2020/2/24'); 
INSERT INTO jdbc_user VALUES(NULL,'tom','123456','2020/2/24');
复制代码

2) SQL注入演示

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

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

问题分析

什么是SQL注入?

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

如何实现的注入

  • 根据用户输入的数据,拼接处的字符串
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

使用PreparedStatement的步骤

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

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

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

Statement 与 PreparedStatement的区别?

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

JDBC 控制事务

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

事务相关API

  • 我们使用Connection中的方法实现事务管理
方法 说明
void setAutoCommit(boolean autoCommit) 参数是true或false如果设置为false,表示关闭自动提交,相当于开启事务
void commit() 提交事务
void rollback() 回滚事务

开发步骤

  1. 获取连接
  2. 开启事务
  3. 获取到 PreparedStatement , 执行两次更新操作
  4. 正常情况下提交事务
  5. 出现异常回滚事务
  6. 最后关闭资源
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享