百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

一步一步学会JDBC

wxin55 2024-11-20 22:42 7 浏览 0 评论

一、JDBC基本知识

是什么

  • 英文全称:Java DataBase Connectivity(java语言连接数据库)
  • 是sun公司制定一套规范,一套接口

为什么要有JDBC(接口)

  • 因为每一个数据库的底层实现原理不一样,恰恰符合面向接口编程,下面解释

JDBC接口的调用者与实现者

  • 调用者:java程序员,调用这个接口就可以连接数据库并进行操作,而不管连接的是哪一个数据库
  • 实现者:各大数据库厂家,如:MySQL,SQL Sever,Oracle等等,该公司的程序员编写程序实现JDBC接口

一图搞懂JDBC接口

驱动:各大数据库厂家实现JDBC接口的实现类也叫驱动,也就是jar包,需要java程序员到官网上下载二、java中与JDBC相关的接口

相关的接口与类位于java.sql包下,

java与数据库的连接与操作靠这几个接口(类)就可以实现,并且调用前一个接口的方法可以生成,下一个类的对象,是层层递进的关系

三、JDBC编程的步骤

1.步骤总览

2.重点说下前三步

后三步的代码背后没有多少内容,所以先暂时放放

2.1注册驱动
  • 告诉java程序,即将要连接的是哪个品牌的数据库

导入MySQL的jar包(驱动)右击项目---->Open Module Settings

找到jar包点击ok即可

代码注册驱动

/**
 * @author Think-Coder
 * @data 2020/5/5 15:11
 */
