V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Lyv5
V2EX  ›  Java

各位 Java 大佬好,先给大佬倒茶。关于 jdbc 与 mysql 交互问题

  •  1
     
  •   Lyv5 · 2021-11-04 17:20:14 +08:00 · 2398 次点击
    这是一个创建于 1141 天前的主题,其中的信息可能已经有所发展或是发生改变。

    是这样我想知道 jdbc 与 mysql 交互,源码上网边看边查到 mysqlIO.class ,问题是我如果 jdbc 里面数据库名或者密码错了(虽然我知道错的),底层是怎么判断的 ,目的是要这套判断,和判断结果,套用在自己的数据上面,相当于借用他们的标准套在我们的数据库上面,以后也好形成统一。 还望各位大佬们不吝赐教,指条明路。我是菜鸡,只管喷。 祝大佬 情绪稳定,睡眠良好,头发浓密

    目前代码看到这里 mysqlIO.class

    void secureAuth411(Buffer packet, int packLength, String user, String password, String database, boolean writeClientParams) throws SQLException { String enc = this.getEncodingForHandshake(); if (packet == null) { packet = new Buffer(packLength); }

    if (writeClientParams) {
        if (this.use41Extensions) {
            if (this.versionMeetsMinimum(4, 1, 1)) {
                packet.writeLong(this.clientParam);
                packet.writeLong((long)this.maxThreeBytes);
                this.appendCharsetByteForHandshake(packet, enc);
                packet.writeBytesNoNull(new byte[23]);
            } else {
                packet.writeLong(this.clientParam);
                packet.writeLong((long)this.maxThreeBytes);
            }
        } else {
            packet.writeInt((int)this.clientParam);
            packet.writeLongInt(this.maxThreeBytes);
        }
    }
    // 设置用户名
    packet.writeString(user, enc, this.connection);
    if (password.length() != 0) {
        packet.writeByte((byte)20);
    
        
        try {
            // 设置密码 
            packet.writeBytesNoNull(Security.scramble411(password, this.seed, this.connection.getPasswordCharacterEncoding()));
        } catch (NoSuchAlgorithmException var11) {
            throw SQLError.createSQLException(Messages.getString("MysqlIO.95") + Messages.getString("MysqlIO.96"), "S1000", this.getExceptionInterceptor());
        } catch (UnsupportedEncodingException var12) {
            throw SQLError.createSQLException(Messages.getString("MysqlIO.95") + Messages.getString("MysqlIO.96"), "S1000", this.getExceptionInterceptor());
        }
    } else {
        packet.writeByte((byte)0);
    }
    
    // 设置数据库名
    if (this.useConnectWithDb) {
        packet.writeString(database, enc, this.connection);
    } else {
        packet.writeByte((byte)0);
    }
    
    if ((this.serverCapabilities & 1048576) != 0) {
        this.sendConnectionAttributes(packet, enc, this.connection);
    }
    // 向 Mysql 服务器发送登录信息包(用户名、密码、此 Socket 连接默认选择的数据库)
    this.send(packet, packet.getPosition());
    byte var10002 = this.packetSequence;
    this.packetSequence = (byte)(var10002 + 1);
    byte savePacketSequence = var10002;
    
    // 读取 Mysql 服务器登录检验后发送的状态信息,如果成功就返回,如果登录失败则抛出异常 
    Buffer reply = this.checkErrorPacket();
    if (reply.isLastDataPacket()) {
        ++savePacketSequence;
        this.packetSequence = savePacketSequence;
        packet.clear();
        String seed323 = this.seed.substring(0, 8);
        packet.writeString(Util.newCrypt(password, seed323));
        this.send(packet, packet.getPosition());
        this.checkErrorPacket();
    }
    

    }

    第 1 条附言  ·  2021-11-05 11:01:16 +08:00

    在mysqlIO源码里面有个this.readFully(this.mysqlInput, reuse.getByteBuffer(), 0, packetLength); 这个应该是读取发送登录信息后mysql服务端返回的响应

    private void checkErrorPacket(Buffer resultPacket)

    这个应该是读取发送登录信息后mysql服务端返回的响应,登录正常直接返回,错误就抛异常。

    不看mysql端 就是怎么知道密码错误或用户名错误返回的异常或者是报错代码就行。利用这个错误在自己的数据库上面 发生同错误也会报这样的异常或错误

    我脑子卡死了一团浆糊

    12 条回复    2021-11-08 09:08:54 +08:00
    xiangyuecn
        1
    xiangyuecn  
       2021-11-04 17:48:27 +08:00
    你的段位不是菜鸡,是会写数据库驱动的牛逼大佬🐶
    AlbertChen
        2
    AlbertChen  
       2021-11-04 18:03:04 +08:00
    misaka19000
        3
    misaka19000  
       2021-11-04 18:12:43 +08:00
    直接 tcpdump 抓包看
    zjsxwc
        4
    zjsxwc  
       2021-11-04 18:39:55 +08:00 via Android
    膜拜大佬
    Lyv5
        5
    Lyv5  
    OP
       2021-11-05 08:39:31 +08:00
    @AlbertChen 好的我研究下
    Lyv5
        6
    Lyv5  
    OP
       2021-11-05 08:39:52 +08:00
    @xiangyuecn 大哥我真菜鸡
    lei2j
        7
    lei2j  
       2021-11-05 09:30:44 +08:00
    你都搞这个了,那我就是菜鸡中的弱鸡了
    yizmaoaa
        8
    yizmaoaa  
       2021-11-05 09:56:54 +08:00
    其实你在驱动里是看不到怎么判断用户名密码是错的,驱动包也只是根据数据库的协议发包的。至于用户名密码是对的还是错的,是你驱动包发数据过去,然后 Mysql Server 里判断然后给客户端返回异常信息的
    Lyv5
        9
    Lyv5  
    OP
       2021-11-05 10:23:38 +08:00
    @yizmaoaa 大哥请留步,我一直看的是 java 端的源码,你的意思是我应该去找 mysql 端做了什么判断是嘛
    DsuineGP
        10
    DsuineGP  
       2021-11-05 14:14:20 +08:00
    @Lyv5 可以看一下 mycat 鉴权这一块的代码,也是用 java 写的,大致的逻辑跟你想实现的很像,拦截 mysql 一端的错误信息并包装一层放回给客户端
    vinle
        11
    vinle  
       2021-11-05 14:49:52 +08:00
    首先膜拜一下,楼主过于谦虚,能为一个新的数据库作贡献是非常强的了。

    然后对于 LZ 的问题,

    “底层是怎么判断的” :mysql 的 server 与 client 通信已经算是很高层的实现了,至于底层,楼主没说清楚到底多底层,看楼主的代码注释应该是指:Client (使用 jdbc 的客户端程序)识别 Server(数据库服务器)返回的 Packet (响应)的过程中,怎么判断 mysql 的错误类型的。
    其实楼主已经分析得非常完整了,因为就是 MysqlIO 类的 checkErrorPacket 来判断的,更完整的调用链是:/ secureAuth411 / -> / checkErrorPacket() / -> / checkErrorPacket(-1) / -> / checkErrorPacket(resultPacket) / -> / 你要的逻辑 /

    “不看 mysql 端 就是怎么知道密码错误...” : 关于这个,一般来说这些错误代码的规范,都会有公开的文档,方便 mysql 社区参考,所以不用担心一般不需要深入到 mysql 的源码里边,对于特定版本的规范也应该不一样,我就随便找了个版本索引一下了: https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-error-sqlstates.html ,进去后直接搜“PASSWORD”大概率就能找到你想要的了。
    Lyv5
        12
    Lyv5  
    OP
       2021-11-08 09:08:54 +08:00
    @vinle 首先感谢老哥,给老哥倒一杯热咖啡,提出的思路是对的,以及老哥给的 mysql 连接,我也查过去了。得到了想要的,菜鸡提的问题有点模糊还望海涵 ,最后还是谢谢老哥指导。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1006 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 21:51 · PVG 05:51 · LAX 13:51 · JFK 16:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.