JDBC-MySql基础

概述

JDBC全称Java DataBase Connectivityjava数据库连接

在JDBC创建之前java程序员每操作一款关系型数据库就需要学习java连接该数据库代码,由于关系型数据库过多(如:oracle、db2、MySQL…),不可能全部学习,所以java程序员就期望SUN公司能研发出一套可以运行所有关系型数据库的代码,于是JDBC就出生了。

JDBC其实是SUN公司定义的一套操作所有关系型数据库的接口(规则),具体的实现类则需要数据库公司自行编写,实现类又名为数据库驱动jar包。
当我们使用JDBC编程时实际运行的为数据库驱动jar包中的代码。

使用步骤(mysql为例)

本文所有资源都可到百度云下载
链接:https://pan.baidu.com/s/1J3888hIwUf8qHnKnfFxO6w.
提取码:j1x3

导入驱动jar包

需要到数据库官网下载jar包

在这里插入图片描述

  1. 将jar包复制到IDEA的LIB目录下(此目录可自定义名称)
    在这里插入图片描述

  2. 右击jar包点击添加为库(Add as library
    在这里插入图片描述

  3. Level选择Module Library
    在这里插入图片描述

  4. 添加成功后jar包会出现一个下拉箭头,可查看源码
    在这里插入图片描述

注册驱动

告诉程序该执行指定的jar包程序

三种注册方法

  1. 反射
//抛出一个ClassNotFoundException异常
Class.forName("com.mysql.jdbc.Driver");
  1. DriverManager.registerDriver(new Driver());
    第一种反射的com.mysql.jdbc.Driver的源码实际调用了DriverManager类registerDriver静态方法

public class Driver extends NonRegisteringDriver implements java.sql.Driver {js
    public Driver() throws SQLException {}
    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

注销驱动

Driver driver = new Driver();//驱动
DriverManager.registerDriver(driver);//注册驱动
DriverManager.deregisterDriver(driver);//注销驱动

注意:Driver的导包为com.mysql.jdbc.Driver中的实现类;而不是java.sql.Driver的接口

  1. 设置系统属性
System.setProperty("jdbc:drivers","com.mysql.jdbc.Drive");

注销驱动

System.clearProperty("jdbc:drivers");//删除系统属性

注意:在mysql5之后可省略注册驱动
因为程序会先读取java.sql.Driver文件注册驱动

在这里插入图片描述

获取数据库连接对象Connection

getConnection()存在多个重载方法

  1. getConnection(String url)
    url:数据库网址
    当数据库没有账号密码时方可使用

  2. getConnection(String url, Properties info)
    info:作为连接参数的任意键/值对的列表; 通常至少应包含“用户”和“密码”属性

Properties pro = new Properties();
pro.load(Statement01.class.getClassLoader().getResourceAsStream("jdbc.properties"));
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", pro);
  1. getConnection(String url, String user, String password)
    user:连接的数据库用户
    password:用户密码
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db?characterEncoding=utf8");

url语法:协议名:子协议://服务器名或 IP 地址:端口号/数据库名?参数=参数值

  1. 如mysql:jdbc:mysql://localhost:3306/数据库[?参数名=参数值]
  2. 如果访问本机上的mysql服务器且默认端口没有修改,url可简写为:
    jdbc:mysql:///数据库名[?参数名=参数值]
  3. 乱码处理:指定编码参数 ?characterEncoding=utf8

执行sql语句

  1. Statement
    用于执行静态SQL语句并返回其生成的结果的对象
Statement statement = connection.createStatement();

Statement对象执行sql的方法

  • boolean execute(String sql):执行任意的SQL语句
    返回:
    true-结果是一个ResultSet对象
    false-更新计数或没有结果
statement.execute("select * from a");//true
statement.execute("update a set age=20 where id=200");//false
  • int executeUpdate(String sql):执行DML(INSERT,UPDATE,DELETE)给定的SQL语句
    返回:sql操作数据影响行

  • ResultSet executeQuery(String sql):执行DQL(SELECT)给定的SQL语句
    返回:ResultSet对象,包含给定查询产生的数据

【注意】此对象执行SQL存在SQL注入漏洞:在拼接sql时,存在一些特殊关键字(1=1…)参与时会存在安全问题
String sql = "select * from user where username='"+username+"' and password='"+password+"'";

  • username为任意值,password="' or '1'='1"时SQL将变为:
    "select * from user where username='任意值' and password='' or '1'='1'"
    便可轻松通过账号密码验证,存在较大隐患
  1. PreparedStatement

特点:

  • 将 SQL 语句发送给数据库预编译,提高 SQL 的执行效率
  • SQL参数可使用占位符(?)替代
  • 避免sql注入攻击:
String sql="select * from user where username=? and password=?";
PreparedStatement prepar = connection.prepareStatement(sql);

提供参数:void setXXX(int parameterIndex, XXX value)

  • parameterIndex:代表sql语句的第几个占位符(?),从1开始计算
  • XXX:代表数据类型,如String,int…

PreparedStatement对象执行sql的方法

  • boolean execute():执行任意的SQL语句
    返回:
    true-结果是一个ResultSet对象
    false-更新计数或没有结果

  • int executeUpdate():执行DML(INSERT,UPDATE,DELETE)给定的SQL语句
    返回:sql操作数据影响行

  • ResultSet executeQuery():执行DQL(SELECT)给定的SQL语句
    返回:ResultSet对象,包含给定查询产生的数据

PreparedStatement和Statement的区别

  • Statement存在sql注入漏洞,PreparedStatement则不存在
  • PreparedStatement编程更易懂,且维护性更好
  • Statement没执行一次就需要编译一次sql语句,PreparedStatement只需预编译一次sql语句,之后重复使用时不用再次编译
  • 在无需传参不存在sql注入漏洞且只执行一次sql语句时,建议使用Statement,速率较快
  • 在需要传参存在sql注入漏洞或一条sql语句需要重复执行时,建议使用PreparedStatement,因为PreparedStatement是通过数据库服务器预编译的,在第一次编译比Statement的时间更长

处理结果

DML操作的结果为int,操作影响数据的行数,
DQL操作则返回ResultSet集合

ResultSet
存储查询得到的数据
类似于Enumeration集合

ResultSet resultSet = prepar.executeQuery();

while (resultSet.next()){
	resultSet.getInt(1);
	resultSet.getInt("age");
}

boolean next()
将光标从当前位置向前移动一行
返回:

  • true-新的当前行
  • false-没有更多的行

getXXX(int columnIndex)
getXXX(String columnLabel)

  • XXX:获取参数的数据类型
  • columnIndex:代表获取当前行的第几列数据,从1开始计数
  • columnLabel:获取当前行列名为columnLabel的数据

释放资源

先开的后关,后开的先关
Connection资源最先打开,最后改变,ResultSet资源最后打开,最先关闭

 finally {
 	if (resultSet != null) {
		try {
        	resultSet.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    if (statement != null) {
        try {
            statement.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

关闭资源的代码建议放在finally中,避免代码中途出错,导致资源未被关闭,从而占用内存空间

JDBC工具类

每创建一个操作数据库的类就要连接数据库,关闭数据库等一堆冗余的代码,我们可以将重复的代码提取出来作为工具类

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

/**
 * @program: JDBC
 * @description: JDBC工具类
 * @author: 吐鲁番
 * @Date: 2020/8/21
 * @Time: 17:29
 **/
public class JDBCutils {
    private static Properties pro = null;

    static {
        try {
            //mysql数据库连接的配置文件
            pro = new Properties();
            //获取配置文件
            pro.load(JDBCutils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description 获取连接数据库对象
     * @return java.sql.Connection
     **/
    public static Connection getConnection() throws SQLException {
        String database = pro.getProperty("database");
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/" + database, pro);
    }

    /**
     * @Description 关闭数据库连接对象
     **/
    public static void closeConnection(Connection con) {
        if (con != null) {
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @Description 关闭执行数据库Statement对象
     **/
    public static void closeStatement(Statement sta) {
        if (sta != null) {
            try {
                sta.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @Description 关闭执行数据库PreparedStatement对象
     **/
    public static void closePreparedStatement(PreparedStatement prepar) {
        if (prepar != null) {
            try {
                prepar.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @Description 关闭数据对象
     **/
    public static void closeResultSet(ResultSet res) {
        if (res != null) {
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close(Connection con, Statement sta, ResultSet res) {
        closeConnection(con);
        closeStatement(sta);
        closeResultSet(res);
    }

    public static void close(Connection con, Statement sta) {
        close(con, sta, null);
    }

    public static void close(Connection con, PreparedStatement prepar, ResultSet res) {
        closeConnection(con);
        closeStatement(prepar);
        closeResultSet(res);
    }

    public static void close(Connection con, PreparedStatement prepar) {
        close(con, prepar, null);
    }
}

第一次尝试编写,本着学习的态度,自己可以总结学过的知识,也可以分享给别人

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值