这篇文章是准备hack in ztc关于mysql监控代码的先期工作。
zabbix监控的好处不用多数,ztc作为zabbix的扩展非常灵活强大,但包含的东西太多,mysql方面显得不是很专精,里面的指标获取都是通show global status like '%xxx'获取,有时候这回显得很乏力。
这时我需要hack in ztc mysql的部分,扩展它,但是mysqldb的模块我用的不是很熟悉。google了很多文章,发现一片很适合切入的教程文章。地址是:http://zetcode.com/db/mysqlpython/
博主很专业,有很多其他类似的教程,不一一枚举了。下面是正文的翻译,细节翻译得不好, 请见谅。
开始前,准备mysql的环境。
apt-get install mysql-server mysql-common mysql-client -y $ apt-cache search MySQLdb python-mysqldb - A Python interface to MySQL python-mysqldb-dbg - A Python interface to MySQL (debug extension) bibus - bibliographic database eikazo - graphical frontend for SANE designed for mass-scanning
我们不知道对应mysqldb 模块的包的名字,可以使用apt-cache解决
apt-get install python-mysqldb
现在我们已经安装了mysql的python接口。包含了_mysql 和MySQLdb的模块。
下面我们需要创建一个数据库和相对应的用户名
root@ubuntu:~# mysql -u root -p123456 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8004 Server version: 5.5.34-0ubuntu0.12.04.1 (Ubuntu) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database testdb; Query OK, 1 row affected (0.00 sec) mysql> create user 'testuser'@'localhost' identified by '123456'; Query OK, 0 rows affected (0.15 sec) mysql> use testdb; Database changed mysql> grant all on testdb.* to 'testuser'@'localhost'; Query OK, 0 rows affected (0.05 sec) mysql> quit Bye
_mysql 模块
_mysql模块是直接调用的MySQL C api,跟python db api 接口没有必然联系
通常, 程序员们都倾向于使用MySQLdb模块,我们稍后再看。
现在先看下关于_mysql模块的例子
#!/usr/bin/env python # -*- coding: utf-8 -*- import _mysql import sys try: con = _mysql.connect('localhost', 'testuser', '123456', 'testdb') con.query('select version()') result = con.use_result() print 'MySQL version: %s' % \ result.fetch_row()[0] except _mysql.Error, e: print "Error %d: %s" % (e.args[0], e.args[1]) sys.exit(1) finally: if con: con.close()
这个例子会打印出mysql数据库的版本,sql采用的是 'select version();' 代码地址:https://gist.github.com/stefanmonkey/8312902
MySQLdb 模块 MySQLdb 是围绕_mysql构建的瘦python包装(原文:MySQLdb is a thin Python wrapper around _mysql) 它与Python DB API协同工作. 这个模块是首选与mysql一起工作的模块
第一个例子
这个例子同样是得到mysql 数据库的版本
#!/usr/bin/env python # -*- coding: utf-8 -*- import MySQLdb as mdb import sys try: con = mdb.connect('localhost', 'testuser', '123456', 'testdb') cur = con.cursor() cur.execute('select version()') ver = cur.fetchone() print "Database version : %s " % ver except mdb.Error, e: print "Error %d: %s" % (e.args[0], e.args[1]) sys.exit(1) finally: if con: con.close()
代码地址:https://gist.github.com/stefanmonkey/8312907 因为我们接收到只有一个记录,所以我们调用fetchone()方法 在ubuntu环境下执行 会是这个样子 root@ubuntu:~# python MySQLdb.py
Database version : 5.5.34-0ubuntu0.12.04.1
创建表并加上加上一些数据
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', '123456', 'testdb'); with con: cur = con.cursor() cur.execute("DROP TABLE IF EXISTS Writers") cur.execute("CREATE TABLE Writers(Id INT PRIMARY KEY AUTO_INCREMENT, \ Name VARCHAR(25))") cur.execute("INSERT INTO Writers(Name) VALUES('Jack London')") cur.execute("INSERT INTO Writers(Name) VALUES('Honore de Balzac')") cur.execute("INSERT INTO Writers(Name) VALUES('Lion Feuchtwanger')") cur.execute("INSERT INTO Writers(Name) VALUES('Emile Zola')") cur.execute("INSERT INTO Writers(Name) VALUES('Truman Capote')")
代码地址:https://gist.github.com/stefanmonkey/8312916
执行结果如下:
root@ubuntu:~# python table.py table.py:11: Warning: Unknown table 'Writers' cur.execute("DROP TABLE IF EXISTS Writers")
这个warning处,具体是我们使用了with语句,它可以让python解释器自动释放资源,也可以提供错误处理这里是因为新创建的Writers表,第一个drop就会有错误,脚本很简陋,只是摸索mysqldb的使用,没必要加错误判断
root@ubuntu:~# mysql -u root -p123456 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8768 Server version: 5.5.34-0ubuntu0.12.04.1 (Ubuntu) Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use testdb; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +------------------+ | Tables_in_testdb | +------------------+ | Writers | +------------------+ 1 row in set (0.00 sec) mysql> select * from Writers; +----+-------------------+ | Id | Name | +----+-------------------+ | 1 | Jack London | | 2 | Honore de Balzac | | 3 | Lion Feuchtwanger | | 4 | Emile Zola | | 5 | Truman Capote | +----+-------------------+ 5 rows in set (0.00 sec) mysql>
接收数据
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', '123456', 'testdb'); with con: cur = con.cursor() cur.execute("SELECT * FROM Writers") rows = cur.fetchall() for row in rows: print row
代码地址:https://gist.github.com/stefanmonkey/8312969
rows = cur.fetchall()fetchall()方法得到所有记录。它返回一个结果集。
从技术上讲, 是一个嵌套的元组。每一个内嵌的元组代表表里面的一行
执行结果如下:
root@ubuntu:~# python get_data.py (1L, 'Jack London') (2L, 'Honore de Balzac') (3L, 'Lion Feuchtwanger') (4L, 'Emile Zola') (5L, 'Truman Capote')
返回所有数据显然不是一个明智的做法。我们可以一行一行的来
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', 'test623', 'testdb'); with con: cur = con.cursor() cur.execute("SELECT * FROM Writers") for i in range(cur.rowcount): row = cur.fetchone() print row[0], row[1]
代码地址:https://gist.github.com/stefanmonkey/8313022
rowcount属性会返回sql执行后得到的行数
字典游标
在MySQLdb模块中,有多个游标类型。默认的游标以嵌套元组返回数据。当我们使用字典游标时, 数据会以python字典的形式获取,以这种方式为基础,我们可以根据列名获取数据
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', '123456', 'testdb') with con: cur = con.cursor(mdb.cursors.DictCursor) cur.execute("SELECT * FROM Writers LIMIT 4") rows = cur.fetchall() for row in rows: print row["Id"], row["Name"]
代码地址:https://gist.github.com/stefanmonkey/8313196
cur = con.cursor(mdb.cursors.DictCursor)表示使用字典游标(dictionary cursor)
执行结果:
python dictcur.py 1 Jack London 2 Honore de Balzac 3 Lion Feuchtwanger 4 Emile Zola
列名 接下来我们会示范,怎样从数据库的表中,同时打印数据和对应的列名
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', '123456', 'testdb') with con: cur = con.cursor() cur.execute("SELECT * FROM Writers LIMIT 5") rows = cur.fetchall() desc = cur.description print "%s %3s" % (desc[0][0], desc[1][0]) for row in rows: print "%2s %3s" % row
代码地址:https://gist.github.com/stefanmonkey/8313251desc = cur.descriptiondescription属性返回查询结果的每一个列名
print "%s %3s" % (desc[0][0], desc[1][0])格式化打印表的列名
运行结果如下:
python columnheaders.py Id Name 1 Jack London 2 Honore de Balzac 3 Lion Feuchtwanger 4 Emile Zola 5 Truman Capote
预设语句
利用占位符创建预设语句。Python DB API指南建议5中不同的方式创建预设语句。MySQLdb模块支持其中一种.
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb con = mdb.connect('localhost', 'testuser', 'test623', 'testdb') with con: cur = con.cursor() cur.execute("UPDATE Writers SET Name = %s WHERE Id = %s", ("Guy de Maupasant", "4")) print "Number of rows updated:", cur.rowcount
代码地址:https://gist.github.com/stefanmonkey/8313313
执行结果如下:root@ubuntu:~# python prepared.py
Number of rows updated: 1
可以看到数据库中第4行的作家名字已经被修改
mysql> select name from Writers where id =4; +------------------+ | name | +------------------+ | Guy de Maupasant | +------------------+ 1 row in set (0.00 sec)
在mysql中插入图片
图片是二进制数据。Mysql有特殊的数据类型去存储二进制数据,这个类型是BlOB
创建相应的表
mysql> create table images(id int primary key, data mediumblob);Query OK, 0 rows affected (0.01 sec)
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb def read_image(): fin = open("woman.jpg") img = fin.read() return img con = mdb.connect('localhost', 'testuser', '123456', 'testdb') with con: cur = con.cursor() data = read_image() cur.execute("INSERT INTO images VALUES(1, %s)", (data, ))
代码地址:https://gist.github.com/stefanmonkey/8313445
执行即可图片是与脚本在同一目录 图片名称修改下即可
读取图片
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb def writeImage(data): fout = open('woman2.jpg', 'wb') with fout: fout.write(data) con = mdb.connect('localhost', 'testuser', 'test623', 'testdb') with con: cur = con.cursor() cur.execute("SELECT Data FROM Images WHERE Id=1") data = cur.fetchone()[0] writeImage(data)
代码地址:https://gist.github.com/stefanmonkey/8313476
执行后 我们在当前目录就有了woman2.jpg ,这个是woman.jgp是一样的哦
事务支持待续
事务支持的部分回去慢慢品味
接下来就是扫下mysql的书看下哪些有用的性能指标,然后加进ztc让zabbix欢快地跑起来