JavaWeb - JDBC操作数据库基本操作和API详解

JDBC

JDBC基本操作

JDBC概念:

JDBC: 就是使用Java语言操作关系型数据库的一套API

全称:( Java DataBase Connectivity ) Java 数据库连接

JDBC本质:

官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口

各个数据库厂商去实现这套接口,提供数据库驱动jar包, 而各个数据库厂商的实现类又有一个比较"洋气"的名字, 叫做驱动

我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

在这里插入图片描述

JDBC好处:

各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发

可随时替换底层数据库,访问数据库的Java代码基本不变

Java操作数据库的步骤如下:

  1. 创建工程,导入驱动jar包(数据库厂商针对JDBC编写的实现类)
  2. 注册驱动(名称是固定的)
Class.forName("com.mysql.jdbc.Driver");
  1. 获取连接
Connection conn = DriverManager.getConnection(url, username, password);
  1. 定义SQL语句
String sql =  “update…” ;
  1. 执行SQL语句
Statement stmt = conn.createStatement();
  1. 执行SQL
stmt.executeUpdate(sql);
  1. 处理返回结果
  2. 释放资源

基本演示代码(了解, 下面会详细讲解API):

public static void main(String[] args) throws Exception {
    
    
    // 1. 注册驱动(com.mysql.jdbc.Driver是固定的)
    Class.forName("com.mysql.jdbc.Driver");

    // 2. 获取连接
    String url = "jdbc:mysql://127.0.0.1:3306/db1";
    String username = "root";
    String password = "123456789";
    Connection conn = DriverManager.getConnection(url, username, password);

    // 3. 定义sql语句
    String sql = "UPDATE account SET money = 2000 WHERE id = 1";

    // 4. 获取sql执行的对象
    Statement stmt = conn.createStatement();

    // 5. 执行sql
    int count = stmt.executeUpdate(sql); // 返回受影响的行数

    // 6. 处理返回结果
    System.out.println(count); // 1

    // 7. 释放资源
    stmt.close();
    conn.close();
}

JDBC API详解

DriverManager

DriverManager(驱动管理类)作用:

1.注册驱动

2.获取数据库连接

作用一: 注册驱动

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

注册驱动是通过Driver类, 查看Driver类源码可以发现, 源码中有一个静态代码块, 里面通过DriverManager类的方法注册驱动

static {
    
    
    try {
    
    
        DriverManager.registerDriver(new Driver());
    } catch (SQLException var1) {
    
    
        throw new RuntimeException("Can't register driver!");
    }
}

提示:

MySQL 5之后的驱动包,可以省略注册驱动的步骤

自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类

作用二: 获取连接

通过getConnection方法

Connection conn = DriverManager.getConnection(url, username, password);

getConnection方法有三个参数:

  • url: 要连接数据库的路径
  • user: 数据库的用户名
  • password: 数据库的密码

参数url的注意事项:

url连接路径的语法: jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…

例如链接本地数据库db1: jdbc:mysql://127.0.0.1:3306/db1

细节:

  • 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
  • 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示

Connection

Connection(数据库连接对象)作用

1.获取执行 SQL 的对象

2.管理事务

作用一: 获取执行 SQL 的对象

普通执行SQL对象: Statement createStatement()

预编译SQL的执行SQL对象, 防止SQL注入: PreparedStatement prepareStatement (sql)

执行存储过程的对象: 执行存储过程的对象

作用二: 管理事务

我们知道MySQL事务管理分为三个操作:

开启事务:BEGIN; 或者 START TRANSACTION;

提交事务:COMMIT;

回滚事务:ROLLBACK;

MySQL默认自动提交事务

在JDBC事务管理中:Connection接口中定义了3个对应的方法

开启事务:setAutoCommit(boolean autoCommit)

  • true为自动提交事务;
  • false为手动提交事务,即为开启事务

提交事务:commit()

回滚事务:rollback()

示例代码:

public static void main(String[] args) throws Exception {
    
    
    // 获取链接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");

    // 定义sql
    String sql1 = "UPDATE account SET money = 3000 WHERE id = 1";
    String sql2 = "UPDATE account SET money = 4000 WHERE id = 2";

    // 获取sql执行对象
    Statement stmt = conn.createStatement();

    // 开启事务
    conn.setAutoCommit(false);
    try {
    
    
        // 执行sql1
        int count1 = stmt.executeUpdate(sql1);
        System.out.println(count1);
        // 执行sql2
        int count2 = stmt.executeUpdate(sql2);
        System.out.println(count2);

        // 提交事务
        conn.commit();
    } catch (Exception e) {
    
    
        // 异常回滚事务
        conn.rollback();
    }

    // 释放资源
    stmt.close();
    conn.close();
}

作用二: 获取执行 SQL 的对象

普通执行SQL对象: Statement createStatement()

预编译SQL的执行SQL对象, 防止SQL注入: PreparedStatement prepareStatement (sql)

执行存储过程的对象: 执行存储过程的对象

Statement

Statement的唯一作用作用:执行SQL语句

执行DML、DDL的SQL语句:

int executeUpdate(sql):

  • 返回值:DML语句返回影响的行数; DDL语句执行后,执行成功也可能返回 0

执行DML语句演示代码

@Test
public void testDML() throws Exception {
    
    
    // 获取连接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
    // 获取sql执行对象
    Statement stmt = conn.createStatement();

    // 定义一个DML sql语句
    String sql = "UPDATE account SET money = 3000 WHERE id = 1";
    // 返回执行完DML sql语句后影响的行数
    int count = stmt.executeUpdate(sql);
    System.out.println(count); // 1
    // 处理结果
    if (count > 0) {
    
    
        System.out.println("修改成功~");
    } else {
    
    
        System.out.println("修改失败~");
    }

    // 释放资源
    stmt.close();
    conn.close();
}

执行DDL语句演示代码, 执行DDL语句成功也有可能返回0

@Test
public void testDDL() throws Exception {
    
    
    // 获取连接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
    // 获取sql执行对象
    Statement stmt = conn.createStatement();

    // 定义一个DDL sql语句
    String sql = "DROP DATABASE db2";
    // 执行成功也有可能返回0
    int count = stmt.executeUpdate(sql);
    System.out.println(count); // 0

    // 释放资源
    stmt.close();
    conn.close();
}

执行DQL的SQL语句

ResultSet executeQuery(sql):执行DQL 语句

  • 返回值:ResultSet 结果集对象

ResultSet

ResultSet(结果集对象)作用:封装了DQL查询语句的结果

ResultSet stmt.executeQuery(sql): 执行DQL语句,返回 ResultSet 对象

获取查询结果:

方法boolean next()

  • 将光标从当前位置向前移动一行
  • 判断当前行是否为有效行

返回值boolean类型:

  • true:表示有效行,当前行有数据
  • false:表示无效行,当前行没有数据

获取数据:

方法xxx getXxx(参数)

  • xxx:数据类型;如:int getInt(参数) ; String getString(参数)

参数: 传入参数可以获取表中的数据

  • int类型参数:列的编号,从1开始
  • String类型参数:列的名称

使用步骤:

游标向下移动一行,并判断该行否有数据:next()

获取数据:getXxx(参数)

//循环判断游标是否是最后一行末尾
while(rs.next()){
    
    
    //获取数据
    rs.getXxx(参数);
}

示例代码:

@Test
public void testResultSet() throws Exception {
    
    
    // 获取连接
    Connection conn = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
    // 获取sql执行对象
    Statement stmt = conn.createStatement();

    // 定义一个DQL sql语句
    String sql = "SELECT * FROM account";
    // 执行结果返回一个ResultSet结果集对象
    ResultSet rs = stmt.executeQuery(sql);
    // 处理结果
    while (rs.next()) {
    
     // 向下移动一行,判断是否有数据
        // 获取数据 传入int类型
        System.out.print(rs.getInt(1));
        System.out.print(rs.getString(2));
        // 获取数据 传入String类型
        System.out.println(rs.getDouble("money"));
    }

    // 释放资源
    stmt.close();
    conn.close();
}

