• JDBC —— 数据库连接


    JDBC介绍

    JDBC全称为Java Database Connectivity,直译过来就是Java数据库连接。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现。我们要连接数据库,就要去相应的数据库官网下载驱动,驱动都是以jar包的形式存在,jar包当中有很多.class文件,这些class文件就是JDBC接口的实现。本文针对MySQL数据库的连接实现。

    JDBC六部曲

    1. 注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌数据库)。
    2. 获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后要关闭通道)
    3. 获取数据库操作对象(专门执行sql语句的对象)。
    4. 执行sql语句。
    5. 处理查询结果集(只有第五步进行的是select语句的时候,才会到这一步)。
    6. 释放资源(使用完资源后一定要关闭资源)。

    数据库连接完整代码如下:

    import java.sql.*;
    public class JDBCTest06 {
        public static void main(String[] args) {
            Connection conn = null;
            Statement state = null;
            Driver driver = null;
            ResultSet rs = null;
            try {
                /*
                注册驱动
                在此处,Driver类型的对象driver和后面的com.mysql.cj.jdbc.Driver()并不是一个,它们是不同包下的。
                 */
                driver = new com.mysql.cj.jdbc.Driver();
                DriverManager.registerDriver(driver);
    
                /*
                第二步:获取连接
                这里的url是由以下部分组成的:
                协议:jdbc:mysql://
                数据库服务端ip地址:因为这里使用的是本机,所以写的是localhost
                数据库端口号:MySQL的专用端口号:3306
                数据库账号:root
                密码:111111
                 */
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/study2","root","111111");
    
                //获取数据库操作对象
                state = conn.createStatement();
    
                /*
                执行sql语句
                若执行DML语句(update,insert,delete),写法如下:
                state.executeUpdate("insert into user (id,name) value ("1", "张三")");
                下面演示的是执行DQL语句(select)
                 */
                rs = state.executeQuery("select *from user");
    
                /*
                处理查询结果
                如果rs中还有没有访问的记录,next()方法则会返回true
                如果访问的字段是varChar类型,则使用getString(),若访问字段是int类型,则使用getInt(),若访问字段是bigint,则使用getDouble(),其余同理。
                注意这里getStrng()以及同类型方法的传参,可以传一个字段名,也可以传要查询字段的下标(从1开始)
                */
                while(rs.next()){
                    System.out.println(rs.getString(1) + "   " + rs.getString(2));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                //释放资源,要从小到大释放
                if(rs != null){
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(state != null){
                    try {
                        state.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(conn != null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    在注册驱动时,我们现在并不会这样写,因为com.mysql.cj.jdbc.Driver类的源码中有如下静态代码块:
    在这里插入图片描述

    SQL注入

    我们在这里简单的利用数据库实现一个账号的登录。

    public static boolean Login(String loginName, String passWord){
            Connection conn = null;
            Statement state = null;
            ResultSet st = null;
            try {
                //注册驱动
                Class.forName("com.mysql.cj.jdbc.Driver");
                //获取连接
                conn = DriverManager.getConnection("jdbc:mysql://localhost/study2","root","111111");
                //获取数据库操作对象
                state = conn.createStatement();
                //执行查询语句
                st = state.executeQuery("select *from login where loginName ='" + loginName + "'and  loginPwd = '" + passWord + "'");
                if(st.next()){
                    return true;
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                if (state != null) {
                    try {
                        state.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    ;
                }
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里我们借助了SQL语句的拼接来实现了一个账号登录功能,其中loginName,和passWordd都是由用户来输入的。如果用户正常输入,例如:输入loginName为’‘111’‘,输入passWord为’‘12345678’',拼接之后的SQL语句如下:

    select * form login where loginName = '111' and passWord = '12345678'
    
    • 1

    只要用户输入的名字和密码是正确的,就会有查询结果,登录成功。

    如果用户在输入时输入了带有sql关键字的’非法信息’并且该非法信息串改了sql语句的原先的含义,导致未输入正确的信息也同样登录成功,例如:输入loginName为’‘111’',输入passWord为 ‘‘1' or ' 1' = '1’’,拼接之后的SQL语句如下:

    select * from login where loginName = '111' and passWord = '1' or '1' = '1';
    
    • 1

    用户如果这样输入就改变的SQL语句的原意,导致在不知道账号密码的情况下仍然登录成功,这就是SQL注入

    PerparedStatement

    上面使用Statement对象执行sql语句会造成SQL注入问题,Statement的子类PreparedStatement对象可以预编译SQL语句,从而避免了这种问题。

    使用PreparedStatement来实现一个简单的登入如下:

     public static boolean login(String loginName, String passWord){
            ResultSet rs = null;
            Connection conn = null;
            //预编译的数据库操作对象
            PreparedStatement ps = null;
            try {
                //注册驱动
                Class.forName("com.mysql.cj.jdbc.Driver");
                //连接数据库
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/study2","root","111111");
                //获取预编译的数据库操作对象
                ps = conn.prepareStatement("select * from login where loginName = ? and loginPwd = ?");
                //给占位符传值
                ps.setString(1,map.get("loginName"));
                ps.setString(2,map.get("passWord"));
                //执行sql语句
                rs = ps.executeQuery();
                //处理查询结果
                if(rs.next()){
                    return true;
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                if(ps != null){
                    try {
                        ps.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(conn != null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在该方法中我们通过调用数据库连接对象的prepareStatement(sql)方法获取的是预编译的数据库操作对象,在获取预编译的数据库操作对象时需要传入SQL语句的框子,其中它用占位符?来代替sql语句要接收的值。然后我们再用setString(int parameterIndex, String x) 方法给占位符‘ ?’传值。

    Statement 与 PreparedStatement比较

    1. Statement存在sql注入问题,PreparedStatement不存在sql注入问题。
    2. Statement每一次执行都需要对sql语句进行编译一次,效率较低,PreparedStatement只需要编译一次就可以执行N次,效率较高。
    3. PreparedStatement会在编译阶段做类型检查,但是Statement不会。
    4. PreparedStatement并不支持sql语句的拼接,Statement更加灵活。

    JDBC的事务机制

    1. JDBC中事务是自动提交的。只要执行一个DML语句,则会自动提交一次。
    2. 若conn为数据库连接对象,调用以下方法可以进行相关事务操作。
    	//关闭自动提交
    	conn.setAutoCommit(false);
    	//回滚事务
    	conn.rollback();
    	//提交事务
    	conn.commit();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    MASC: Multi-scale Affinity with Sparse Convolution for 3D Instance Segmentation
    redis 登录案例
    李沐动手学深度学习V2-BERT预训练和代码实现
    Kamailio default-routing-logic-flowchart
    qt day3
    无胁科技-TVD每日漏洞情报-2022-8-4
    xxl-job学习
    FunAudioLLM SenseVoice语音转录(ASR)与CosyVoice语音合成(TTS)及语音克隆使用案例;webui可视化页面操作使用
    openCV第一篇
    怎么恢复移走的u盘数据?可以尝试这三种方法
  • 原文地址:https://blog.csdn.net/m0_62969222/article/details/125445375