严肃的皮蛋 · sql like 多个值 - CSDN文库· 3 周前 · |
发财的山寨机 · 高级查询 · ...· 3 周前 · |
健壮的大象 · sql server ...· 3 周前 · |
谦和的皮带 · datagrip连接sql ...· 2 周前 · |
小胡子的日光灯 · 2021-11-23 ...· 1 年前 · |
寂寞的茶叶 · mac端 electron 应用自动更新 - 简书· 1 年前 · |
私奔的棒棒糖 · 安装webpack 报错 npm ERR! ...· 1 年前 · |
MySQL的驱动:
2、pymysql使用
安装 :pip install pymysql
创建数据库和表:
1 CREATE DATABASE IF NOT EXISTS school; 2 SHOW DATABASES ; 3 USE school 5 CREATE TABLE `students` ( 6 id int(10) NOT NULL AUTO_INCREMENT, 7 name VARCHAR(20) NOT NULL , 8 age INT(10) DEFAULT NULL , 9 PRIMARY KEY (id) 10 ) ENGINE =InnoDB DEFAULT CHARSET = utf8mb4
连接Connect:
首先,必须建立一个传输数据通道------连接
pymsql.connect() 方法返回的是Connections 模块下的Connection类实例,connect方法传参就是给Connection类的__init__ 提供参数。
3 Representation of a socket with a mysql server. 5 The proper way to get an instance of this class is to call 6 connect(). 8 Establish a connection to the MySQL database. Accepts several 9 arguments: 11 :param host: Host where the database server is located 12 :param user: Username to log in as 13 :param password: Password to use. 14 :param database: Database to use, None to not use a particular one. 15 :param port: MySQL port to use, default is usually OK. (default: 3306) 16 :param bind_address: When the client has multiple network interfaces, specify 17 the interface from which to connect to the host. Argument can be 18 a hostname or an IP address. 19 :param unix_socket: Optionally, you can use a unix socket rather than TCP/IP. 20 :param read_timeout: The timeout for reading from the connection in seconds (default: None - no timeout) 21 :param write_timeout: The timeout for writing to the connection in seconds (default: None - no timeout) 22 :param charset: Charset you want to use. 23 :param sql_mode: Default SQL_MODE to use. 24 :param read_default_file: 25 Specifies my.cnf file to read these parameters from under the [client] section. 26 :param conv: 27 Conversion dictionary to use instead of the default one. 28 This is used to provide custom marshalling and unmarshaling of types. 29 See converters. 30 :param use_unicode: 31 Whether or not to default to unicode strings. 32 This option defaults to true for Py3k. 33 :param client_flag: Custom flags to send to MySQL. Find potential values in constants.CLIENT. 34 :param cursorclass: Custom cursor class to use. 35 :param init_command: Initial SQL statement to run when connection is established. 36 :param connect_timeout: Timeout before throwing an exception when connecting. 37 (default: 10, min: 1, max: 31536000) 38 :param ssl: 39 A dict of arguments similar to mysql_ssl_set()'s parameters. 40 For now the capath and cipher arguments are not supported. 41 :param read_default_group: Group to read from in the configuration file. 42 :param compress: Not supported 43 :param named_pipe: Not supported 44 :param autocommit: Autocommit mode. None means use server default. (default: False) 45 :param local_infile: Boolean to enable the use of LOAD DATA LOCAL command. (default: False) 46 :param max_allowed_packet: Max size of packet sent to server in bytes. (default: 16MB) 47 Only used to limit size of "LOAD LOCAL INFILE" data packet smaller than default (16KB). 48 :param defer_connect: Don't explicitly connect on contruction - wait for connect call. 49 (default: False) 50 :param auth_plugin_map: A dict of plugin names to a class that processes that plugin. 51 The class will take the Connection object as the argument to the constructor. 52 The class needs an authenticate method taking an authentication packet as 53 an argument. For the dialog plugin, a prompt(echo, prompt) method can be used 54 (if no authenticate method) for returning a string from the user. (experimental) 55 :param server_public_key: SHA256 authenticaiton plugin public key value. (default: None) 56 :param db: Alias for database. (for compatibility to MySQLdb) 57 :param passwd: Alias for password. (for compatibility to MySQLdb) 58 :param binary_prefix: Add _binary prefix on bytes and bytearray. (default: False) 60 See `Connection <https://www.python.org/dev/peps/pep-0249/#connection-objects>`_ in the 61 specification. 62 """ 64 _sock = None 65 _auth_plugin_name = '' 66 _closed = False 67 _secure = False 69 def __init__ (self, host=None, user=None, password= "" , 70 database=None, port=0, unix_socket= None, 71 charset= '' , sql_mode= None, 72 read_default_file=None, conv=None, use_unicode= None, 73 client_flag=0, cursorclass=Cursor, init_command= None, 74 connect_timeout=10, ssl=None, read_default_group= None, 75 compress=None, named_pipe= None, 76 autocommit=False, db=None, passwd=None, local_infile= False, 77 max_allowed_packet=16*1024*1024, defer_connect= False, 78 auth_plugin_map=None, read_timeout=None, write_timeout= None, 79 bind_address=None, binary_prefix=False, program_name= None, 80 server_public_key= None): 81 if use_unicode is None and sys.version_info[0] > 2 : 82 use_unicode = True 84 if db is not None and database is None: 85 database = db 86 if passwd is not None and not password: 87 password = passwd 89 if compress or named_pipe: 90 raise NotImplementedError( " compress and named_pipe arguments are not supported " ) 92 self._local_infile = bool(local_infile) 93 if self._local_infile: 94 client_flag |= CLIENT.LOCAL_FILES 96 if read_default_group and not read_default_file: 97 if sys.platform.startswith( " win " ): 98 read_default_file = " c:\\my.ini " 99 else : 100 read_default_file = " /etc/my.cnf " 102 if read_default_file: 103 if not read_default_group: 104 read_default_group = " client " 106 cfg = Parser() 107 cfg.read(os.path.expanduser(read_default_file)) 109 def _config(key, arg): 110 if arg: 111 return arg 112 try : 113 return cfg.get(read_default_group, key) 114 except Exception: 115 return arg 117 user = _config( " user " , user) 118 password = _config( " password " , password) 119 host = _config( " host " , host) 120 database = _config( " database " , database) 121 unix_socket = _config( " socket " , unix_socket) 122 port = int(_config( " port " , port)) 123 bind_address = _config( " bind-address " , bind_address) 124 charset = _config( " default-character-set " , charset) 125 if not ssl: 126 ssl = {} 127 if isinstance(ssl, dict): 128 for key in [ " ca " , " capath " , " cert " , " key " , " cipher " ]: 129 value = _config( " ssl- " + key, ssl.get(key)) 130 if value: 131 ssl[key] = value 133 self.ssl = False 134 if ssl: 135 if not SSL_ENABLED: 136 raise NotImplementedError( " ssl module not found " ) 137 self.ssl = True 138 client_flag |= CLIENT.SSL 139 self.ctx = self._create_ssl_ctx(ssl) 141 self.host = host or " localhost " 142 self.port = port or 3306 143 self.user = user or DEFAULT_USER 144 self.password = password or b "" 145 if isinstance(self.password, text_type): 146 self.password = self.password.encode( ' latin1 ' ) 147 self.db = database 148 self.unix_socket = unix_socket 149 self.bind_address = bind_address 150 if not (0 < connect_timeout <= 31536000 ): 151 raise ValueError( " connect_timeout should be >0 and <=31536000 " ) 152 self.connect_timeout = connect_timeout or None 153 if read_timeout is not None and read_timeout <= 0: 154 raise ValueError( " read_timeout should be >= 0 " ) 155 self._read_timeout = read_timeout 156 if write_timeout is not None and write_timeout <= 0: 157 raise ValueError( " write_timeout should be >= 0 " ) 158 self._write_timeout = write_timeout 159 if charset: 160 self.charset = charset 161 self.use_unicode = True 162 else : 163 self.charset = DEFAULT_CHARSET 164 self.use_unicode = False 166 if use_unicode is not None: 167 self.use_unicode = use_unicode 169 self.encoding = charset_by_name(self.charset).encoding 171 client_flag |= CLIENT.CAPABILITIES 172 if self.db: 173 client_flag |= CLIENT.CONNECT_WITH_DB 175 self.client_flag = client_flag 177 self.cursorclass = cursorclass 179 self._result = None 180 self._affected_rows = 0 181 self.host_info = " Not connected " 183 # : specified autocommit mode. None means use server default. 184 self.autocommit_mode = autocommit 186 if conv is None: 187 conv = converters.conversions 189 # Need for MySQLdb compatibility. 190 self.encoders = dict([(k, v) for (k, v) in conv.items() if type(k) is not int]) 191 self.decoders = dict([(k, v) for (k, v) in conv.items() if type(k) is int]) 192 self.sql_mode = sql_mode 193 self.init_command = init_command 194 self.max_allowed_packet = max_allowed_packet 195 self._auth_plugin_map = auth_plugin_map or {} 196 self._binary_prefix = binary_prefix 197 self.server_public_key = server_public_key 199 self._connect_attrs = { 200 ' _client_name ' : ' pymysql ' , 201 ' _pid ' : str(os.getpid()), 202 ' _client_version ' : VERSION_STRING, 203 } 204 if program_name: 205 self._connect_attrs[ " program_name " ] = program_name 206 elif sys.argv: 207 self._connect_attrs[ " program_name " ] = sys.argv[0] 209 if defer_connect: 210 self._sock = None 211 else : 212 self.connect() 214 def _create_ssl_ctx(self, sslp): 215 if isinstance(sslp, ssl.SSLContext): 216 return sslp 217 ca = sslp.get( ' ca ' ) 218 capath = sslp.get( ' capath ' ) 219 hasnoca = ca is None and capath is None 220 ctx = ssl.create_default_context(cafile=ca, capath= capath) 221 ctx.check_hostname = not hasnoca and sslp.get( ' check_hostname ' , True) 222 ctx.verify_mode = ssl.CERT_NONE if hasnoca else ssl.CERT_REQUIRED 223 if ' cert ' in sslp: 224 ctx.load_cert_chain(sslp[ ' cert ' ], keyfile=sslp.get( ' key ' )) 225 if ' cipher ' in sslp: 226 ctx.set_ciphers(sslp[ ' cipher ' ]) 227 ctx.options |= ssl.OP_NO_SSLv2 228 ctx.options |= ssl.OP_NO_SSLv3 229 return ctx 231 def close(self): 232 """ 233 Send the quit message and close the socket. 235 See `Connection.close() <https://www.python.org/dev/peps/pep-0249/#Connection.close>`_ 236 in the specification. 238 :raise Error: If the connection is already closed. 239 """ 240 if self._closed: 241 raise err.Error( " Already closed " ) 242 self._closed = True 243 if self._sock is None: 244 return 245 send_data = struct.pack( ' <iB ' , 1 , COMMAND.COM_QUIT) 246 try : 247 self._write_bytes(send_data) 248 except Exception: 249 pass 250 finally : 251 self._force_close() 253 @property 254 def open(self): 255 """ Return True if the connection is open """ 256 return self._sock is not None 258 def _force_close(self): 259 """ Close connection without QUIT message """ 260 if self._sock: 261 try : 262 self._sock.close() 263 except : # noqa 264 pass 265 self._sock = None 266 self._rfile = None 268 __del__ = _force_close 270 def autocommit(self, value): 271 self.autocommit_mode = bool(value) 272 current = self.get_autocommit() 273 if value != current: 274 self._send_autocommit_mode() 276 def get_autocommit(self): 277 return bool(self.server_status & 278 SERVER_STATUS.SERVER_STATUS_AUTOCOMMIT) 280 def _read_ok_packet(self): 281 pkt = self._read_packet() 282 if not pkt.is_ok_packet(): 283 raise err.OperationalError(2014, " Command Out of Sync " ) 284 ok = OKPacketWrapper(pkt) 285 self.server_status = ok.server_status 286 return ok 288 def _send_autocommit_mode(self): 289 """ Set whether or not to commit after every execute() """ 290 self._execute_command(COMMAND.COM_QUERY, " SET AUTOCOMMIT = %s " % 291 self.escape(self.autocommit_mode)) 292 self._read_ok_packet() 294 def begin(self): 295 """ Begin transaction. """ 296 self._execute_command(COMMAND.COM_QUERY, " BEGIN " ) 297 self._read_ok_packet() 299 def commit(self): 300 """ 301 Commit changes to stable storage. 303 See `Connection.commit() <https://www.python.org/dev/peps/pep-0249/#commit>`_ 304 in the specification. 305 """ 306 self._execute_command(COMMAND.COM_QUERY, " COMMIT " ) 307 self._read_ok_packet() 309 def rollback(self): 310 """ 311 Roll back the current transaction. 313 See `Connection.rollback() <https://www.python.org/dev/peps/pep-0249/#rollback>`_ 314 in the specification. 315 """ 316 self._execute_command(COMMAND.COM_QUERY, " ROLLBACK " ) 317 self._read_ok_packet() 319 def show_warnings(self): 320 """ Send the "SHOW WARNINGS" SQL command. """ 321 self._execute_command(COMMAND.COM_QUERY, " SHOW WARNINGS " ) 322 result = MySQLResult(self) 323 result.read() 324 return result.rows 326 def select_db(self, db): 327 """ 328 Set current db. 330 :param db: The name of the db. 331 """ 332 self._execute_command(COMMAND.COM_INIT_DB, db) 333 self._read_ok_packet() 335 def escape(self, obj, mapping= None): 336 """ Escape whatever value you pass to it. 338 Non-standard, for internal use; do not use this in your applications. 339 """ 340 if isinstance(obj, str_type): 341 return " ' " + self.escape_string(obj) + " ' " 342 if isinstance(obj, (bytes, bytearray)): 343 ret = self._quote_bytes(obj) 344 if self._binary_prefix: 345 ret = " _binary " + ret 346 return ret 347 return converters.escape_item(obj, self.charset, mapping= mapping) 349 def literal(self, obj): 350 """ Alias for escape() 352 Non-standard, for internal use; do not use this in your applications. 353 """ 354 return self.escape(obj, self.encoders) 356 def escape_string(self, s): 357 if (self.server_status & 358 SERVER_STATUS.SERVER_STATUS_NO_BACKSLASH_ESCAPES): 359 return s.replace( " ' " , " '' " ) 360 return converters.escape_string(s) 362 def _quote_bytes(self, s): 363 if (self.server_status & 364 SERVER_STATUS.SERVER_STATUS_NO_BACKSLASH_ESCAPES): 365 return " '%s' " % (_fast_surrogateescape(s.replace(b " ' " , b " '' " )),) 366 return converters.escape_bytes(s) 368 def cursor(self, cursor= None): 369 """ 370 Create a new cursor to execute queries with. 372 :param cursor: The type of cursor to create; one of :py:class:`Cursor`, 373 :py:class:`SSCursor`, :py:class:`DictCursor`, or :py:class:`SSDictCursor`. 374 None means use Cursor. 375 """ 376 if cursor: 377 return cursor(self) 378 return self.cursorclass(self) 380 def __enter__ (self): 381 """ Context manager that returns a Cursor """ 382 return self.cursor() 384 def __exit__ (self, exc, value, traceback): 385 """ On successful exit, commit. On exception, rollback """ 386 if exc: 387 self.rollback() 388 else : 389 self.commit() 391 # The following methods are INTERNAL USE ONLY (called from Cursor) 392 def query(self, sql, unbuffered= False): 393 # if DEBUG: 394 # print("DEBUG: sending query:", sql) 395 if isinstance(sql, text_type) and not (JYTHON or IRONPYTHON): 396 if PY2: 397 sql = sql.encode(self.encoding) 398 else : 399 sql = sql.encode(self.encoding, ' surrogateescape ' ) 400 self._execute_command(COMMAND.COM_QUERY, sql) 401 self._affected_rows = self._read_query_result(unbuffered= unbuffered) 402 return self._affected_rows 404 def next_result(self, unbuffered= False): 405 self._affected_rows = self._read_query_result(unbuffered= unbuffered) 406 return self._affected_rows 408 def affected_rows(self): 409 return self._affected_rows 411 def kill(self, thread_id): 412 arg = struct.pack( ' <I ' , thread_id) 413 self._execute_command(COMMAND.COM_PROCESS_KILL, arg) 414 return self._read_ok_packet() 416 def ping(self, reconnect= True): 417 """ 418 Check if the server is alive. 420 :param reconnect: If the connection is closed, reconnect. 421 :raise Error: If the connection is closed and reconnect=False. 422 """ 423 if self._sock is None: 424 if reconnect: 425 self.connect() 426 reconnect = False 427 else : 428 raise err.Error( " Already closed " ) 429 try : 430 self._execute_command(COMMAND.COM_PING, "" ) 431 self._read_ok_packet() 432 except Exception: 433 if reconnect: 434 self.connect() 435 self.ping(False) 436 else : 437 raise 439 def set_charset(self, charset): 440 # Make sure charset is supported. 441 encoding = charset_by_name(charset).encoding 443 self._execute_command(COMMAND.COM_QUERY, " SET NAMES %s " % self.escape(charset)) 444 self._read_packet() 445 self.charset = charset 446 self.encoding = encoding 448 def connect(self, sock= None): 449 self._closed = False 450 try : 451 if sock is None: 452 if self.unix_socket: 453 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 454 sock.settimeout(self.connect_timeout) 455 sock.connect(self.unix_socket) 456 self.host_info = " Localhost via UNIX socket " 457 self._secure = True 458 if DEBUG: print ( ' connected using unix_socket ' ) 459 else : 460 kwargs = {} 461 if self.bind_address is not None: 462 kwargs[ ' source_address ' ] = (self.bind_address, 0) 463 while True: 464 try : 465 sock = socket.create_connection( 466 (self.host, self.port), self.connect_timeout, 467 ** kwargs) 468 break 469 except (OSError, IOError) as e: 470 if e.errno == errno.EINTR: 471 continue 472 raise 473 self.host_info = " socket %s:%d " % (self.host, self.port) 474 if DEBUG: print ( ' connected using socket ' ) 475 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1 ) 476 sock.settimeout(None) 477 sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1 ) 478 self._sock = sock 479 self._rfile = _makefile(sock, ' rb ' ) 480 self._next_seq_id = 0 482 self._get_server_information() 483 self._request_authentication() 485 if self.sql_mode is not None: 486 c = self.cursor() 487 c.execute( " SET sql_mode=%s " , (self.sql_mode,)) 489 if self.init_command is not None: 490 c = self.cursor() 491 c.execute(self.init_command) 492 c.close() 493 self.commit() 495 if self.autocommit_mode is not None: 496 self.autocommit(self.autocommit_mode) 497 except BaseException as e: 498 self._rfile = None 499 if sock is not None: 500 try : 501 sock.close() 502 except : # noqa 503 pass 505 if isinstance(e, (OSError, IOError, socket.error)): 506 exc = err.OperationalError( 507 2003 , 508 " Can't connect to MySQL server on %r (%s) " % ( 509 self.host, e)) 510 # Keep original exception and traceback to investigate error. 511 exc.original_exception = e 512 exc.traceback = traceback.format_exc() 513 if DEBUG: print (exc.traceback) 514 raise exc 516 # If e is neither DatabaseError or IOError, It's a bug. 517 # But raising AssertionError hides original error. 518 # So just reraise it. 519 raise 521 def write_packet(self, payload): 522 """ Writes an entire "mysql packet" in its entirety to the network 523 addings its length and sequence number. 524 """ 525 # Internal note: when you build packet manualy and calls _write_bytes() 526 # directly, you should set self._next_seq_id properly. 527 data = pack_int24(len(payload)) + int2byte(self._next_seq_id) + payload 528 if DEBUG: dump_packet(data) 529 self._write_bytes(data) 530 self._next_seq_id = (self._next_seq_id + 1) % 256 532 def _read_packet(self, packet_type= MysqlPacket): 533 """ Read an entire "mysql packet" in its entirety from the network 534 and return a MysqlPacket type that represents the results. 536 :raise OperationalError: If the connection to the MySQL server is lost. 537 :raise InternalError: If the packet sequence number is wrong. 538 """ 539 buff = b '' 540 while True: 541 packet_header = self._read_bytes(4 ) 542 # if DEBUG: dump_packet(packet_header) 544 btrl, btrh, packet_number = struct.unpack( ' <HBB ' , packet_header) 545 bytes_to_read = btrl + (btrh << 16 ) 546 if packet_number != self._next_seq_id: 547 self._force_close() 548 if packet_number == 0: 549 # MariaDB sends error packet with seqno==0 when shutdown 550 raise err.OperationalError( 551 CR.CR_SERVER_LOST, 552 " Lost connection to MySQL server during query " ) 553 raise err.InternalError( 554 " Packet sequence number wrong - got %d expected %d " 555 % (packet_number, self._next_seq_id)) 556 self._next_seq_id = (self._next_seq_id + 1) % 256 558 recv_data = self._read_bytes(bytes_to_read) 559 if DEBUG: dump_packet(recv_data) 560 buff += recv_data 561 # https://dev.mysql.com/doc/internals/en/sending-more-than-16mbyte.html 562 if bytes_to_read == 0xffffff : 563 continue 564 if bytes_to_read < MAX_PACKET_LEN: 565 break 567 packet = packet_type(buff, self.encoding) 568 packet.check_error() 569 return packet 571 def _read_bytes(self, num_bytes): 572 self._sock.settimeout(self._read_timeout) 573 while True: 574 try : 575 data = self._rfile.read(num_bytes) 576 break 577 except (IOError, OSError) as e: 578 if e.errno == errno.EINTR: 579 continue 580 self._force_close() 581 raise err.OperationalError( 582 CR.CR_SERVER_LOST, 583 " Lost connection to MySQL server during query (%s) " % (e,)) 584 if len(data) < num_bytes: 585 self._force_close() 586 raise err.OperationalError( 587 CR.CR_SERVER_LOST, " Lost connection to MySQL server during query " ) 588 return data 590 def _write_bytes(self, data): 591 self._sock.settimeout(self._write_timeout) 592 try : 593 self._sock.sendall(data) 594 except IOError as e: 595 self._force_close() 596 raise err.OperationalError( 597 CR.CR_SERVER_GONE_ERROR, 598 " MySQL server has gone away (%r) " % (e,)) 600 def _read_query_result(self, unbuffered= False): 601 self._result = None 602 if unbuffered: 603 try : 604 result = MySQLResult(self) 605 result.init_unbuffered_query() 606 except : 607 result.unbuffered_active = False 608 result.connection = None 609 raise 610 else : 611 result = MySQLResult(self) 612 result.read() 613 self._result = result 614 if result.server_status is not None: 615 self.server_status = result.server_status 616 return result.affected_rows 618 def insert_id(self): 619 if self._result: 620 return self._result.insert_id 621 else : 622 return 0 624 def _execute_command(self, command, sql): 625 """ 626 :raise InterfaceError: If the connection is closed. 627 :raise ValueError: If no username was specified. 628 """ 629 if not self._sock: 630 raise err.InterfaceError( " (0, '') " ) 632 # If the last query was unbuffered, make sure it finishes before 633 # sending new commands 634 if self._result is not None: 635 if self._result.unbuffered_active: 636 warnings.warn( " Previous unbuffered result was left incomplete " ) 637 self._result._finish_unbuffered_query() 638 while self._result.has_next: 639 self.next_result() 640 self._result = None 642 if isinstance(sql, text_type): 643 sql = sql.encode(self.encoding) 645 packet_size = min(MAX_PACKET_LEN, len(sql) + 1) # +1 is for command 647 # tiny optimization: build first packet manually instead of 648 # calling self..write_packet() 649 prelude = struct.pack( ' <iB ' , packet_size, command) 650 packet = prelude + sql[:packet_size-1 ] 651 self._write_bytes(packet) 652 if DEBUG: dump_packet(packet) 653 self._next_seq_id = 1 655 if packet_size < MAX_PACKET_LEN: 656 return 658 sql = sql[packet_size-1 :] 659 while True: 660 packet_size = min(MAX_PACKET_LEN, len(sql)) 661 self.write_packet(sql[:packet_size]) 662 sql = sql[packet_size:] 663 if not sql and packet_size < MAX_PACKET_LEN: 664 break 666 def _request_authentication(self): 667 # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse 668 if int(self.server_version.split( ' . ' , 1)[0]) >= 5 : 669 self.client_flag |= CLIENT.MULTI_RESULTS 671 if self.user is None: 672 raise ValueError( " Did not specify a username " ) 674 charset_id = charset_by_name(self.charset).id 675 if isinstance(self.user, text_type): 676 self.user = self.user.encode(self.encoding) 678 data_init = struct.pack( ' <iIB23s ' , self.client_flag, MAX_PACKET_LEN, charset_id, b '' ) 680 if self.ssl and self.server_capabilities & CLIENT.SSL: 681 self.write_packet(data_init) 683 self._sock = self.ctx.wrap_socket(self._sock, server_hostname= self.host) 684 self._rfile = _makefile(self._sock, ' rb ' ) 685 self._secure = True 687 data = data_init + self.user + b ' \0 ' 689 authresp = b '' 690 plugin_name = None 692 if self._auth_plugin_name in ( '' , ' mysql_native_password ' ): 693 authresp = _auth.scramble_native_password(self.password, self.salt) 694 elif self._auth_plugin_name == ' caching_sha2_password ' : 695 plugin_name = b ' caching_sha2_password ' 696 if self.password: 697 if DEBUG: 698 print ( " caching_sha2: trying fast path " ) 699 authresp = _auth.scramble_caching_sha2(self.password, self.salt) 700 else : 701 if DEBUG: 702 print ( " caching_sha2: empty password " ) 703 elif self._auth_plugin_name == ' sha256_password ' : 704 plugin_name = b ' sha256_password ' 705 if self.ssl and self.server_capabilities & CLIENT.SSL: 706 authresp = self.password + b ' \0 ' 707 elif self.password: 708 authresp = b ' \1 ' # request public key 709 else : 710 authresp = b ' \0 ' # empty password 712 if self.server_capabilities & CLIENT.PLUGIN_AUTH_LENENC_CLIENT_DATA: 713 data += lenenc_int(len(authresp)) + authresp 714 elif self.server_capabilities & CLIENT.SECURE_CONNECTION: 715 data += struct.pack( ' B ' , len(authresp)) + authresp 716 else : # pragma: no cover - not testing against servers without secure auth (>=5.0) 717 data += authresp + b ' \0 ' 719 if self.db and self.server_capabilities & CLIENT.CONNECT_WITH_DB: 720 if isinstance(self.db, text_type): 721 self.db = self.db.encode(self.encoding) 722 data += self.db + b ' \0 ' 724 if self.server_capabilities & CLIENT.PLUGIN_AUTH: 725 data += (plugin_name or b '' ) + b ' \0 ' 727 if self.server_capabilities & CLIENT.CONNECT_ATTRS: 728 connect_attrs = b '' 729 for k, v in self._connect_attrs.items(): 730 k = k.encode( ' utf8 ' ) 731 connect_attrs += struct.pack( ' B ' , len(k)) + k 732 v = v.encode( ' utf8 ' ) 733 connect_attrs += struct.pack( ' B ' , len(v)) + v 734 data += struct.pack( ' B ' , len(connect_attrs)) + connect_attrs 736 self.write_packet(data) 737 auth_packet = self._read_packet() 739 # if authentication method isn't accepted the first byte 740 # will have the octet 254 741 if auth_packet.is_auth_switch_request(): 742 if DEBUG: print ( " received auth switch " ) 743 # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest 744 auth_packet.read_uint8() # 0xfe packet identifier 745 plugin_name = auth_packet.read_string() 746 if self.server_capabilities & CLIENT.PLUGIN_AUTH and plugin_name is not None: 747 auth_packet = self._process_auth(plugin_name, auth_packet) 748 else : 749 # send legacy handshake 750 data = _auth.scramble_old_password(self.password, self.salt) + b ' \0 ' 751 self.write_packet(data) 752 auth_packet = self._read_packet() 753 elif auth_packet.is_extra_auth_data(): 754 if DEBUG: 755 print ( " received extra data " ) 756 # https://dev.mysql.com/doc/internals/en/successful-authentication.html 757 if self._auth_plugin_name == " caching_sha2_password " : 758 auth_packet = _auth.caching_sha2_password_auth(self, auth_packet) 759 elif self._auth_plugin_name == " sha256_password " : 760 auth_packet = _auth.sha256_password_auth(self, auth_packet) 761 else : 762 raise err.OperationalError( " Received extra packet for auth method %r " , self._auth_plugin_name) 764 if DEBUG: print ( " Succeed to auth " ) 766 def _process_auth(self, plugin_name, auth_packet): 767 handler = self._get_auth_plugin_handler(plugin_name) 768 if handler: 769 try : 770 return handler.authenticate(auth_packet) 771 except AttributeError: 772 if plugin_name != b ' dialog ' : 773 raise err.OperationalError(2059, " Authentication plugin '%s' " 774 " not loaded: - %r missing authenticate method " % (plugin_name, type(handler))) 775 if plugin_name == b " caching_sha2_password " : 776 return _auth.caching_sha2_password_auth(self, auth_packet) 777 elif plugin_name == b " sha256_password " : 778 return _auth.sha256_password_auth(self, auth_packet) 779 elif plugin_name == b " mysql_native_password " : 780 data = _auth.scramble_native_password(self.password, auth_packet.read_all()) 781 elif plugin_name == b " mysql_old_password " : 782 data = _auth.scramble_old_password(self.password, auth_packet.read_all()) + b ' \0 ' 783 elif plugin_name == b " mysql_clear_password " : 784 # https://dev.mysql.com/doc/internals/en/clear-text-authentication.html 785 data = self.password + b ' \0 ' 786 elif plugin_name == b " dialog " : 787 pkt = auth_packet 788 while True: 789 flag = pkt.read_uint8() 790 echo = (flag & 0x06) == 0x02 791 last = (flag & 0x01) == 0x01 792 prompt = pkt.read_all() 794 if prompt == b " Password: " : 795 self.write_packet(self.password + b ' \0 ' ) 796 elif handler: 797 resp = ' no response - TypeError within plugin.prompt method ' 798 try : 799 resp = handler.prompt(echo, prompt) 800 self.write_packet(resp + b ' \0 ' ) 801 except AttributeError: 802 raise err.OperationalError(2059, " Authentication plugin '%s' " \ 803 " not loaded: - %r missing prompt method " % (plugin_name, handler)) 804 except TypeError: 805 raise err.OperationalError(2061, " Authentication plugin '%s' " \ 806 " %r didn't respond with string. Returned '%r' to prompt %r " % (plugin_name, handler, resp, prompt)) 807 else : 808 raise err.OperationalError(2059, " Authentication plugin '%s' (%r) not configured " % (plugin_name, handler)) 809 pkt = self._read_packet() 810 pkt.check_error() 811 if pkt.is_ok_packet() or last: 812 break 813 return pkt 814 else : 815 raise err.OperationalError(2059, " Authentication plugin '%s' not configured " % plugin_name) 817 self.write_packet(data) 818 pkt = self._read_packet() 819 pkt.check_error() 820 return pkt 822 def _get_auth_plugin_handler(self, plugin_name): 823 plugin_class = self._auth_plugin_map.get(plugin_name) 824 if not plugin_class and isinstance(plugin_name, bytes): 825 plugin_class = self._auth_plugin_map.get(plugin_name.decode( ' ascii ' )) 826 if plugin_class: 827 try : 828 handler = plugin_class(self) 829 except TypeError: 830 raise err.OperationalError(2059, " Authentication plugin '%s' " 831 " not loaded: - %r cannot be constructed with connection object " % (plugin_name, plugin_class)) 832 else : 833 handler = None 834 return handler 836 # _mysql support 837 def thread_id(self): 838 return self.server_thread_id[0] 840 def character_set_name(self): 841 return self.charset 843 def get_host_info(self): 844 return self.host_info 846 def get_proto_info(self): 847 return self.protocol_version 849 def _get_server_information(self): 850 i = 0 851 packet = self._read_packet() 852 data = packet.get_all_data() 854 self.protocol_version = byte2int(data[i:i+1 ]) 855 i += 1 857 server_end = data.find(b ' \0 ' , i) 858 self.server_version = data[i:server_end].decode( ' latin1 ' ) 859 i = server_end + 1 861 self.server_thread_id = struct.unpack( ' <I ' , data[i:i+4 ]) 862 i += 4 864 self.salt = data[i:i+8 ] 865 i += 9 # 8 + 1(filler) 867 self.server_capabilities = struct.unpack( ' <H ' , data[i:i+2 ])[0] 868 i += 2 870 if len(data) >= i + 6 : 871 lang, stat, cap_h, salt_len = struct.unpack( ' <BHHB ' , data[i:i+6 ]) 872 i += 6 873 # TODO: deprecate server_language and server_charset. 874 # mysqlclient-python doesn't provide it. 875 self.server_language = lang 876 try : 877 self.server_charset = charset_by_id(lang).name 878 except KeyError: 879 # unknown collation 880 self.server_charset = None 882 self.server_status = stat 883 if DEBUG: print ( " server_status: %x " % stat) 885 self.server_capabilities |= cap_h << 16 886 if DEBUG: print ( " salt_len: " , salt_len) 887 salt_len = max(12, salt_len - 9 ) 889 # reserved 890 i += 10 892 if len(data) >= i + salt_len: 893 # salt_len includes auth_plugin_data_part_1 and filler 894 self.salt += data[i:i+ salt_len] 895 i += salt_len 897 i+=1 898 # AUTH PLUGIN NAME may appear here. 899 if self.server_capabilities & CLIENT.PLUGIN_AUTH and len(data) >= i: 900 # Due to Bug#59453 the auth-plugin-name is missing the terminating 901 # NUL-char in versions prior to 5.5.10 and 5.6.2. 902 # ref: https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake 903 # didn't use version checks as mariadb is corrected and reports 904 # earlier than those two. 905 server_end = data.find(b ' \0 ' , i) 906 if server_end < 0: # pragma: no cover - very specific upstream bug 907 # not found \0 and last field so take it all 908 self._auth_plugin_name = data[i:].decode( ' utf-8 ' ) 909 else : 910 self._auth_plugin_name = data[i:server_end].decode( ' utf-8 ' ) 912 def get_server_info(self): 913 return self.server_version 915 Warning = err.Warning 916 Error = err.Error 917 InterfaceError = err.InterfaceError 918 DatabaseError = err.DatabaseError 919 DataError = err.DataError 920 OperationalError = err.OperationalError 921 IntegrityError = err.IntegrityError 922 InternalError = err.InternalError 923 ProgrammingError = err.ProgrammingError 924 NotSupportedError = err.NotSupportedError Clnnection类操作数据库, 必须使用游标, 需要现获取 一个游标对象,
Connection.cursor(cursor=None) 方法返回一个新的游标。
连接没有关闭前,游标对象可以反复使用。
cursor 参数,可以指定一个Cursor 类,如果为None,则使用默认Cursor类
操作数据库
数据库操作需要使用Cursor类的实例,提供execute()方法,执行sql 语句,成功返回影响的行数。
默认是非自动提交的,需要手动提交,这也是业务上的默认需要。
新增记录
使用 insert into 语句插入数据。
1 import pymysql 3 conn = None 4 try: 5 conn = pymysql.connect('192.168.112.111', 'root', '123456', 'test') 6 # reconnect=True,会尝试重连一次,False 不会尝试重连 7 conn.ping(False) # 如果 活着,返回None 8 cursor = conn.cursor() 9 insert_sql = "INSERT INTO t1 (name,age) VALUES('tom',20)" 10 rows = cursor.execute(insert_sql) 11 conn.commit() # 原码中 没开启自动提交。 12 # :param autocommit: Autocommit mode. None means use server default. (default: False) 13 print(rows) # 返回影响的行数。此处只插入一行,所以影响的行数 为 1. 14 except Exception as e: 15 print(e) 16 finally: 17 if conn: 18 conn.close()
查询数据:(注意,要选择的字段以及行数,刚刚够用最佳,否则,影响服务器端,带宽,以及本地缓存空间)
1 import pymysql 3 conn = None 4 try: 5 # 实例化一个 cconnection类的实例 6 conn = pymysql.connect('192.168.112.111', 'root', '123456', 'test') 7 # Connection.cursor(cursor=None) 创建游标 8 cursor = conn.cursor() 10 insert_sql = "SELECT * FROM t1" 11 count = cursor.execute(insert_sql) 12 print(count) 14 rows = cursor.fetchone() 15 print(rows) 16 print(cursor.rowcount, cursor.rownumber) # 影响的行数,匹配到的第几行 18 rows = cursor.fetchone() 19 print(rows) 20 print(cursor.rowcount, cursor.rownumber) 22 rows = cursor.fetchmany(2) 23 print(rows) 24 print(cursor.rowcount, cursor.rownumber) 26 rows = cursor.fetchall() 27 print(rows) 28 print(cursor.rowcount, cursor.rownumber) 30 except Exception as e: 31 print(e) 32 finally: 33 if conn: 34 conn.close()7 ((4, ' jack ' , 30), (5, ' lilei ' , 30 )) 8 7 4 9 ((6, ' jerry ' , 20), (30, ' tom1 ' , 30), (31, ' rot ' , 30 )) 10 7 7 12 Process finished with exit code 0
将字段 也 返回
1 import pymysql 3 conn = None 4 curosr =None 6 try: 7 # 实例化一个 cconnection类的实例 8 conn = pymysql.connect('192.168.112.111', 'root', '123456', 'test') 9 print(conn) 10 # Connection.cursor(cursor=None) 创建游标 11 # 默认cursor=None 12 # 传入一个增强后的cursor类,创建游标(原码是一个Mixin类 13 cursor = conn.cursor(pymysql.cursors.DictCursor) 15 insert_sql = "SELECT * FROM t1" 16 count = cursor.execute(insert_sql) 17 print(count) 19 print(cursor.fetchall()) 21 conn.commit() 24 except Exception as e: 25 print(e) 26 finally: 27 if conn: 28 conn.close()
1 <pymysql.connections.Connection object at 0x000000000297CB70> 3 [{'id': 1, 'name': 'e', 'age': None}, {'id': 3, 'name': 'tom', 'age': 20}, {'id': 4, 'name': 'jack', 'age': 30}, {'id': 5, 'name': 'lilei', 'age': 30}, {'id': 6, 'name': 'jerry', 'age': 20}, {'id': 30, 'name': 'tom1', 'age': 30}, {'id': 31, 'name': 'rot', 'age': 30}]6 try : 7 # 实例化一个 cconnection类的实例 8 conn = pymysql.connect( ' 192.168.112.111 ' , ' root ' , ' 123456 ' , ' test ' ) 9 curosr = conn.cursor() 11 # 批量插入 方式 1: 12 for i in range(10 ): 13 sql = " INSERT INTO t1 (name, age) values('to',12) " 14 rows = curosr.execute(sql) 16 # 批量插入 方式 2: 17 sql = " INSERT INTO t1 (name, age) values(%s,%s) " 18 rows = curosr.executemany(sql, (( ' t{} ' .format(i), 30+i) for i in range(5 ))) 20 conn.commit() # 以后只要有 commit,就记得在出现异常出,增加回滚 22 except Exception as e: 23 print (e) 24 conn.rollback() 25 finally : 26 if conn: 27 conn.close() 28 if curosr: 29 curosr.close()
事实上,方式2 就是方式1:
self.rowcount = sum(self.execute(query, arg) for arg in args)
总结: 一般的执行流程:
SQL 注入攻击:
找出用户id 为 6 的用户信息的SQL 语句如下:
SELECT * FROM students WHERE id= 6
本以为如上的查询语句,但是实施上, SELECT * FROM `t1` WHERE age=30 or 1 ; 也就是通过字符拼接,还是可以获取所有的表中数据。
现在,要求可以找出某个id对应用户信息,代码如下:
1 userid = 5 2 sql = "SELECT * FROM stedents WHERE id={}".format(userid)
userid 可以变,例如从客户端 request请求 中获取,直接拼接到查询字符串中。
可是,如果userid = ‘5 or 1=1’ 呢?
运行的结果 竟然是返回了所有的数据。
(这就是利用 拼接 ,包括引号等 ,拼接出 类似 SELECT * FROM `t1` WHERE age=30 or 1)
SQL 注入攻击:
猜测 后台数据库的查询语句使用拼接字符串的方式,从而经过设计为服务端传参,令其拼接出特殊字符串的SQL 语句,返回攻击者想要的结果。
永远不要相信客户端传来的数据是规范的 ,安全的。!!!
如何解决:
1、参数化查询 ,可以有效防止注入攻击,并提高查询的效率。
2、同时不要报 详细的异常给客户端。
Cursor.execute(query, args= None):
args, 必须是元组,列表或字典, 如果查询字符串使用 %(name)s, 就必须使用字典。
1 import pymysql 2 from pymysql.cursors import DictCursor 4 conn = pymysql.connect('192.168.112.111', 'root','123456', 'test') 5 cursor = conn.cursor(DictCursor) 7 userid = '5 or 1=1' 8 sql = 'SELECT * FROM t1 WHERE id=%s' 9 cursor.execut(sql,(userid,)) # 参数化查询 10 print(cursor.fetchall()) 12 sql = 'SELECT * FROM t1 WHERE `name` like %(name)s and age > %(age)s' 13 cursor.execute(sql, {'name':'tom%', 'age':25}) # 参数化查询 15 if cursor: 16 cursor.close() 17 if conn: 18 conn.close()
结果 :没有吧所有的数据显示出来。只显示要查询的行
[ { 'age':20, 'id' : 5, 'name':'tom0'}]
参数化查询为什么会提高效率:
原因是 ---SQL 语句缓存,
数据库服务器一般会对SQL 语句编译和缓存,编译只对SQL 语句部分,所以参数中就算有SQL 指令也不会被执行。
编译过程,需要 词法分析,语义分析,生成AST(语法抽象树,倒转的),优化,生成执行计划等过程 ,比较耗费资源。
服务端 会先查找是否对同一条查询语句进行了缓存,如果缓存未失效,则不需要再次编译,从而降低了编译的成本,降低了内存消耗
可以认为SQL 语句字符串就是一个KEY, 如果使用拼接方案,每次发送过去的SQL 语句都不一样,都需要编译并缓存。
大量查询的时候,首选参数化查询。
开发时,应该使用参数化查询。
注意:这里的查询字符串的缓存,不是查询结果的缓存
上下文支持:
连接类源代码:
1 class Connection(object): # 返回一个conn 2 def __enter__(self): 3 """Context manager that returns a Cursor""" 4 return self.cursor() 6 def __exit__(self, exc, value, traceback): 7 """On successful exit, commit. On exception, rollback""" 8 if exc: 9 self.rollback() 10 else: 11 self.commit()
游标类源代码:
1 class Cursor(object): 2 def __enter__(self): 3 return self 5 def __exit__(self, *exc_info): 6 del exc_info 7 self.close()
可以看出,连接类 的上下文,进入之前,conn实例,调用cursor() 方法,创建游标,结束的时候,,如果异常,回滚,如果正常,则只是提交。并没有关闭连接
游标类,进入的时候,返回游标实例,退出的时候,关闭 了游标类。
举例 1:
1 import pymysql 2 from pymysql.cursors import DictCursor 4 conn = pymysql.connect('192.168.112.111', 'root','123456', 'test') 6 try: 7 with conn.cursor() as cursor: 8 sql = "select * from t1" 9 cursor.execute(sql) 10 conn.commit() 11 # 只需要提交事务,cursor 已经在退出with的时候,就关闭了 13 except Exception as e: 14 print(e) 15 conn.rollback() 16 finally: 17 conn.close() #
举例 2:
1 import pymysql 2 from pymysql.cursors import DictCursor 4 conn = pymysql.connect('192.168.112.111', 'root','123456', 'test') 7 with conn as cursor: 8 sql = "select * from t1" 9 cursor.execute(sql) 11 # 此外 在 __enter__ 里创建的curor 也没有关掉,所以可以继续 使用 12 sql = "select * from t2" 13 cursor.execute(sql) 15 # conn 的上下文 退出with 的时候,没有将conn 关掉 16 cursor.close() 17 conn.close()
举例 3:
1 import pymysql 2 from pymysql.cursors import DictCursor 4 conn = pymysql.connect('192.168.112.111', 'root','123456', 'test') 7 with conn as cursor: 8 with cursor: 9 sql = "select * from t1" 10 cursor.execute(sql) 13 # conn 的上下文 退出with 的时候,没有将conn 关掉,但是cursor 关了 14 conn.close()
总结 :连接不需要反反复复重建销毁,应该是多个cursor 共享一个conn
# Python implementation of the MySQL client-server protocol#http://dev.mysql.com/doc/internals/en/client-server-protocol.html#Error codes:#http://dev.mysql.com/doc/refman/5.5/en/error-messages-client.h... Python 标准数据接口为 Python DB-API Python DB-API为 开发 人员提供了 数据库 应用的编程接口 它定义了一系列必须的对象和 数据库 存取方式,以便为各种各样的底层 数据库 系统提供一致的访问接口 使用它连接各种 数据库 后,就可以用相同的方式操作各种 数据库 不同的 数据库 需要安装不同的DB-API模块,... 批量插入数据欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdow 本章主要实现 myuvc_vidioc_streamon()即启动传输 中的摄像头参数设置 向USB摄像头设置参数: 比如使用哪个format, 使用这个format下的哪个frame(分辨率),参考UVC驱动,实现向USB摄像头设置参数的功能,分为如下三部分: 步骤一:myuvc_try_streaming_params() ; 测试参数 说明:测试参数,代码中只是测试设置了某几个参数,并... 接下来这一段时间我们将要了解 数据库 的相关知识,顾名思义 " 数据库 " 就是用来保存数据的。像美团、淘宝、京东等头部企业每天都有大量的数据保存,如果做一个横向的对比,是程序重要还是数据重要呢?那肯定是数据最重要了。比如说淘宝系统, 开发 淘宝大概是用了 7000W(这个数字是道听途说来的,非官方证实),但是淘宝的 数据库 数据所附带产生远远超过 开发 的成本,由此可见数据的重要性。............ AttributeError: module 'pymysql._auth' has no attribute 'scramble_old_password'问题解决前言问题描述解决方法 遇到此问题,百度和谷歌皆无果 世界独此一家(百度仅有的两篇相关内容,都没有真正解决问题),最终在自己的尝试中解决。 此问题在win10系统下尚未遇到,在win7版本的电脑上出现。 环境说明:严肃的皮蛋 · sql like 多个值 - CSDN文库 3 周前 |
小胡子的日光灯 · 2021-11-23 工作记录--LayUI-laydate-显示小时分钟秒、显示年月日 + 只显示年、只显示月、只显示日 + 显示年-月_layui日期控件只显示年月_小呀小萝卜儿的博客-CSDN博客 1 年前 |
寂寞的茶叶 · mac端 electron 应用自动更新 - 简书 1 年前 |