2022年5月6日 【狂神说Java】MySQL最新教程通俗易懂6 JDBC

本文详细介绍了Java使用JDBC连接MySQL数据库的过程,包括数据库驱动、JDBC规范、第一个JDBC程序、Statement与PreparedStatement对象的使用,以及事务处理和数据库连接池的概念,特别强调了PreparedStatement在防止SQL注入方面的优势和数据库连接池的资源管理作用。
摘要由CSDN通过智能技术生成

10 JDBC

10.1 数据库驱动

应用程序无法直接连接到数据库, 需要通过数据库厂商提供的驱动连接数据库.

我们的程序会通过数据库驱动, 和数据库打交道

10.2 JDBC

为了简化开发人员对数据库的统一操作, 提供了一个java操作数据库的规范, 俗称jdbc

这些规范的实现由具体的厂商去做.

对于开发人员来说, 我们只需要掌握JDBC接口的操作即可.

java.sql

javax.sql

还需要导入一个数据库驱动包

mysql- connector 驱动包官方下载地址: 5.1.47

https://downloads.mysql.com/archives/c-j/

10.3 第一个JDBC程序

创建测试数据库

CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;

USE `jdbcStudy`;

CREATE TABLE `users`(
 `id` INT PRIMARY KEY,
 `NAME` VARCHAR(40),
 `PASSWORD` VARCHAR(40),
 `email` VARCHAR(60),
 birthday DATE
);

 INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES('1','zhangsan','123456','zs@sina.com','1980-12-04'),
('2','lisi','123456','lisi@sina.com','1981-12-04'),
('3','wangwu','123456','wangwu@sina.com','1979-12-04')
  1. 创建一个普通项目

  2. 导入数据库驱动( 项目根目录下创建lib文件夹, 复制粘贴进mysql-connector的jar包, 右键点击考入的jar包,选择Add as Library…)

  3. 编写测试代码

package com.kuang;

import java.sql.*;

public class lesson01 {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        // 1. 加载驱动
        Class<?> c = Class.forName("com.mysql.jdbc.Driver");

        // 2. 用户信息 和url
        // useUnicode=true&characterEncoding=utf8&useSSL=true
        String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
        String username = "root";
        String password = "123456";

        // 3.连接成功, 数据库对象 connection代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //4. 执行SQL的对象Statement  执行SQL的对象
        Statement statement = connection.createStatement();

        // 5.执行SQL的对象去执行SQL, 可能存在结果, 查看返回结果
        String sql = "select * from users";

        ResultSet resultSet = statement.executeQuery(sql);  // 返回的结果集,
        // 结果集中封装了我们查询的全部结果

        while(resultSet.next()){
            System.out.println(resultSet.getObject("id"));
            System.out.println(resultSet.getObject("name"));
            System.out.println(resultSet.getObject("PASSWORD"));
            System.out.println(resultSet.getObject("email"));
            System.out.println(resultSet.getObject("birthday"));
        }


        // 6. 释放连接
        resultSet.close();
        statement.close();
        connection.close();


    }
}

步骤总结:

  1. 加载驱动
    1.
  2. 连接数据库DriverManager
  3. 获取执行sql的对象statement
  4. 获得返回的结果集
  5. 释放连接

DriverManager

// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");

Connection connection = DriverManager.getConnection(url, username, password);
// 数据库设置自动提交
// 事务提交
// 事务回滚

connection.rollback();
connection.commit();
connection.setAutoCommit();

URL

 String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=false";

// jdbc:mysql://主机地址:3306/数据库名?参数1&参数2&参数3
// oracle-- 1521
//jdbc:oracle:think:@localhost:1521:sid
     //sqlserver 1433

statement 执行sql的对象 PreparedStatement

 String sql = "select * from users"; // 编写sql 

statement.execute(); 执行任何sql
statement.executeQuery(); // 查询操作返回ResultSet
statement.executeUpdate();	// 更新, 插入, 删除. 都是用这个, 返回一个受影响的行数

