JDBC保姆级教程

JDBC简介

  Java数据库连接,(Java Database Connectivity,简称JDBC)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成,是Java访问数据库的标准规范。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。


一、JDBC原理

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

二、开发步骤

1.注册驱动

  • 告知JVM使用的是哪一个数据库的驱动

2.获取数据库连接

  • 使用JDBC中的类,完成对MySQL数据库的连接

3.获取数据库操作对象

  • 通过连接对象获取对SQL语句的执行者对象

4.执行sql语句

  • 使用执行者对象,向数据库执行SQL语句 获取到数据库的执行后的结果

5.处理结果

  • 处理 resultSet 数据库结果集的数据表

6.释放资源

  • 调用一堆close()方法

下面展示示例代码

import java.sql.*;

public class JDBCDemo01 {
    /**
     * JDBC连接数据库的主要六步骤
     * @param args
     */
    public static void main(String[] args) {

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {

            //1、注册驱动  com.mysql.jdbc.Driver 是 mysql-connector-java5 中的 更高版本为 com.mysql.cj.jdbc.Driver
            Class.forName("com.mysql.jdbc.Driver");

            //2、获取数据库连接

            /* url 连接数据库地址   jdbc:mysql 协议    localhost 本地ip地址   3306 mysql默认端口号    
            test_database 数据库
            useUnicode=true&characterEncoding=UTF-8 指定字符的编码、解码格式
            
            例如:mysql数据库用的是 gbk编码,而项目数据库用的是 utf-8编码。
            如果添加了useUnicode=true&characterEncoding=UTF-8,那么作用有如下两个方面:
            存数据时:数据库在存放项目数据的时候会先用 UTF-8格式将数据解码成字节码,
            然后再将解码后的字节码重新使用 GBK编码存放到数据库中。
            取数据时:在从数据库中取数据的时候,数据库会先将数据库中的数据按 GBK格式解码成字节码,
            然后再将解码后的字节码重新按 UTF-8格式编码数据,最后再将数据返回给客户端。
            
            useSSL=false    MySQL在高版本需要指明是否进行SSL连接  1.true 需要连接     2.false 不需要连接
            
            JDBC连接 mysql6 需要指定时区serverTimezone 这时 url则为:
            url: jdbc:mysql://localhost:3306/test_database?
            serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
            在设定时区的时候,如果设定serverTimezone=UTC,会比中国时间早8个小时,
            如果在中国,可以选择Asia/Shanghai或者Asia/Hongkong,例如
            ?serverTimezone=Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false */

            String url = "jdbc:mysql://localhost:3306/test_database?" +
                    "useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";                   //user 用户名
            String password = "123456";             //password 密码
            connection = DriverManager.getConnection(url,user,password);

            System.out.println("数据库连接对象为:"+connection);

            //3、获取数据库操作对象
            statement = connection.createStatement();

            //4、执行sql语句
            String sql = "select * from tb_stu";

            /*如果执行的是删除、插入语句
            String sql = "insert into tb_stu(name,age,address) values('李四',18,'上海市')";
            //  num 为受到影响的语句数
            int num = statement.executeUpdate(sql);

            if(num == 1){

                System.out.println("插入数据成功");

            }else{

                System.out.println("插入数据失败");

            }*/

            //5、处理 resultSet 数据库结果集的数据表
            resultSet = statement.executeQuery(sql);

            //遍历结果集
            while(resultSet.next()){

                String name = resultSet.getString("name");

                int age = resultSet.getInt("age");

                String address = resultSet.getString("address");

                System.out.println(name+" "+age+" "+address);
            }

        } catch (Exception exception) {

            exception.printStackTrace();

        }finally {

            //6、关闭数据库资源 必须放在finally中,这样不会因为抛异常而不执行,需要做好非空校验
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

三、根据配置文件连接数据库

JDBC通过配置文件(properites)读取数据库配置信息

  采用ResourceBundle进行数据库配置文件读取,比通过获取IO流的方式更加地简便!

  创建一个默认的ResourceBundle对象,ResourceBundle会查找资源包下的properties的文件。资源包的命名,它跟普通java类的命名规则完全一样,区分大小写,资源文件必须位于指定包的路径之下(位于所指定的classpath中)。假如你是在非Web项目中使用,则一定要写资源文件的路径,也就是包路径必须存在。如果是Web项目,不写包路径可以,此时将资源文件放在WEB-INF\classes\目录下就可以。

配置文件db.properites

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test_database?useUnicode=true&characterEncoding=utf8&useSSL=false
user=root
password=123456

下面展示示例代码


import java.util.ResourceBundle;
/**
 * 从配置文件读取数据库配置信息
 */
public class JDBCDemo02 {

    public static void main(String[] args) {

        ResourceBundle jdbc = ResourceBundle.getBundle("db");

        String driver = jdbc.getString("driver");
        String url = jdbc.getString("url");
        String user = jdbc.getString("user");
        String password = jdbc.getString("password");

        System.out.println(driver);
        System.out.println(url);
        System.out.println(user);
        System.out.println(password);

    }
}

四、预处理对象,防止SQL注入

  SQL注入攻击是黑客对数据库进行攻击的常用手段之一。其本质是在前端输入数据中夹带数据库SQL语句的关键字,达到绕开数据库数据判定,访问受限数据的目的。

  在Java中Statement主要是用拼串传值的,这会造成可能出现危险!为此,我们使用PreparedStatement(预编译对象)来解决对应的问题。

下面展示示例代码

import java.sql.*;

public class JDBCDemo03 {
    /**
     * PreparedStatement 可以防止sql注入
     * @param args
     */
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");

            String url = "jdbc:mysql://localhost:3306/test_database?useUnicode=true&characterEncoding=utf8&useSSL=false";
            String user = "root";
            String password = "123456";
            connection = DriverManager.getConnection(url,user,password);

            System.out.println("数据库连接对象为:"+connection);

            //获取数据库操作对象 并且预编译sql
            preparedStatement = connection.prepareStatement("SELECT * from tb_user WHERE user = ? AND password = ?");

            //给占位赋值
            preparedStatement.setString(1,"jack");

            preparedStatement.setString(2,"1234 'or '1' = '1");

            //执行sql语句
            resultSet = preparedStatement.executeQuery();

            if (resultSet.next()){

                System.out.println("登录成功");

            }else {

                System.out.println("登录失败");
            }


        } catch (Exception exception) {

            exception.printStackTrace();

        }finally {

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

五、封装JDBC工具类

下面展示示例代码

import java.sql.*;

/**
 * 封装JDBC工具类
 * 1、构造方法私有化 不希望工具类可以实例化对象
 * 2、所有使用的方法用 static 关键字修饰 让其变成是类级别的方法 可以被类直接调用
 */
public class JDBCUtil {

    //构造方法私有化
    private JDBCUtil(){

    }

    /**
     * 把注册驱动的过程 写在静态代码块里,静态代码块在类加载的时候执行且只执行一次
     */
    static {

        //1、注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException exception) {
            exception.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     * @return
     */
    public static Connection getConnection() throws SQLException {

        //2、获取数据库连接
        Connection connection =
                DriverManager.getConnection("jdbc:mysql://localhost:3306/test_database","root","123456");

        return connection;
    }
    /**
     * 关闭数据库资源
     */
    public static void JDBCclose(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
        if (resultSet != null) {
            resultSet.close();
        }
        if (statement != null) {
            statement.close();
        }
        if (connection != null) {
            connection.close();
        }
    }
}

六、案例

下面展示示例代码

import java.sql.*;
/**
 * jbdc 事务
 * 在不开启jdbc情况下,只要执行了任意一条DML语句(增删改语句) 都会有一次事务的提交
 * 例子:银行 A账户 转账 给B账户  (事务的一致性)A账务 扣钱,发生异常,B不加钱
 */
public class JDBCDemo04 {

    public static void main(String[] args) {

        Connection connection =null;
        PreparedStatement preparedStatement = null;
        try {

            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //获取链接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test_database","root","123456");


            //开启事务 关闭自动提交模式 开启手动提交
            connection.setAutoCommit(false);

            //获取数据库操作对象并且预编译sql
            preparedStatement = connection.prepareStatement("update bank set a_bank = a_bank - ? where id = ?");
            //给占位赋值
            preparedStatement.setDouble(1,10000);
            preparedStatement.setInt(2,1);

            //执行sql语句
            int num = preparedStatement.executeUpdate();

            //模拟异常
            String str = null;
            str.split("123");

            //给账户加钱
            preparedStatement = connection.prepareStatement("update bank set b_bank = b_bank + ? where id = ?");
            //给占位赋值
            preparedStatement.setDouble(1,10000);
            preparedStatement.setInt(2,1);

            //执行sql语句
            num += preparedStatement.executeUpdate();

            System.out.println(num == 2?"执行成功":"执行失败");

            //提交事务
            connection.commit();

        }catch(Exception e){
            e.printStackTrace();
        }finally {

            try {
                if(connection != null){
                    //事务回滚
                    connection.rollback();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值