本文已經遷移至:java
高可用mysql 的python代碼:mysql
https://launchpad.net/mysql-replicant-pythongit
Mysql 在python有不少鏈接庫。目前用戶最多的要數:https://pypi.python.org/pypi/MySQL-python。它還有一個精煉版本:https://github.com/farcepest/moist。可是近期更新比較慢,不支持python3。尤爲oracle的官方的mysql-connector-python鏈接器逐漸成熟以後,參見:http://dev.mysql.com/doc/connector-python/en/。github
初期mysql-connector-python處理中文等不夠完美,可是逐漸完善,並增長了c語言實現版本,性能大幅度提升。對python3支持也比較好。可是常常經過pip install的方式沒法安裝,此時就須要克隆https://github.com/mysql/mysql-connector-python.git,用python setup.py install的方式安裝。sql
import mysql.connector try: conn_params = { "database": "cookbook", "host": "localhost", "user": "cbuser", "password": "cbpass", "charset": "utf8", } conn = mysql.connector.connect(**conn_params) print("Connected") except: print("Cannot connect to server") else: conn.close() print("Disconnected")
常見選項:數據庫
conn_params = { "database": "cookbook", "host": "localhost", "port": 3307, "unix_socket": "/var/tmp/mysql.sock", "user": "cbuser", "password": "cbpass", }
基於jdbc,使用MySQL Connector/J。api
// Connect.java: connect to the MySQL server import java.sql.*; public class Connect { public static void main (String[] args) { Connection conn = null; String url = "jdbc:mysql://localhost/cookbook"; String userName = "cbuser"; String password = "cbpass"; try { Class.forName ("com.mysql.jdbc.Driver").newInstance (); conn = DriverManager.getConnection (url, userName, password); System.out.println ("Connected"); } catch (Exception e) { System.err.println ("Cannot connect to server"); System.exit (1); } if (conn != null) { try { conn.close (); System.out.println ("Disconnected"); } catch (Exception e) { /* ignore close errors */ } } } }
能夠省略主機,默認爲localhost,好比jdbc:mysql:///。
其餘方式:String url = "jdbc:mysql://localhost/cookbook?user=cbuser&password=cbpass";
Connector/J 不支持Unix domain socket,指定端口:String url = "jdbc:mysql://127.0.0.1:3307/cookbook";oracle
錯誤發生時,mysql提供:app
另外查詢和ERROR日誌也有輔助做用。
python
#!/usr/bin/python # error.py: demonstrate MySQL error handling import mysql.connector import sys #@ _FRAG_ conn_params = { "database": "cookbook", "host": "localhost", "user": "baduser", "password": "badpass" } try: conn = mysql.connector.connect(**conn_params) print("Connected") except mysql.connector.Error as e: print("Cannot connect to server") print("Error code: %s" % e.errno) print("Error message: %s" % e.msg) print("Error SQLSTATE: %s" % e.sqlstate) for item in sys.exc_info(): print item #@ _FRAG_ else: conn.close() print("Disconnected")
執行會發現e.errno、e.msg、e.sqlstate等比sys.exc_info()要更可讀,不過注意不是python的全部異常都有這些字段。
Java中簡單的異常處理以下
try { /* ... some database operation ... */ } catch (Exception e) { e.printStackTrace (); }
不過這樣可讀性不太好。
import java.sql.*; public class Error { public static void main (String[] args) { Connection conn = null; String url = "jdbc:mysql://localhost/cookbook"; String userName = "baduser"; String password = "badpass"; try { Class.forName ("com.mysql.jdbc.Driver").newInstance (); conn = DriverManager.getConnection (url, userName, password); System.out.println ("Connected"); tryQuery (conn); // issue a query } catch (Exception e) { System.err.println ("Cannot connect to server"); System.err.println (e); if (e instanceof SQLException) // JDBC-specific exception? { // e must be cast from Exception to SQLException to // access the SQLException-specific methods printException ((SQLException) e); } } finally { if (conn != null) { try { conn.close (); System.out.println ("Disconnected"); } catch (SQLException e) { printException (e); } } } } public static void tryQuery (Connection conn) { try { // issue a simple query Statement s = conn.createStatement (); s.execute ("USE cookbook"); s.close (); // print any accumulated warnings SQLWarning w = conn.getWarnings (); while (w != null) { System.err.println ("SQLWarning: " + w.getMessage ()); System.err.println ("SQLState: " + w.getSQLState ()); System.err.println ("Vendor code: " + w.getErrorCode ()); w = w.getNextWarning (); } } catch (SQLException e) { printException (e); } } public static void printException (SQLException e) { // print general message, plus any database-specific message System.err.println ("SQLException: " + e.getMessage ()); System.err.println ("SQLState: " + e.getSQLState ()); System.err.println ("Vendor code: " + e.getErrorCode ()); } }
爲了方便,咱們對數據庫鏈接進行了簡單的封裝:
cookbook.py
import mysql.connector conn_params = { "database": "cookbook", "host": "localhost", "user": "cbuser", "password": "cbpass", } # Establish a connection to the cookbook database, returning a connection # object. Raise an exception if the connection cannot be established. def connect(): return mysql.connector.connect(**conn_params)
使用:harness.py
import mysql.connector import cookbook try: conn = cookbook.connect() print("Connected") except mysql.connector.Error as e: print("Cannot connect to server") print("Error code: %s" % e.errno) print("Error message: %s" % e.msg) else: conn.close() print("Disconnected")
package com.kitebird.mcb; import java.sql.*; import java.util.*; public class Cookbook { public static Connection connect () throws Exception { String url = "jdbc:mysql://localhost/cookbook"; String user = "cbuser"; String password = "cbpass"; Class.forName ("com.mysql.jdbc.Driver").newInstance (); return (DriverManager.getConnection (url, user, password)); } public static Connection propsConnect () throws Exception { String propsFile = "Cookbook.properties"; Properties props = new Properties (); String host = ""; String database = ""; String user = ""; String password = ""; props.load (Cookbook.class.getResourceAsStream (propsFile)); host = props.getProperty ("host", "localhost"); database = props.getProperty ("database", "cookbook"); user = props.getProperty ("user", ""); password = props.getProperty ("password", ""); String url = "jdbc:mysql://" + host + "/" + database; Class.forName ("com.mysql.jdbc.Driver").newInstance (); return (DriverManager.getConnection (url, user, password)); } public static String getErrorMessage (Exception e) { StringBuffer s = new StringBuffer (); if (e instanceof SQLException) // JDBC-specific exception? { // print general message, plus any database-specific message s.append ("Error message: " + e.getMessage () + "\n"); s.append ("Error code: " + ((SQLException) e).getErrorCode () + "\n"); } else { s.append (e + "\n"); } return (s.toString ()); } public static void printErrorMessage (Exception e) { System.err.println (Cookbook.getErrorMessage (e)); } }
使用:
import java.sql.*; import com.kitebird.mcb.Cookbook; public class Harness { public static void main (String[] args) { Connection conn = null; try { conn = Cookbook.connect (); System.out.println ("Connected"); } catch (Exception e) { Cookbook.printErrorMessage (e); System.exit (1); } finally { if (conn != null) { try { conn.close (); System.out.println ("Disconnected"); } catch (Exception e) { String err = Cookbook.getErrorMessage (e); System.out.println (err); } } } } }
SQL語句有些是獲取信息,有些是改變信息。
1,改變信息,不返回信息:INSERT , DELETE , UPDATE等
2,不改變信息,不返回信息:好比USE
3,返回信息:SELECT , SHOW , EXPLAIN或DESCRIBE
python操做mysql的演示:stmt.py:
#!/usr/bin/python # stmt.py: demonstrate statement processing in Python # (without placeholders) import sys import mysql.connector import cookbook try: conn = cookbook.connect() except mysql.connector.Error as e: print("Cannot connect to server") print("Error code: %s" % e.errno) print("Error message: %s" % e.msg) sys.exit(1) print("Fetch rows with fetchone") try: #@ _FETCHONE_ cursor = conn.cursor() cursor.execute("SELECT id, name, cats FROM profile") while True: row = cursor.fetchone() if row is None: break print("id: %s, name: %s, cats: %s" % (row[0], row[1], row[2])) print("Number of rows returned: %d" % cursor.rowcount) cursor.close() #@ _FETCHONE_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: %s" % e) # Note: Following loop would be shorter if written like this: # for row in cursor: # But don't do that because surrounding text in book discusses how to # use rows as a direct-access array following the fetch operation. print("Fetch rows with fetchall") try: #@ _FETCHALL_ cursor = conn.cursor() cursor.execute("SELECT id, name, cats FROM profile") rows = cursor.fetchall() for row in rows: print("id: %s, name: %s, cats: %s" % (row[0], row[1], row[2])) print("Number of rows returned: %d" % cursor.rowcount) cursor.close() #@ _FETCHALL_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: %s" % e) print("Fetch rows using cursor as iterator") try: #@ _CURSOR_ITERATOR_ cursor = conn.cursor() cursor.execute("SELECT id, name, cats FROM profile") for (id, name, cats) in cursor: print("id: %s, name: %s, cats: %s" % (id, name, cats)) print("Number of rows returned: %d" % cursor.rowcount) cursor.close() #@ _CURSOR_ITERATOR_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: %s" % e) print("Execute UPDATE statement (no placeholders)") try: #@ _DO_1_ cursor = conn.cursor() cursor.execute("UPDATE profile SET cats = cats+1 WHERE name = 'Sybil'") print("Number of rows updated: %d" % cursor.rowcount) cursor.close() conn.commit() #@ _DO_1_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: %s" % e) conn.close()
執行結果:
$ python stmt.py Fetch rows with fetchone id: 1, name: Sybil, cats: 1 id: 2, name: Nancy, cats: 3 id: 3, name: Ralph, cats: 4 id: 4, name: Lothair, cats: 5 id: 5, name: Henry, cats: 1 id: 6, name: Aaron, cats: 1 id: 7, name: Joanna, cats: 0 id: 8, name: Stephen, cats: 0 Number of rows returned: 8 Fetch rows with fetchall id: 1, name: Sybil, cats: 1 id: 2, name: Nancy, cats: 3 id: 3, name: Ralph, cats: 4 id: 4, name: Lothair, cats: 5 id: 5, name: Henry, cats: 1 id: 6, name: Aaron, cats: 1 id: 7, name: Joanna, cats: 0 id: 8, name: Stephen, cats: 0 Number of rows returned: 8 Fetch rows using cursor as iterator id: 1, name: Sybil, cats: 1 id: 2, name: Nancy, cats: 3 id: 3, name: Ralph, cats: 4 id: 4, name: Lothair, cats: 5 id: 5, name: Henry, cats: 1 id: 6, name: Aaron, cats: 1 id: 7, name: Joanna, cats: 0 id: 8, name: Stephen, cats: 0 Number of rows returned: 8 Execute UPDATE statement (no placeholders) Number of rows updated: 1
注意:除了fetchall方法以後,其餘都只能往前,不能日後。不過使用fetchall注意不要把內存塞滿了。
引號、反斜槓及NULL,另外還有防止SQL注入攻擊。可使用佔位符或引用函數。好比:
INSERT INTO profile (name,birth,color,foods,cats) VALUES('De'Mont','1973-01-12','blue','eggroll',4); INSERT INTO profile (name,birth,color,foods,cats) VALUES('De''Mont','1973-01-12','blue','eggroll',4); INSERT INTO profile (name,birth,color,foods,cats) VALUES('De\'Mont','1973-01-12','blue','eggroll',4); 在沒有開啓ANSI_QUOTES SQL的狀況下: INSERT INTO profile (name,birth,color,foods,cats) VALUES("De'Mont",'1973-01-12','blue','eggroll',4); INSERT INTO profile (name,birth,color,foods,cats) VALUES('De''Mont','1973-01-12',NULL,'eggroll',4); INSERT INTO profile (name,birth,color,foods,cats) VALUES(?,?,?,?,?) INSERT INTO profile (name,birth,color,foods,cats) VALUES(%s,%s,%s,%s,%s)
Python種用%s表示佔位符,原始%用%%表示。
#!/usr/bin/python import mysql.connector import cookbook conn = cookbook.connect() try: #@ _FETCHLOOP_ cursor = conn.cursor() cursor.execute("SELECT name, birth, foods FROM profile") for row in cursor: row = list(row) # convert nonmutable tuple to mutable list for i, value in enumerate(row): if value is None: # is the column value NULL? row[i] = "NULL" print("name: %s, birth: %s, foods: %s" % (row[0], row[1], row[2])) cursor.close() #@ _FETCHLOOP_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: %s" % e) conn.close()
更加推薦的格式以下:
#!/usr/bin/python import mysql.connector import cookbook conn = cookbook.connect() try: #@ _FETCHLOOP_ cursor = conn.cursor() cursor.execute("SELECT name, birth, foods FROM profile") for row in cursor: row = list(row) # convert nonmutable tuple to mutable list for i, value in enumerate(row): if value is None: # is the column value NULL? row[i] = "NULL" print("name: {0}, birth: {1}, foods: {2}".format(row[0], row[1], row[2])) cursor.close() #@ _FETCHLOOP_ except mysql.connector.Error as e: print("Oops, the statement failed") print("Error: {0}".format(e)) conn.close()