浅学JDBC

JDBC简述

先来段代码看看,诶诶诶,先别着急复制去Idea运行

	public static void main(String[] args) throws Exception {
        //1、注册成功
        Class.forName("com.mysql.jdbc.Driver");//使用如果是mysql5.+版本可以不写这一句
        //2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";//localhost 是mysql设置的主机 db1是自己新建的数据库名
        String username = "root";//用户名(你自己的)
        String password = "admin";//密码(你自己的)
        Connection conn = DriverManager.getConnection(url, username, password);
        //3、定义SQL
        String sql = "update tb_goods set title = '牛马' where id = 7";
        //4、获取执行sql的对象
        Statement stmt = conn.createStatement();
        //5、执行sql
        int count = stmt.executeUpdate(sql);
        //6、处理结果
        System.out.println(count);
        //7、释放资源
        stmt.close();
        conn.close();
    }

JDBC概念:

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

运行代码

导包

IDEA新建工程(记得先设置好自己的SDK)
在这里插入图片描述
新建Modules,在新建的Modules目录下新建lib文件目录,后将下载好的jar包复制入jar包,我的版本是JDK11 使用了mysql-5.1.48,这里采用的是最基本的导包方法,后期使用到maven就不用这么麻烦

jar包上这儿下载去
mysql与数据库以及jdk各版本的匹配情况上这儿看
在这里插入图片描述
对准包右键点击Add as Li……

在这里插入图片描述
点击Module Library,直接OK就可以
在这里插入图片描述
接下去就新建类文件开始粘贴源码就可以运行自己的项目了

JDBC的API详解:

DriverManager(驱动管理类)

作用:
(较常用方法: getConnection​(获取数据库连接Connetion对象)、registerDriver(注册驱动com.mysql.jdbc.Driver中使用了此方法))

  1. 注册驱动
  2. 获取数据库连接
String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
//如果连接的是本机且端口号也为3306可以简化书写为
String url = "jdbc:mysql:///db1?useSSL=false";

Connection(数据库连接对象)

作用:

  1. 获取执行SQL的对象
    - 普通执行SQL对象:Statement createStatement()重点
    - 预编译SQL的执行SQL对象:防止SQL注入 PrepareStatement prepareStatement(sql)重点
    - 执行存储过程的对象:CallableStatement prepareCall(sql)

防注入代码测试

    public void testlogin() throws Exception {

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

        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);

        String title = "'or '1' = '1";
        double price = 4999.00;

        String sql = "select * from tb_goods where title = '"+ title +"' and price = '" + price + "'";

        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery(sql);

        if (rs.next()){
            System.out.println("成功");
        }else {
            System.out.println("失败");
        }
        //7、释放资源
        rs.close();
        stmt.close();
        conn.close();
    }

如果出现在登录的功能,那么是不是意味着我只要把密码或者账号输入’or ‘1’ = '1,那我是不是就可以为所欲为了,直接登录都不要,注入!!注入!!!注入!!!!

注入成功

如何防止注入:

    public void testPrepatedStatement() throws Exception {

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

        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);


        //SQL语句中的参数值,使用?占位符替代
        String sql = "select * from tb_goods where title=? and id=?";

        //通过Connection对象获取,并传入对应的sql语句,防注入
        PreparedStatement ps = conn.prepareStatement(sql);

        //向?传入值
        ps.setString(1, "手机");
        ps.setInt(2, 2);

        ResultSet rs = ps.executeQuery();

        while (rs.next()){
            System.out.println(rs.getInt(1));
            System.out.println(rs.getString(2));
            System.out.println(rs.getDouble(3));
        }

        //7、释放资源
        rs.close();
        ps.close();
        conn.close();
    }

在这里插入图片描述

小小一试
果然失败

下面会更加详细的介绍

  1. 管理事务
    MySQL中:
# 开启事务
BEGIN;/START TRANSACTION;
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;

JDBC中:

//开启事务,true为自动提交事务;false为手动提交事务
setAutoCommit(boolean autoCommit)

// 提交事务
commit()

//回滚事务
rollback();

试试:

public static void main(String[] args) throws Exception {
        //1、注册成功
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3、定义SQL
        String sql1 = "update tb_goods set title = '狗子' where id = 7";
        String sql2 = "update tb_goods set price = 4999.00 where id = 7";
        //4、获取执行sql的对象
        Statement stmt = conn.createStatement();

        try {
            //开启事务
            conn.setAutoCommit(false);

            //5、执行sql
            int count1 = stmt.executeUpdate(sql1);
            //6、处理结果
            System.out.println(count1);


            int i = 3/0;

            //5、执行sql
            int count2 = stmt.executeUpdate(sql2);
            //6、处理结果
            System.out.println(count2);

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


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

执行后数据库结果为:(由于误删所以截图就将就看吧)
在这里插入图片描述

Statement

作用:

  1. 执行SQL语句
    - int executeUpdate() :执行DML(对表中数据进行操作)、DDL(对数据库操作)
    返回值:int(1)DML语句影响行数(2)DDL语句执行后,执行成功也可能返回0(后者少用)
    - ReseultSet executeQuery(sql):执行DQL(对表中数据进行查询)语句
    返回值:ResultSet

上代码:

    @Test
    public void testDML() throws Exception {
        //1、注册成功
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3、定义SQL
        String sql = "update tb_goods set title = '牛马' where id = 7";
        //4、获取执行sql的对象
        Statement stmt = conn.createStatement();
        //5、执行sql
        int count = stmt.executeUpdate(sql);//DML返回执行的影响行数
        //6、处理结果
        if(count > 0){
            System.out.println("修改成功");
        }else {
            System.out.println("修改失败");
        }
        //7、释放资源
        stmt.close();
        conn.close();
    }

    @Test
    public void testDDL() throws Exception {
        //1、注册成功
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3、定义SQL
        String sql = "drop DATABASE db2";
        //4、获取执行sql的对象
        Statement stmt = conn.createStatement();
        //5、执行sql
        int count = stmt.executeUpdate(sql);
        //6、处理结果
        System.out.println(count);//DDL可能返回0
        //7、释放资源
        stmt.close();
        conn.close();
    }

ResultSet(结果集对象)

作用:

  1. 封装了DQL查询语句的结果

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

    · 获取查询结果

    boolean next():(1)将光标从当前位置向前移动一行(2)判断当前是否为有效行
    返回值:
    true:有效行,当前行有效数据
    false:无效行,当前行没有数据

    xxx getXxx(参数):获取数据
    xxx:数据类型;如:int getInt(参数);String getString(参数)
    参数:
    int:列的编号,从1开始
    String:列的名称

小小test一下

@Test
    public void testDML() throws Exception {
        //1、注册成功
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3、定义SQL
        String sql = "select * from tb_goods";

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

        //5、执行sql
        ResultSet rs = stmt.executeQuery(sql);

        while(rs.next()){
            int id = rs.getInt(1);
            String title = rs.getString(2);
            double price = rs.getDouble(3);

            System.out.println(id);
            System.out.println(title);
            System.out.println(price);

            System.out.println("===============");

        }

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

在这里插入图片描述

PreparedStatement

  • 作用:
    预编译SQL语句并执行:预防SQL注入问题。

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

看一个SQL注入的问题,就是字符串字段输入特殊的字段实现最终的成效果

@Test
    public void testlogin() throws Exception {

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

        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);

        String title = "手机";
        double price = 4999.00;

        String sql = "select * from tb_goods where title = '"+ title +"' and price = '" + price + "'";

        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery(sql);

        if (rs.next()){
            System.out.println("成功");
        }else {
            System.out.println("失败");
        }
        //7、释放资源
        rs.close();
        stmt.close();
        conn.close();
    }



    /**
     SQL注入的问题
     * */
    @Test
    public void testlogin_Inject() throws Exception {

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

        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);

        String title = "' or 'a' = 'a";
        double price = 4999.00;

        String sql = "select * from tb_goods where title = '"+ title +"' and price = '" + price + "'";

        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery(sql);

        if (rs.next()){
            System.out.println("成功");
        }else {
            System.out.println("失败");
        }
        //7、释放资源
        rs.close();
        stmt.close();
        conn.close();
    }

如何预防,来看看

  1. 获取PreparedStatement对象

    //SQL语句中的参数值,使用?占位符替代
    String sql = "select * from user where username=? and password=?";
    
    //通过Connection对象获取,并传入对应的sql语句
    PreparedStatement pstmt = conn.prepareStatement(sql);
    
  2. 设置参数值
    PreparedStatement对象:setXxx(参数1,参数2):给?赋值
    Xxx:数据类型;如setInt(参数1, 参数2)
    参数1:?的位置编号,从1开始
    参数2:?的值

  3. 执行SQL

    //不需要再传递sql
    executeUpdate();
    executeQuery();
    

看看代码:

@Test
    public void testPrepatedStatement_Inject() throws Exception {

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

        String url = "jdbc:mysql://localhost:3306/db1?useSSL=false";
        String username = "root";
        String password = "admin";
        Connection conn = DriverManager.getConnection(url, username, password);


        //SQL语句中的参数值,使用?占位符替代
        String sql = "select * from tb_goods where title=? and id=?";

        //通过Connection对象获取,并传入对应的sql语句
        PreparedStatement ps = conn.prepareStatement(sql);

        //向?传入值
        ps.setString(1, "' or 'a' = 'a");
        ps.setInt(2, 2);

        ResultSet rs = ps.executeQuery();

        if(rs.next()){
            System.out.println("成功");
            while (rs.next()) {
                System.out.println(rs.getInt(1));
                System.out.println(rs.getString(2));
                System.out.println(rs.getDouble(3));
            }
        }else{
            System.out.println("失败");
        }
        //7、释放资源
        rs.close();
        ps.close();
        conn.close();
    }

PreparedStatement原理

使用黑马的老师一张ppt来理解下

在这里插入图片描述

数据线程池

简介

数据连接池是个容器,负责分配,管理数据库连接(Connection)
好处:

  • 资源重用
  • 提升系统响应速度
  • 避免数据库连接遗漏

Druid数据库连接池

使用步骤

  1. 导入jar包duid-1.1.12.jar
    下载链接
    粘贴到lib目录下
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. 定义配置文件

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/db1?useSSL=false&ServerPreStmts=true
    username=root
    password=admin
    # 初始化连接数量
    initialSize=5
    # 最大连接数
    maxActive=10
    # 最大等待时间
    maxWait=3000
    
  3. 加载配置文件

    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc_demo/src/druid.properties"));
    
  4. 获取数据库连接池对象

    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    
  5. 获取连接

    Connection conn = dataSource.getConnection();
    

以下使用一个小案例来汇总一下数据库线程池的知识:
Goods.java

package com.test.pojo;

public class Goods {
    private Integer id;
    private String name;
    private double price;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "goods{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

GoodsTest.java

package com.test.example;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.test.pojo.Goods;
import org.junit.jupiter.api.Test;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class GoodsTest {
    @Test
    public void selectAll() throws Exception {
        //加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/druid.properties"));

        //创建连接对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //创建数据库连接对象
        Connection conn = dataSource.getConnection();

        //sql查询语句
        String sql = "select * from tb_goods";

        //定义sql的执行对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

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

        //定义List<Goods>进行存储
        List<Goods> list = new ArrayList<>();
        while (rs.next()) {
            Goods goods = new Goods();

            int id = rs.getInt("id");
            String title = rs.getString("title");
            double price = rs.getDouble("price");

            goods.setId(id);
            goods.setName(title);
            goods.setPrice(price);

            list.add(goods);
        }
        System.out.println(list);
        pstmt.close();
        rs.close();
        conn.close();
    }

    @Test
    public void testAll() throws Exception {
        String goodsTitle = "鼠标";
        double goodsPrice = 9.99;

        //加载文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/druid.properties"));

        //创建连接对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //创建数据库连接对象
        Connection conn = dataSource.getConnection();

        String sql = "insert into tb_goods(title, price) values (?,?);";

        PreparedStatement pstmt = conn.prepareStatement(sql);

        //设置参数
        pstmt.setString(1, goodsTitle);
        pstmt.setDouble(2, goodsPrice);

        int count = pstmt.executeUpdate();
        System.out.println(count > 0);
        prop.clone();
        conn.close();
        pstmt.close();

    }

    @Test
    public void testUpdate() throws Exception {
        String goodsTitle = "狗子";
        int goodsId = 7;

        //加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/druid.properties"));

        //创建连接的对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //创建数据库连接对象
        Connection conn = dataSource.getConnection();

        String sql = "update tb_goods set title = ? where id = ?";
        
        //执行sql语句
        PreparedStatement pstmt = conn.prepareStatement(sql);

        pstmt.setString(1, goodsTitle);
        pstmt.setInt(2,goodsId);

        int count = pstmt.executeUpdate();
        System.out.println(count > 0);
        prop.clone();
        conn.close();
        pstmt.close();
    }

    @Test
    public void testDeleteById() throws Exception {
        int goodsId = 9;

        //加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("src/druid.properties"));

        //创建连接的对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //创建数据库连接对象
        Connection conn = dataSource.getConnection();

        String sql = "delete from tb_goods where id=?";

        //执行sql语句
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1,goodsId);

        int count = pstmt.executeUpdate();
        System.out.println(count > 0);
        prop.clone();
        conn.close();
        pstmt.close();
    }

}

当然这里也可以采用工具类或者是方法的方式来进行简化代码,由于是练习,就没有采取更加简洁的代码了,如果需要可以将每个方法中的如下方法进行提取:在这里插入图片描述

均可运行成功

druid.properties包路径出错的问题解决!

如果显示路径出错的话,你可以在本程序中进行输出当前程序路径,如果已经包含了当前项目名(module名)那就可以跟我一样写src/druid.properties即可,否则需将当前项目名(module名)添加,如:jdbc_demo/src/druid.properties

//路径可能会出错,有时需要添加(jdbc_demo)可以答应一下当前目录:
System.out.println(System.getProperty("user.dir"));

在这里插入图片描述
以上情况是我的输出当前文件,已经包含了本项目名

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值