PreparedStatement

PreparedStatement作用

预编译SQL语句并执行:预防SQL注入问题

SQL注入:

SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

SQL注入演示

创建tb_user表, 用于做登录演示

-- 创建tb_user表
CREATE TABLE tb_user(
	id int,
	username VARCHAR(20),
	password VARCHAR(32)
);

-- 添加数据
INSERT INTO tb_user VALUES(1,'zhangsan','123'),(2,'lisi','234');

首先写出登录的逻辑, 输入的账号密码只有与数据库一致的时候, 才会登录成功

@Test
public void testLogin() throws Exception {
    
    
    // 获取连接
    Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
    // 获取sql执行对象
    Statement stmt = coon.createStatement();
    // 接收用户输入的账号密码
    String userName = "zhangsan";
    String password = "123";
    // 定义sql语句
    String sql = "SELECT * from tb_user WHERE username = '" + userName + "'AND password = '" + password + "'";
    // 执行sql
    ResultSet rs = stmt.executeQuery(sql);
    // 判断登录是否成功
    if (rs.next()) {
    
    
        System.out.println("登录成功");
    } else {
    
    
        System.out.println("登录失败");
    }
}

sql注入演示, 我们随便输入一个账号, 然后密码输入' or '1' = '1, 发现是可以登录成功的

@Test
public void testLogin() throws Exception {
    
    
    Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");
    Statement stmt = coon.createStatement();
    // 接收用户输入的账号密码
    String userName = "ddamhkhyug";
  	// 演示sql注入
    String password = "'or '1' = '1";
    String sql = "SELECT * from tb_user WHERE username = '" + userName + "'AND password = '" + password + "'";
    ResultSet rs = stmt.executeQuery(sql);
    if (rs.next()) {
    
    
        System.out.println("登录成功");
    } else {
    
    
        System.out.println("登录失败");
    }
}

SQL注入是非常危险的, 我们可以通过PreparedStatement防止SQL注入, PreparedStatement使用步骤如下:

  1. 获取 PreparedStatement 对象
// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ?";

// 通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
  1. 设置参数值
pstmt.setString(1, userName);
pstmt.setString(2, password);

PreparedStatement对象:setXxx(参数1,参数2):给 ? 赋值

  • Xxx:数据类型 ; 如 setInt (参数1,参数2)

参数:

  • 参数1: ?的位置编号,从1 开始
  • 参数2: ?的值
  1. 执行SQL
executeUpdate();
executeQuery(); // 不需要在传入sql语句

演示代码:

@Test
public void testPreparedStatement() throws Exception {
    
    
    Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false", "root", "123456789");

    String userName = "ddamhkhyug";
    // sql注入
    String password = "'or '1' = '1";

    // 定义sql语句
    String sql = "SELECT * from tb_user WHERE username = ? AND password = ?";

    // 获取PrepareStatement对象
    PreparedStatement pstmt = coon.prepareStatement(sql);
    // 设置sql语句中?的值
    pstmt.setString(1, userName);
    pstmt.setString(2, password);

    // 执行sql
    ResultSet rs = pstmt.executeQuery();

    // 判断登录是否成功
    if (rs.next()) {
    
    
        System.out.println("登录成功");
    } else {
    
    
        System.out.println("登录失败");
    }

    pstmt.close();
    rs.close();
    coon.close();
}

PreparedStatement 好处, 除了防止SQL注入, 将敏感字符进行转义之外; 还可以预编译SQL,性能更高

PreparedStatement 预编译功能开启:url添加参数useServerPrepStmts=true

Connection coon = DriverManager.getConnection("jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true",
                "root", "123456789");

猜你喜欢

转载自blog.csdn.net/m0_71485750/article/details/127817972