import java.sql.*;
public class JDBCTest03
{
	public static void main(String[] args){
		try{
			//1.注册驱动常用方式
			//为什么常用:因为参数是一个字符串,字符串可以写道xxx.properties文件中
			Class.forName("com.mysql.jdbc.Driver");
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

com.mysql.jdbc.Driver类源码

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {}
    
    static {
        try {
        	//这个方法是注册MySQL驱动的
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

整个注册驱动方法驱动在static静态代码块中,当执行Class.forName(“com.mysql.jdbc.Driver”);时会加载com.mysql.jdbc.Driver类,此时static静态代码块执行,便会注册驱动了

2.2.获取Connection连接:DriverManager.getConnection方法

  • 表示JVM的进程和数据库进程之间的通道打开了
  • 进程通信,重量级的,使用完一定要关闭

方法参数需要提供

url(统一资源定位符)
			如:jdbc:mysql://127.0.0.1:3306/selfproj
			jdbc:mysql://  协议
			127.0.0.1      IP地址
			3306           端口号
			selfproj       数据库名
	账号:root
	密码:123456代码如下:

代码如下:

conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?characterEncoding=utf8","root","123456");

getConnection方法中是三个字符串参数,可以放在外部配置文件中

当更改数据库时,只要更改外部配置文件就搞定,不需要重新启动服务,这个很重要

咱们记住一条规律

只要参数是字符串,用户需要动态变化的,都可以写在外部配置文件中

2.3.获取数据库操作对象:通过Connection接口中的方法创建对象

try {
	    //1.注册驱动
	    Class.forName("com.mysql.jdbc.Driver");
	    //2.获取链接
	    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
	   
	    //3.获取数据库操作对象
	    stmt = conn.createStatement();
	    //4.执行sql
	    //存在sql注入问题
	    //假如此时userName="张三",userPwd="张三'or'1'='1"
	    //通过字符串拼接将sql关键字or拼接进去
	    //String sql="select * from user where name='张三' and pwd ='张三'or'1'='1'"
	    //不需要正确的用户名及密码就能此时就能进入系统
	    String sql = "select * from user where name='"+userName+"'and pwd ='"+userPwd+"'";
	    
	    //以上正好完成了sql语句的拼接
	    //以下代码的含义是,发送sql语句给DBMS,DBMS进行sql编译
	    rs = stmt.executeQuery(sql);
	    if(rs.next()){
	        loginSucess = true;
	    }
	}catch (Exception e) {
	    e.printStackTrace();
	}

因为存在SQL注入问题,平时开发基本不用Statement对象,所以没有贴完整得代码


3.JDBC完整的6步

接下来会写一个用户登录完整的代码将JDBC的6步完全融合进去,使用了PreparedStatement对象,操作数据库,是开发中最常用的

public class JDBCTest08 {
    public static void main(String[] args)  {
        //初始化一个界面
        Map<String,String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean loginSucess = false;
        try {
            loginSucess = login(userLoginInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(loginSucess?"登录成功":"登录失败");
    }
    
    //用户登录的方法
    public static boolean login(Map<String,String> userLoginInfo){
        //打标记
        boolean loginSucess = false;
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        //单独定义变量
        String userName = userLoginInfo.get("loginName");
        String userPwd = userLoginInfo.get("loginPwd");

        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取链接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "123456");
            
            //3.获取数据库预编译PreparedStatement对象
            //sql语句框子,一个?代表一个占位符
            
            String sql = "select * from test where id=? and pwd=?";
            //程序执行到此,会发送sql语句框子给DBMS,然后DBMS进行sql语句的预先编译
            //此时sql语句中没有用户输入的值,很好的解决了sql注入问题
            ps = conn.prepareStatement(sql);
            //给?占位符传值
            ps.setString(1, userName);
            ps.setString(2, userPwd);

            //4.执行sql
            rs = ps.executeQuery();
            
            //5.处理返回的结果集
            // rs为返回的结果集
            if (rs.next()) {
                loginSucess = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            //6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return loginSucess;
    }
    //用户输入的方法
    private static Map<String, String> initUI() {
        Scanner s = new Scanner(System.in);

        System.out.println("用户名:");
        String loginName = s.nextLine();

        System.out.println("密码:");
        String loginPwd = s.nextLine();

        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);

        return userLoginInfo;
    }
}

解释说明

完整的JDBC编程6步就写完了,JDBC编程6步是针对于查询的

对于增删改的,是不需要第5步的,因为没有返回查询结果集

使用增删改时,只需将第4步ps.executeQuery()变为ps.executeUpdate()就可以了,代码我就不写了,哈哈

下面对比Statement对象和PreparedStatement对象

1.Statement存在sql注入问题,PreparedStatement解决了sql注入问题。

2.PreparedStatement执行效率高,编译一次执行多次,因为相同的sql语句不会再编译

而Statement编译一次执行一次,因为基本上sql语句不会相同

3.PreparedStatement会在编译阶段做类型检查

总结:开发场景中99%使用PreparedStatement对象,在需要SQL注入的业务场景中使用Statement

四.封装工具类

注册驱动、连接数据库和释放连接经常使用可以封装到工具类中

public class DBUtil {
    /*
    * 工具类中的构造方法都是私有的
    * 因为工具类当中的方法是静态的,不需要new对象,直接采用类名调用
    * */
    private DBUtil(){}

    //静态代码块在类加载时执行,并且只执行一次
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /*
    * 获取数据库连接对象
    * */
    public static Connection getConnection()throws Exception{
        return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/selfproj?useUnicode=true&characterEncoding=utf8","root","123456");
    }
    /*
    * 关闭资源
    * */
    public static void close(Connection conn, Statement ps, ResultSet rs){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

使用工具类,实现模糊查询

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

        try {
            //使用工具类获取连接
            conn=DBUtil.getConnection();
            
            //获取预编译的数据库操作对象
            String sql = "select * from user where pwd like ?";
            ps = conn.prepareStatement(sql);
            
            //实现查询密码第二位是2的
            ps.setString(1,"_2%");
            rs=ps.executeQuery();
            while(rs.next()){
                System.out.println(rs.getString("pwd"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //使用工具类释放资源
            DBUtil.close(conn,ps,rs);
        }
    }

五、总结

JDBC是一套让各个数据库厂家实现的接口,通过调用这些接口,实现java程序连接数据库,很好体现面向接口编程的特点

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: