我正在将Python 2.7中的MySQLdb模块与MariaDB数据库一起使用。我想知道跨多个模块使用数据库的正确方法。我有一个示例,尝试将另一个函数中的元素插入数据库。我越来越OperationalError: (1046, 'No database selected')
编辑:这里是校正码(1,2)。谢谢。知道我想要这样一个带有依赖注入的工作示例。
这是我要在其中处理数据库的模块。
# test.py
import MySQLdb
import traceback
import test2 as insert_module
from warnings import filterwarnings
# Ignore MySQL `table already exists` warnings
filterwarnings ('ignore', category = MySQLdb.Warning)
# Create database object to keep it open as global variable
class MyDB (object):
connection = None
cursor = None
# Open database connection
def connect (self):
self.connection = MySQLdb.connect ()
self.cursor = self.connection.cursor ()
def execute (self, sql, *args):
try:
self.cursor.execute (sql, *args)
self.connection.commit ()
except MySQLdb.Error, e:
print (traceback.format_exc())
self.connection.rollback ()
def query (self, sql, *args):
try:
self.execute (sql, *args)
# Reopen database connection
except ( AttributeError, MySQLdb.OperationalError ):
self.connect ()
self.execute (sql, *args)
def disconnect (self):
self.connection.close ()
db = MyDB ()
def createDatabase ():
db.query ("CREATE DATABASE IF NOT EXISTS Product")
db.query ("USE Product")
sql = """CREATE TABLE IF NOT EXISTS `ProductColor` (
`ProductID` VARCHAR(20) PRIMARY KEY,
`ColorID` VARCHAR(20)
)"""
db.query (sql)
def insertProductColor (*args):
sql = """INSERT INTO `ProductColor` VALUE (%s, %s)"""
db.query (sql, args)
def main ():
createDatabase ()
insert_module.processListOfProductColors ()
if __name__ == "__main__":
main ()
db.disconnect ()
这是我要从中插入产品的模块。
#test2.py
import test as db_module
def processListOfProductColors ():
db_module.insertProductColor ("cup", "blue")
解决方案
大多无关,但:
# Create database object to keep it open as global variable
class MyDB (object):
connection = None
cursor = None
这些类属性是无用的-将它们定义为实例属性:
def __init__(self):
self.connection = None
self.cursor = None
当我们使用它时:不要对所有查询重复使用相同的游标。否则,当您在遍历第一个查询的结果时尝试执行另一个查询时会遇到麻烦(并且不要谈论多线程...)
# Open database connection
def connect (self):
self.connection = MySQLdb.connect ()
当然,您应该检查是否已经打开了连接,如果可以,请先关闭它,或者只是跳过MySQLdb.connect()呼叫。
同样,对于FWIW,您必须将连接信息(用户名,密码,数据库名称等)传递给MySQLdb.connect()呼叫。您的OperationalError来自未在此处传递数据库名称。
self.cursor = self.connection.cursor ()
cf以上:这只会给您带来麻烦。每次使用一个新的游标,这就是dbapi的预期用途。
def execute (self, sql, *args):
try:
self.cursor.execute (sql, *args)
cf以上
self.connection.commit ()
您应该给调用方一种在每次调用后不提交的方式-他可能希望在单个事务中执行多个语句(实际上这是进行事务的一部分...)
except MySQLdb.Error, e:
你要:
except MySQLdb.Error as e:
print (traceback.format_exc())
设置记录器(python的logging模块)并调用logger.exception(...)。
self.connection.rollback ()
和?假装没关系???您显然想在这里重新引发异常。
def query (self, sql, *args):
try:
self.execute (sql, *args)
您确定要提交读取查询的事务吗?
# Reopen database connection
except ( AttributeError, MySQLdb.OperationalError ):
self.connect ()
self.execute (sql, *args)
错误...如果要延迟处理连接,则您失败了。看看python对计算属性的支持(property等)。
def disconnect (self):
self.connection.close ()
更笼统地说:尝试将连接部分包装在可以(最终懒惰地)处理连接问题的东西中可能是一个好主意(但也不是那么容易...),但是一定要让调用者处理光标并手动交易。这里的一个解决办法是使execute()和query() 上下文管理器是关闭游标并提交(或回滚)事务。还要记住,不良的异常处理比没有异常处理更糟糕。