• python网络编程学习笔记(二)


    python网络编程学习(四)

    多用途客户端协议
    一、ftp
    功能:上传下载文件,删除命名文件,建立删除目录,自动压缩,保存目录
    1.代码:

    #coding=utf-8
    '''连接远程ftp服务器,显示问候语,并打印当前工作目录'''
    from ftplib import FTP
    
    f = FTP('ftp.ibiblio.org')
    print "Welcome:", f.getwelcome()
    f.login()#匿名登陆
    
    print "CWD:", f.pwd()
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/connect.py
    Welcome: 220 ProFTPD Server
    CWD: /

    Process finished with exit code 0

    2.以ascii形式下载文件
    ftp以两种形式传输文件,ASCII和二进制文件
    代码1:

    #coding=utf-8
    
    from ftplib import FTP
    
    def writeline(data):
        fd.write(data + "
    ")
    
    #f = FTP('ftp.kernel.org')
    f=FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')#在远处系统转换目录
    fd = open('README', 'wt')
    f.retrlines('RETR README', writeline)
    #开始传输,第一个参数指定一个在远程系统运行的命令,后一个文件名;第二个参数是函数,客户端每收到一行数据运行一次函数;
    #如果省略,数据会被输出到标准输出设备上。
    fd.close()
    
    f.quit()
    

    运行结果:

    README文件:
    README for kernel

    What you'll find here: kernel sources and patches

    注:使用python实现一个基于socket的c/s模式文件传输程序。出现error: [Errno 10061]错误。查找资料提示是”目标机器积极拒绝连接”。
    原因说法不过有3种:
    检查目的地址或端口号书写出错。
    人工检查一下代码便可排除。
    目标防火墙未关闭。
    使用ping命令,验证目标是否有回应,必要时可用telnet,nmap等工具尝试验证目标端口开放情况。
    软件或网络状况原因。
    查看python是否有联网权限,当前网络是否畅通等。
    3.以二进制形式下载文件
    代码:

    #coding=utf-8
    
    from ftplib import FTP
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    fd = open('README', 'wb')
    f.retrbinary('RETR README', fd.write)
    #retrbinary()向指定的函数输出整块数据
    fd.close()
    
    f.quit()
    

    4.以高级形式下载文件
    ntransfercmd()函数,了解传输文件细节;
    代码:

    #coding=utf-8
    
    from ftplib import FTP
    import sys
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    #向服务器传输一条指令,检差有没有错
    f.voidcmd("TYPE I")#TYPE I表示以二进制模式传输
    #retrbinary()会在后台自动执行下载指令,nsransfercmd()不会
    datasock, estsize = f.ntransfercmd("RETR README")
    transbytes = 0
    fd = open('README', 'wb')
    while 1:
        buf = datasock.recv(2048)
        if not len(buf):
            break
        fd.write(buf)
        transbytes += len(buf)
        sys.stdout.write("Received %d " % transbytes)
    
        if estsize:
            sys.stdout.write("of %d bytes (%.1f%%)
    " % 
                    (estsize, 100.0 * float(transbytes) / float(estsize)))
        else:
            sys.stdout.write("bytes
    ")
        sys.stdout.flush()
    sys.stdout.write("
    ")
    fd.close()
    datasock.close()
    f.voidresp()#获得服务器响应,报错
    
    
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/advbinarydl.py
    Received 70 of 70 bytes (100.0%)

    Process finished with exit code 0

    5.上传数据
    storbinary() read(),storlines() readline()

    #coding=utf-8
    
    from ftplib import FTP
    import sys, getpass, os.path
    
    host, username, localfile, remotepath = sys.argv[1:]
    password = getpass.getpass("Enter password for %s on %s: " % 
            (username, host))
    f = FTP(host)
    f.login(username, password)
    
    f.cwd(remotepath)
    f.voidcmd("TYPE I")
    
    fd = open(localfile, 'rb')
    datasock, esize = f.ntransfercmd('STOR %s' % os.path.basename(localfile))
    esize = os.stat(localfile)[6]
    transbytes = 0
    
    while 1:
        buf = fd.read(2048)
        if not len(buf):
            break
        datasock.sendall(buf)
        transbytes += len(buf)
        sys.stdout.write("Sent %d of %d bytes (%.1f%%)
    " % (transbytes, esize,
            100.0 * float(transbytes) / float(esize)))
        sys.stdout.flush()
    datasock.close()#通知服务器上传结束
    sys.stdout.write("
    ")
    fd.close()
    f.voidresp()
    
    f.quit()
    

    6.高级二进制模式上传

    #cosing=utf-8
    
    from ftplib import FTP
    import sys, getpass, os.path
    
    host, username, localfile, remotepath = sys.argv[1:]
    password = getpass.getpass("Enter password for %s on %s: " % 
            (username, host))
    f = FTP(host)
    f.login(username, password)
    
    f.cwd(remotepath)
    fd = open(localfile, 'rb')
    f.storbinary('STOR %s' % os.path.basename(localfile), fd)
    #f.storline('STOR %s' % os.path.basename(localfile), fd)
    #以二进制形式上传
    fd.close()
    
    f.quit()
    

    7.错误处理
    8.扫描目录
    通过 nlst(),dir()函数
    nlst()函数返回给定目录下的一系列条目(信息)。当前位置下所有文件何目录的列表。没有区分文件还是目录。
    dir()可以从远方服务器上返回一个目录的列表。与unix ls -l输出一样。
    (1)nlst()
    代码:

    #coding=utf-8
    
    from ftplib import FTP
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    entries = f.nlst()
    entries.sort()
    
    print "%d entries:" % len(entries)
    for entry in entries:
        print entry
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/nlst.py
    58 entries:
    !INDEX
    !INDEX.html
    !INDEX.short.html
    COPYING
    LFSBOOK_ED1.iso
    LFSBOOK_ED1.lsm
    README
    changes
    config
    esep-1.5.lsm
    esep-1.5.tgz
    getkernel-1.1.1.tar.gz
    getkernel.lsm
    getpatch-2.21.lsm
    getpatch-2.21.tar.gz
    images
    irq-1.71.tar.gz
    irq.lsm
    iso9660-compress-2.0.tar.gz
    iso9660-compress.lsm
    kdebug-1.1.tgz
    kernel-2.1.33.dial_on_demand_patch.gz
    kernel-2.1.33.dial_on_demand_patch.lsm
    kscripts-2.1.40.lsm
    kscripts-2.1.40.tar.gz
    linux-lite-v1.00.diff.gz
    linux-lite-v1.00.lsm
    linux-lite-v1.00.relnotes
    linux-lite-v1.00.tar.gz
    misc-cards
    modremove-1.01.lsm
    modremove-1.01.tar.gz
    modules-2.0.0.lsm
    modules-2.0.0.tar.gz
    modules-3.1.3-3.1.4.diff.bz2
    modules-3.1.3-3.1.4.diff.gz
    modules-3.1.4.tar.bz2
    modules-3.1.4.tar.gz
    modules.lsm
    patches
    pcmcia
    profil.lsm
    profil.tgz
    readprofile-2.0.lsm
    readprofile-2.0.tar.gz
    rfs-2.13-4.lsm
    rfs-2.13-4.tar.bz2
    sound
    tapes
    udma-generic-0.2.1.lsm
    udma-generic-0.2.1.tar.gz
    upgrade-in-a-box.2.29.lsm
    upgrade-in-a-box.2.29.tar.gz
    vuzkern-1.0.lsm
    vuzkern.gz
    xabt-1.0a.beta.README
    xabt-1.0a.beta.bin.tar.gz
    xabt-1.0a.beta.lsm

    Process finished with exit code 0

    (2)dir()
    代码:

    #coding=utf-8
    
    from ftplib import FTP
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    entries = []
    f.dir(entries.append)
    
    print "%d entries:" % len(entries)
    for entry in entries:
        print entry
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/dir.py
    58 entries:
    drwxrwsr-x 2 1029 704 4096 Feb 20 1997 changes
    drwxrwsr-x 2 1029 704 4096 Feb 18 2000 config
    -r--rw-r-- 1 1029 704 17982 Jun 26 1994 COPYING
    -rw-rw-r-- 1 1029 704 1164 Dec 29 1997 esep-1.5.lsm
    -rw-rw-r-- 1 1029 704 20691 Dec 29 1997 esep-1.5.tgz
    -rw-rw-r-- 1 1029 704 9014 Feb 2 1998 getkernel-1.1.1.tar.gz
    -rw-rw-r-- 1 1029 704 586 Jan 27 1998 getkernel.lsm
    -rw-r--r-- 1 1029 704 1204 Apr 24 2004 getpatch-2.21.lsm
    -rw-r--r-- 1 1029 704 3841 Apr 24 2004 getpatch-2.21.tar.gz
    drwxrwsr-x 2 1029 704 4096 Feb 11 1999 images
    -rw-rw-r-- 1 1029 704 2596 Nov 7 2007 !INDEX
    -rw-rw-r-- 1 1029 704 9081 Nov 7 2007 !INDEX.html
    -rw-rw-r-- 1 1029 704 4114 Nov 7 2007 !INDEX.short.html
    -rw-r--r-- 1 1029 704 111147 Jul 14 2003 irq-1.71.tar.gz
    -rw-r--r-- 1 1029 704 763 Jul 18 2003 irq.lsm
    -rw-rw-r-- 1 1029 704 25314 Mar 13 1998 iso9660-compress-2.0.tar.gz
    -rw-rw-r-- 1 1029 704 668 Mar 13 1998 iso9660-compress.lsm
    -rw-rw-r-- 1 1029 704 5849 Feb 27 1995 kdebug-1.1.tgz
    -rw-rw-r-- 1 1029 704 636 Apr 15 1997 kernel-2.1.33.dial_on_demand_patch.gz
    -rw-rw-r-- 1 1029 704 519 Apr 15 1997 kernel-2.1.33.dial_on_demand_patch.lsm
    -rw-rw-r-- 1 1029 704 612 May 28 1997 kscripts-2.1.40.lsm
    -rw-rw-r-- 1 1029 704 20522 May 28 1997 kscripts-2.1.40.tar.gz
    -rw-r--r-- 1 1029 704 707048680 Nov 21 2003 LFSBOOK_ED1.iso
    -rw-r--r-- 1 1029 704 956 Nov 20 2003 LFSBOOK_ED1.lsm
    -rw-rw-r-- 1 1029 704 31732 Apr 28 1998 linux-lite-v1.00.diff.gz
    -rw-rw-r-- 1 1029 704 779 Apr 28 1998 linux-lite-v1.00.lsm
    -rw-rw-r-- 1 1029 704 7406 Apr 28 1998 linux-lite-v1.00.relnotes
    -rw-rw-r-- 1 1029 704 1259801 Apr 28 1998 linux-lite-v1.00.tar.gz
    drwxrwsr-x 2 1029 704 4096 Jan 31 2001 misc-cards
    -rw-rw-r-- 1 1029 704 563 Nov 2 1998 modremove-1.01.lsm
    -rw-rw-r-- 1 1029 704 10367 Nov 2 1998 modremove-1.01.tar.gz
    -rw-rw-r-- 1 1029 704 588 Jun 12 1996 modules-2.0.0.lsm
    -rw-rw-r-- 1 1029 704 115459 Jun 12 1996 modules-2.0.0.tar.gz
    -rw-rw-r-- 1 1029 704 14780 Aug 3 2001 modules-3.1.3-3.1.4.diff.bz2
    -rw-rw-r-- 1 1029 704 14811 Aug 3 2001 modules-3.1.3-3.1.4.diff.gz
    -rw-rw-r-- 1 1029 704 293843 Aug 3 2001 modules-3.1.4.tar.bz2
    -rw-rw-r-- 1 1029 704 375034 Aug 3 2001 modules-3.1.4.tar.gz
    -rw-rw-r-- 1 1029 704 1369 Aug 3 2001 modules.lsm
    drwxrwsr-x 10 1029 704 4096 Feb 11 1999 patches
    drwxr-xr-x 2 root root 4096 Dec 4 2006 pcmcia
    -rw-rw-r-- 1 1029 704 466 Jul 13 1997 profil.lsm
    -rw-rw-r-- 1 1029 704 1581 Feb 20 1995 profil.tgz
    -rw-r--r-- 1 1029 704 70 Nov 7 2007 README
    -rw-rw-r-- 1 1029 704 532 May 16 1996 readprofile-2.0.lsm
    -rw-rw-r-- 1 1029 704 4068 May 16 1996 readprofile-2.0.tar.gz
    -rw-r--r-- 1 1029 704 629 Oct 29 2007 rfs-2.13-4.lsm
    -rw-r--r-- 1 1029 704 19735 Oct 29 2007 rfs-2.13-4.tar.bz2
    drwxrwsr-x 2 1029 704 4096 Apr 23 2001 sound
    drwxrwsr-x 2 1029 704 4096 Jul 26 2000 tapes
    -rw-rw-r-- 1 1029 704 875 May 10 1998 udma-generic-0.2.1.lsm
    -rw-rw-r-- 1 1029 704 14536 May 10 1998 udma-generic-0.2.1.tar.gz
    -rw-rw-r-- 1 1029 704 1124 Feb 9 1997 upgrade-in-a-box.2.29.lsm
    -rw-rw-r-- 1 1029 704 18479392 Feb 9 1997 upgrade-in-a-box.2.29.tar.gz
    -rw-rw-r-- 1 1029 704 747 Sep 18 1995 vuzkern-1.0.lsm
    -rw-rw-r-- 1 1029 704 1497 Sep 18 1995 vuzkern.gz
    -rw-rw-r-- 1 1029 704 173279 May 25 1998 xabt-1.0a.beta.bin.tar.gz

    -rw-rw-r-- 1 1029 704 422 May 25 1998 xabt-1.0a.beta.lsm
    -rw-rw-r-- 1 1029 704 735 May 25 1998 xabt-1.0a.beta.README

    Process finished with exit code 0

    9.解析unix目录表
    代码:

    #coding=utf-8
    from ftplib import FTP
    
    #在一个目录中的单独条目
    class DirEntry:
        def __init__(self, line):
            self.parts = line.split(None, 8)
    
        def isvalid(self):
            return len(self.parts) >= 6
    
        def gettype(self):
            """Returns - for regular file; d for directory; l for symlink."""
            return self.parts[0][0]
    
        def getfilename(self):
            if self.gettype() != 'l':
                return self.parts[-1]
            else:
                return self.parts[-1].split(' -> ', 1)[0]
    
        def getlinkdest(self):
            if self.gettype() == 'l':
                return self.parts[-1].split(' -> ', 1)[1]
            else:
                raise RuntimeError, "getlinkdest() called on non-link item"
    
    class DirScanner(dict):
        #把从dir()得到的一行数据作为参数,有效加到dict
        def addline(self, line):
            obj = DirEntry(line)
            if obj.isvalid():
                self[obj.getfilename()] = obj
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    d = DirScanner()
    f.dir(d.addline)
    
    print "%d entries:" % len(d.keys())
    for key, value in d.items():
        print "%s: type %s" % (key, value.gettype())
    
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/dirparse.py
    58 entries:
    getkernel.lsm: type -
    modules-3.1.4.tar.bz2: type -
    modules.lsm: type -
    linux-lite-v1.00.relnotes: type -
    modremove-1.01.lsm: type -
    getkernel-1.1.1.tar.gz: type -
    upgrade-in-a-box.2.29.tar.gz: type -
    COPYING: type -
    images: type d
    vuzkern-1.0.lsm: type -
    pcmcia: type d
    profil.tgz: type -
    linux-lite-v1.00.diff.gz: type -
    misc-cards: type d
    kscripts-2.1.40.tar.gz: type -
    modules-3.1.4.tar.gz: type -
    profil.lsm: type -
    modules-3.1.3-3.1.4.diff.bz2: type -
    xabt-1.0a.beta.bin.tar.gz: type -
    getpatch-2.21.tar.gz: type -
    rfs-2.13-4.tar.bz2: type -
    readprofile-2.0.lsm: type -
    README: type -
    linux-lite-v1.00.tar.gz: type -
    config: type d
    udma-generic-0.2.1.tar.gz: type -
    modules-2.0.0.tar.gz: type -
    !INDEX: type -
    sound: type d
    LFSBOOK_ED1.lsm: type -
    patches: type d
    esep-1.5.tgz: type -
    modules-2.0.0.lsm: type -
    rfs-2.13-4.lsm: type -
    xabt-1.0a.beta.lsm: type -
    kdebug-1.1.tgz: type -
    udma-generic-0.2.1.lsm: type -
    modremove-1.01.tar.gz: type -
    !INDEX.html: type -
    upgrade-in-a-box.2.29.lsm: type -
    !INDEX.short.html: type -
    vuzkern.gz: type -
    irq.lsm: type -
    kernel-2.1.33.dial_on_demand_patch.lsm: type -
    kscripts-2.1.40.lsm: type -
    tapes: type d
    getpatch-2.21.lsm: type -
    esep-1.5.lsm: type -
    LFSBOOK_ED1.iso: type -
    linux-lite-v1.00.lsm: type -
    readprofile-2.0.tar.gz: type -
    kernel-2.1.33.dial_on_demand_patch.gz: type -
    xabt-1.0a.beta.README: type -
    iso9660-compress-2.0.tar.gz: type -
    modules-3.1.3-3.1.4.diff.gz: type -
    changes: type d
    irq-1.71.tar.gz: type -
    iso9660-compress.lsm: type -

    Process finished with exit code 0

    10.不用解析表而得到目录信息
    代码:

    #coding=utf-8
    
    import ftplib
    
    class DirEntry:
        def __init__(self, filename, ftpobj, startingdir = None):
            self.filename = filename
            if startingdir == None:
                startingdir = ftpobj.pwd()
            try:
                ftpobj.cwd(filename)
                self.filetype = 'd'
                ftpobj.cwd(startingdir)
            except ftplib.error_perm:
                self.filetype = '-'
    
        def gettype(self):
            """Returns - for regular file; d for directory."""
            return self.filetype
    
        def getfilename(self):
            return self.filename
    
    f = ftplib.FTP('ftp.ibiblio.org')
    f.login()
    
    f.cwd('/pub/linux/kernel')
    nitems = f.nlst()
    items = [DirEntry(item, f, f.pwd()) for item in nitems]
    
    print "%d entries:" % len(items)
    for item in items:
        print "%s: type %s" % (item.getfilename(), item.gettype())
    f.quit()
    

    运行结果:

    D:pythonpython.exe E:/code/python/chap4/nlstscan.py
    58 entries:
    changes: type d
    config: type d
    images: type d
    misc-cards: type d
    patches: type d
    pcmcia: type d
    sound: type d
    tapes: type d
    !INDEX.html: type -
    !INDEX: type -
    iso9660-compress-2.0.tar.gz: type -
    !INDEX.short.html: type -
    COPYING: type -
    LFSBOOK_ED1.iso: type -
    LFSBOOK_ED1.lsm: type -
    README: type -
    esep-1.5.lsm: type -
    esep-1.5.tgz: type -
    getkernel-1.1.1.tar.gz: type -
    getkernel.lsm: type -
    getpatch-2.21.lsm: type -
    getpatch-2.21.tar.gz: type -
    irq-1.71.tar.gz: type -
    irq.lsm: type -
    linux-lite-v1.00.relnotes: type -
    iso9660-compress.lsm: type -
    kdebug-1.1.tgz: type -
    kscripts-2.1.40.lsm: type -
    kernel-2.1.33.dial_on_demand_patch.gz: type -
    kernel-2.1.33.dial_on_demand_patch.lsm: type -
    kscripts-2.1.40.tar.gz: type -
    linux-lite-v1.00.diff.gz: type -
    linux-lite-v1.00.lsm: type -
    modules-3.1.3-3.1.4.diff.bz2: type -
    linux-lite-v1.00.tar.gz: type -
    modremove-1.01.lsm: type -
    modremove-1.01.tar.gz: type -
    modules-2.0.0.lsm: type -
    modules-2.0.0.tar.gz: type -
    rfs-2.13-4.lsm: type -
    modules-3.1.3-3.1.4.diff.gz: type -
    modules-3.1.4.tar.bz2: type -
    modules-3.1.4.tar.gz: type -
    modules.lsm: type -
    profil.lsm: type -
    profil.tgz: type -
    readprofile-2.0.lsm: type -
    readprofile-2.0.tar.gz: type -
    udma-generic-0.2.1.lsm: type -
    udma-generic-0.2.1.tar.gz: type -
    upgrade-in-a-box.2.29.lsm: type -
    upgrade-in-a-box.2.29.tar.gz: type -
    vuzkern-1.0.lsm: type -
    vuzkern.gz: type -
    xabt-1.0a.beta.README: type -
    xabt-1.0a.beta.bin.tar.gz: type -
    xabt-1.0a.beta.lsm: type -
    rfs-2.13-4.tar.bz2: type -

    Process finished with exit code 0

    11.递归下载
    代码:

    #coding=utf-8
    from ftplib import FTP
    import os, sys
    
    class DirEntry:
        def __init__(self, line):
            self.parts = line.split(None, 8)
    
        def isvalid(self):
            return len(self.parts) >= 6
    
        def gettype(self):
            return self.parts[0][0]
    
        def getfilename(self):
            if self.gettype() != 'l':
                return self.parts[-1]
            else:
                return self.parts[-1].split(' -> ', 1)[0]
    
        def getlinkdest(self):
            if self.gettype() == 'l':
                return self.parts[-1].split(' -> ', 1)[1]
            else:
                raise RuntimeError, "getlinkdest() called on non-link item"
    
    class DirScanner(dict):
        def addline(self, line):
            obj = DirEntry(line)
            if obj.isvalid():
                self[obj.getfilename()] = obj
    
    def downloadfile(ftpobj, filename):
        ftpobj.voidcmd("TYPE I")
        datasock, estsize = ftpobj.ntransfercmd("RETR %s" % filename)
        transbytes = 0
        fd = open(filename, 'wb')
        while 1:
            buf = datasock.recv(2048)
            if not len(buf):
                break
            fd.write(buf)
            transbytes += len(buf)
            sys.stdout.write("%s: Received %d " % (filename, transbytes))
            if estsize:
                sys.stdout.write("of %d bytes (%.1f%%)
    " % (estsize,
                    100.0 * float(transbytes) / float(estsize)))
            else:
                sys.stdout.write("bytes
    ")
        fd.close()
        datasock.close()
        ftpobj.voidresp()
        sys.stdout.write("
    ")
    
    
    def downloaddir(ftpobj, localpath, remotepath):
        print "*** Processing directory", remotepath
        localpath = os.path.abspath(localpath)
        oldlocaldir = os.getcwd()
        if not os.path.isdir(localpath):
            os.mkdir(localpath)
        olddir = ftpobj.pwd()
        try:
            os.chdir(localpath)
            ftpobj.cwd(remotepath)
            d = DirScanner()
            f.dir(d.addline)
    
            for filename, entryobj in d.items():
                if entryobj.gettype() == '-':
                    downloadfile(ftpobj, filename)
                elif entryobj.gettype() == 'd':
                    downloaddir(ftpobj, localpath + '/' + filename,
                            remotepath + '/' + filename)
                    # Re-display directory info
                    print "*** Processing directory", remotepath
        finally:
            os.chdir(oldlocaldir)
            ftpobj.cwd(olddir)
    
    f = FTP('ftp.ibiblio.org')
    f.login()
    
    downloaddir(f, 'kernel', '/pub/linux/kernel')
    
    f.quit()
    

    12.操作服务器上的文件和目录
    delete()删除一个文件
    rmd()删除一个目录
    mkdir()建立目录
    rename()移动重命名文件夹

    本性的苏醒,往往在遭遇真实之后。
  • 相关阅读:
    优化页面响应时间
    php性能优化
    加快compser install 和update的方法
    好用的类库
    php会话(session)实现原理
    mysql引擎
    数据库事物四大特性
    数据库索引
    insert和insertSelective区别
    java面试题之int和Integer的区别
  • 原文地址:https://www.cnblogs.com/chance88/p/6593781.html
Copyright © 2020-2023  润新知