resultSet 查询的结果集: 封装了所有的查询结果

resultSet.getObject(); // 在不知道列类型的时候使用
    // 在直到列类型的时候使用
resultSet.getInt();
resultSet.getString();
resultSet.getDate();
resultSet.getFloat();
    
resultSet.previous();
resultSet.next();

释放资源

 // 6. 释放连接
resultSet.close();
statement.close();
connection.close();

— 业务级别 mysql

— 运维级别mysql 底层拷贝…架构…

10.4 statement对象

statement对象用于想数据库发送SQL语句.

create

executeUpdate(String sql)

delete

executeUpdate(String sql)

insert

executeUpdate(String sql)

代码实现

  1. 提取工具类
package com.kuang.Lesson02.util;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {

    private static String driver =null;
    private static String url =null;
    private static String username=null;
    private static String password=null;
    static {
        try{
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
             driver = properties.getProperty("driver");
             url = properties.getProperty("url");
             username = properties.getProperty("username");
             password = properties.getProperty("password");

            System.out.println(driver+url);

            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }


    }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    public static void release(Connection conn, Statement st, ResultSet rs){
        if(rs!= null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
  1. 编写增删改的方法 executeUpdate()
// 增加例子
public class TestInsert { 

    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql ="insert into users(id, `name`, `password`, `email`, `birthday`) values(4,'kuangshen','123456','123@123.com','2020-01-01')";
            int i = st.executeUpdate(sql);
            if(i>0){
                System.out.println("更新成功");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st, rs);

        }
    }
}

  1. 查询
public class TestSelect {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql ="select id, name from users";
            rs = st.executeQuery(sql);
            while(rs.next()){
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st, rs);

        }
    }
}

sql注入的问题

sql存在漏洞, 会导致数据泄露.

可以使用PreparedStatement防止sql注入问题

package com.kuang.Lesson02.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Login {
    public static void main(String[] args) {
//        login("lisi", "123456");
        login("' or 1=1'", "' or 1=1'");
    }

    public static void login(String username ,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql ="select * from users where name ='"+username+ "' and password ='"+password+"'";
            rs = st.executeQuery(sql);
            while(rs.next()){
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st, rs);

        }
    }

}

10.5 PreparedStatement

PreparedStatement可以防止sql注入, 并且效率更好.

  1. 新增
public class TestInsert {

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            connection = JdbcUtils.getConnection();

            // 区别
            // 使用?占位符代替参数
            String sql = "insert into users(id, `name`, `password`, `email`, `birthday`) values (?,?,?,?,?)";

            pst = connection.prepareStatement(sql); // 预编译sql, 先写sql, 然后不执行

            // 手动给参数赋值
            pst.setInt(1,4);
            pst.setString(2,"kuangshen");
            pst.setString(3,"123456");
            pst.setString(4,"1234@5.com");
            // 注意点: sql.Date()  数据库    java.sql.Date()
            //          util.Date()  Java  new Date().getTime() 获得时间戳
            pst.setDate(5,new java.sql.Date(new Date().getTime()));

            int i = pst.executeUpdate();
            if(i>0) System.out.println("成功");


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,pst,rs);
        }
    }
}
  1. 删除
public class TestDelete {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            connection = JdbcUtils.getConnection();

            // 区别
            // 使用?占位符代替参数
            String sql = "delete from users where id = ?";
            pst = connection.prepareStatement(sql); // 预编译sql, 先写sql, 然后不执行

            // 手动给参数赋值
            pst.setInt(1,4);

            int i = pst.executeUpdate();
            if(i>0) System.out.println("成功");


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,pst,rs);
        }
    }
}
  1. 更新
public class TestUpdate {

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            connection = JdbcUtils.getConnection();

            // 区别
            // 使用?占位符代替参数
            String sql = "update users set `name` = ? where id = ?";
            pst = connection.prepareStatement(sql); // 预编译sql, 先写sql, 然后不执行

