mysql与python交互
MySQL 官方驱动模块 mysql connector 是mysql官方的驱动模块,兼容性特别好 下载地址:https://dev.mysql.com/downloads/connector/python/
直接查询数据库结果
mysql> show databases;
+
| Database |
+
| gpc |
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+
6 rows in set (0.00 sec)
mysql> use test;
Database changed
mysql> show tables;
+
| Tables_in_test |
+
| gongzi |
+
1 row in set (0.00 sec)
mysql> select * from gongzi;
+
| id | name | sex | tel | years | wages |
+
| 1 | zhangsan | man | 18398989898 | 1 | 1000 |
| 2 | lisi | man | 18398555555 | 2 | 3000 |
| 3 | wangwu | man | 18398454542 | 3 | 2000 |
| 4 | mazi | man | 18398989898 | 4 | 4000 |
| 5 | xiao_ming | man | 18398989898 | 5 | 5000 |
+
5 rows in set (0.00 sec)
mysql>
使用python进行交互
import mysql.connector
con =mysql.connector.connect(
host="localhost",port = "3306",
user = "root",password = "cheng.123456789",
database = "test"
)
cursor=con.cursor()
sql="select * from gongzi;"
cursor.execute(sql)
for one in cursor:
print(one)
con.close()
sql注入与防御
import mysql.connector
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.12345",
"database":"gpc"
}
con=mysql.connector.connect(**config)
username="1 OR 1=1"
password="1 OR 1=1"
sql="SELECT COUNT(*) FROM t_user WHERE username="+username+\
" AND AES_DECRYPT(UNHEX(password),'HelloWorld')="+password;
cursor=con.cursor()
cursor.execute(sql)
print(cursor.fetchone()[0])
con.close()
sql注入攻击的危害:
- 由于sql语句是解释型语言,所以在拼接sql语句的时候,容易被注入恶意的sql语句
- id = “1 or 1=1”
- sql = delete from t_news where id=1 or 1=1;
mysql> select * from t_student;
+
| no | name | sex | age | email |
+
| 1 | 2 | 2 | 2 | 2 |
+
1 row in set (0.00 sec)
mysql> select * from t_news;
+
| id | title | editor_id | type_id | content_id | is_top | create_time | update_time | state |
+
| 1 | xiaoming | 121 | 123 | 2112 | 123 | 2022-05-10 21:14:38 | 2022-05-18 21:14:42 | 鑽夌? |
+
1 row in set (0.00 sec)
mysql> delete from t_news where id=1 or 1=1;
Query OK, 1 row affected (0.06 sec)
mysql> delete from t_student where no=1 or 1=1;
Query OK, 1 row affected (0.04 sec)
mysql> select * from t_news;
Empty set (0.00 sec)
mysql> select * from t_student;
Empty set (0.00 sec)
mysql>
防御
- sql 预编译机制
- 预编译sql就是数据库提前把sql语句编译成二进制,这样反复执行同一条sql语句的效率就会提升
- 使用%s作为占位符代替具体的数据,传给数据库编译成二进制
- sql语句编译的过程中,关键字已经被解析过了,所以向编译后的sql语句传入参数,都被当作字符串处理,数据库不会解析其中注入的sql语句
import mysql.connector
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.12345",
"database":"gpc"
}
con=mysql.connector.connect(**config)
username="1 OR 1=1"
password="1 OR 1=1"
sql="SELECT COUNT(*) FROM t_user WHERE username=%s " \
"AND AES_DECRYPT(UNHEX(password),'HelloWorld')=%s";
cursor=con.cursor()
cursor.execute(sql,(username,password))
print(cursor.fetchone()[0])
con.close()
异常处理
con.start_transaction([事物隔离级别]) con.commit() 事物提交 con.rollback() 事物回滚 未写入数据前:
mysql> select * from t_emp;
+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1982-12-09 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1983-01-12 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+
14 rows in set (0.00 sec)
写入数据
import mysql.connector
try:
con=mysql.connector.connect(
host="localhost",
port=3306,
user="root",
password="cheng.12345",
database="gpc"
)
con.start_transaction()
cursor=con.cursor()
sql="INSERT INTO t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) " \
"VALUES(%s,%s,%s,%s,%s,%s,%s,%s)"
cursor.execute(sql,(9600,"赵娜","SALESMAN",None,"1985-12-1",2500,None,10))
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
finally:
if "con" in dir():
con.close()
mysql> select * from t_emp;
+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1982-12-09 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1983-01-12 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
| 9600 | 赵娜 | SALESMAN | NULL | 1985-12-01 | 2500.00 | NULL | 10 |
+
15 rows in set (0.00 sec)
数据库连接池
- 数据库连接是一种关键的,有限的,昂贵的资源,在并发执行的应用程序中体现得尤为突出
- tcp连接需要三次握手,四次挥手,然后数据库还要验证用户信息
- 数据库连接池,预先创建出一些数据库连接,然后缓存起来,避免了程序语言反复创建和销毁连接昂贵代价
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.123455",
"database":"gpc"
}
try:
pool=mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con=pool.get_connection()
con.start_transaction()
cursor=con.cursor()
sql="update t_emp set sal=sal+%s where deptno=%s"
cursor.execute(sql,(200000,20))
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
删除数据
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.1333",
"database":"gpc"
}
try:
pool=mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con=pool.get_connection()
con.start_transaction()
cursor=con.cursor()
sql="delete from t_emp where deptno = 20; "
cursor.execute(sql)
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
清空
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.12333",
"database":"gpc"
}
try:
pool=mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con=pool.get_connection()
con.start_transaction()
cursor=con.cursor()
sql="TRUNCATE TABLE t_emp;"
cursor.execute(sql)
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
循环执行sql语句
executemany()
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.1023",
"database":"gpc"
}
try:
pool=mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con=pool.get_connection()
con.start_transaction()
cursor=con.cursor()
sql="INSERT INTO t_dept(deptno,dname,loc) VALUES(%s,%s,%s)"
data=[
[100,"A部门","北京"],[110,"B部门","上海"]
]
cursor.executemany(sql,data)
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
案例
使用insert 语句,把部门平均底薪超过公司平均底薪的这样部门里的员工信息导入到t_emp_new表里面,并且让这些员工隶属于sales部门
一阶段
原:
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng",
"database":"gpc"
}
try:
pool = mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con = pool.get_connection()
con.start_transaction()
cursor = con.cursor()
sql = "CREATE TABLE t_emp_new AS (SELECT * FROM t_emp)"
cursor.execute(sql)
con.commit()
except Exception as e:
print(e)
现:
二阶段
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng",
"database":"gpc"
}
try:
pool = mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con = pool.get_connection()
con.start_transaction()
cursor = con.cursor()
sql = "DROP TABLE IF EXISTS t_emp_new"
cursor.execute(sql)
sql = "CREATE TABLE t_emp_new LIKE t_emp"
cursor.execute(sql)
sql="SELECT AVG(sal) AS avg FROM t_emp"
cursor.execute(sql)
temp = cursor.fetchone()
avg = temp[0]
print("公司平均底薪:",temp)
sql="SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=%s"
cursor.execute(sql,[avg])
for one in cursor:
print(one)
con.commit()
except Exception as e:
print(e)
插入
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng.1023",
"database":"gpc"
}
try:
pool = mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con = pool.get_connection()
con.start_transaction()
cursor = con.cursor()
sql = "DROP TABLE IF EXISTS t_emp_new"
cursor.execute(sql)
sql = "CREATE TABLE t_emp_new LIKE t_emp"
cursor.execute(sql)
sql="SELECT AVG(sal) AS avg FROM t_emp"
cursor.execute(sql)
temp = cursor.fetchone()
avg = temp[0]
print("公司平均底薪:",temp)
sql="SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=%s"
cursor.execute(sql,[avg])
temp = cursor.fetchall()
print(temp)
sql="INSERT INTO t_emp_new SELECT * FROM t_emp WHERE deptno IN ("
for index in range(len(temp)):
one = temp[index][0]
if index < len(temp)-1:
sql+=str(one)+","
else:
sql+=str(one)
sql+=")"
print(sql)
cursor.execute(sql)
con.commit()
except Exception as e:
print(e)
三阶段
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng",
"database":"gpc"
}
try:
pool = mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con = pool.get_connection()
con.start_transaction()
cursor = con.cursor()
sql = "DROP TABLE IF EXISTS t_emp_new"
cursor.execute(sql)
sql = "CREATE TABLE t_emp_new LIKE t_emp"
cursor.execute(sql)
sql="SELECT AVG(sal) AS avg FROM t_emp"
cursor.execute(sql)
temp = cursor.fetchone()
avg = temp[0]
print("公司平均底薪:",temp)
sql="SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=%s"
cursor.execute(sql,[avg])
temp = cursor.fetchall()
print(temp)
sql="INSERT INTO t_emp_new SELECT * FROM t_emp WHERE deptno IN ("
for index in range(len(temp)):
one = temp[index][0]
if index < len(temp)-1:
sql+=str(one)+","
else:
sql+=str(one)
sql+=")"
print(sql)
cursor.execute(sql)
sql="DELETE FROM t_emp WHERE deptno IN ("
for index in range(len(temp)):
one=temp[index][0]
if index < len(temp)-1:
sql+=str(one)+","
else:
sql+=str(one)
sql+=")"
print(sql)
cursor.execute(sql)
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
最终
import mysql.connector.pooling
config={
"host":"localhost",
"port":3306,
"user":"root",
"password":"cheng",
"database":"gpc"
}
try:
pool = mysql.connector.pooling.MySQLConnectionPool(
**config,
pool_size=10
)
con = pool.get_connection()
con.start_transaction()
cursor = con.cursor()
sql = "DROP TABLE IF EXISTS t_emp_new"
cursor.execute(sql)
sql = "CREATE TABLE t_emp_new LIKE t_emp"
cursor.execute(sql)
sql="SELECT AVG(sal) AS avg FROM t_emp"
cursor.execute(sql)
temp = cursor.fetchone()
avg = temp[0]
print("公司平均底薪:",temp)
sql="SELECT deptno FROM t_emp GROUP BY deptno HAVING AVG(sal)>=%s"
cursor.execute(sql,[avg])
temp = cursor.fetchall()
print(temp)
sql="INSERT INTO t_emp_new SELECT * FROM t_emp WHERE deptno IN ("
for index in range(len(temp)):
one = temp[index][0]
if index < len(temp)-1:
sql+=str(one)+","
else:
sql+=str(one)
sql+=")"
print(sql)
cursor.execute(sql)
sql="DELETE FROM t_emp WHERE deptno IN ("
for index in range(len(temp)):
one=temp[index][0]
if index < len(temp)-1:
sql+=str(one)+","
else:
sql+=str(one)
sql+=")"
print(sql)
cursor.execute(sql)
sql="SELECT deptno FROM t_dept WHERE dname=%s"
cursor.execute(sql,["SALES"])
deptno=cursor.fetchone()[0]
sql="UPDATE t_emp_new SET deptno=%s"
cursor.execute(sql,[deptno])
con.commit()
except Exception as e:
if "con" in dir():
con.rollback()
print(e)
|