            // 手动给参数赋值
            pst.setString(1,"狂神");
            pst.setInt(2,4);

            int i = pst.executeUpdate();
            if(i>0) System.out.println("成功");


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,pst,rs);
        }
    }
}
  1. 查询
public class TestSelect {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            connection = JdbcUtils.getConnection();

            String sql = "select * from users where id = ?"; // 编写sql

            pst = connection.prepareStatement(sql); // 预编译

            pst.setInt(1,2);    // 传递参数

            rs = pst.executeQuery();        // 执行

            while(rs.next()){
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,pst,rs);
        }


    }
}
  1. 防止SQL注入
public class SQL注入 {
    public static void main(String[] args) {
//        login("lisi", "123456");
        login("'' or 1=1'", "'' or 1=1");
    }

    public static void login(String username ,String password){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            String sql ="select * from users where name = ? and password = ?";
       // PreparedStatement防止SQL注入的本质是把传递进来的参数当做字符
            // 假设其中存在转义字符, 会直接忽略, 比如说'会被直接转义
            st = conn.prepareStatement(sql);
            st.setString(1, username);
            st.setString(2, password);

            rs = st.executeQuery();

            while(rs.next()){
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st, rs);

        }
    }
}

10.7 使用IDEA连接数据库

连接成功后 可以选择数据库schemas

在这里插入图片描述

设置数据库,

如果出现问题找不到数据库驱动, 可以进行调整
在这里插入图片描述

10.8 事务

要么都成功 要么都失败

ACID

原子性: 要么全部完成, 要么都不完成

一致性:总数不变

隔离性: 多个进程互不干扰

持久性:一旦提交不可逆

隔离性问题:

脏读: 一个事务读取了另一个没有提交的事务

不可重复度: 在一个事务内重复读取表中的数据 ,表数据发生了改变

虚读(幻读): 在一个事务内, 读取到了别人插入的数据 ,导致前后读出来的数据不一致.

代码实现

  1. 开启事务 connection.setAutoCommit(false)
  2. 一组业务执行完毕 , 提交事务
  3. 可以再catch语句中显示的定义回滚语句, 但是默认失败就回滚.
public class TestTransaction1 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            connection = JdbcUtils.getConnection();
            // 关闭数据库的自动提交功能, 会自动开启事务
            connection.setAutoCommit(false); // 开启事务

            String sql1 ="update account set money = money-100 where name ='A'";
            st = connection.prepareStatement(sql1);
            st.executeUpdate();

            String sql2 ="update account set money = money+100 where name ='B'";
            st = connection.prepareStatement(sql2);
            st.executeUpdate();

            // 业务完成, 提交事务
            connection.commit();
            System.out.println("成功");

        } catch (SQLException throwables) {
            try {
                connection.rollback(); // 如果失败则回滚
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(connection,st, rs);
        }

    }
}

10.9 数据库连接池

数据库连接— 执行完毕 —释放

连接 --释放十分浪费资源

池化技术: 准备一些预先的资源, 过来就连接预先准备好的

---- 开门-- 业务员:等待 — 服务— 关门

常用连接数 : 100

15个员工

最小连接数: 10

最大连接数:15 业务最高承载上限

排队等待,

等待超时:100ms

编写连接池 , 实现一个接口 DataSource

开源数据源实现 (拿来即用)

DBCP

C3P0

Druid : 阿里巴巴

使用了这些数据库连接池之后, 我们在项目开发中就不需要编写数据库的代码了

DBCP

导入: commons-dbcp-1.4.jar

commons-pool- 1.6.jar

编写配置文件dbcpconfig.properties

C3P0

导入:c3p0-0.9.5.5.jar

mchange-commons-java-0.2.19.jar

编写配置文件 c3p0-config.xml

结论

无论使用什么数据源, 本质还是一样的, DataSource接口不会变, 方法就不会变

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值