Python 如何使用.using()优雅地处理OperationalError2003和更改数据库
假设您有一个Django 1.11应用程序,Python 如何使用.using()优雅地处理OperationalError2003和更改数据库,python,mysql,django,python-3.x,Python,Mysql,Django,Python 3.x,假设您有一个Django 1.11应用程序,该应用程序在站点该站点上 在站点/settings.py中,您有以下数据库: DATABASES = { 'default': { 'ENGINE': 'django.db.back
该应用程序在站点该站点上
在站点/settings.py
中,您有以下数据库:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'the-site_webapp',
'USER': 'tester',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306',
},
'remote-db1': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'remote-db1',
'USER': 'tester',
'PASSWORD': '',
'HOST': '<ip1>',
'PORT': '3306',
},
'remote-db2': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'remote-db2',
'USER': 'tester',
'PASSWORD': '',
'HOST': '<ip2>',
'PORT': '3306',
},
}
指向app/routers.py的:
class MasterRouter(object):
'''
https://stackoverflow.com/questions/13988432/how-to-use-db-router-in-django-1-4
'''
def __init__(self, app_label, db_name):
super(MasterRouter, self).__init__()
self.app_label = app_label
self.db_name = db_name
def db_for_read(self, model, **hints):
if model._meta.app_label == self.app_label:
return self.db_name
#return self.app_label
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == self.app_label:
return self.db_name
return None
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == self.app_label or obj2._meta.app_label == self.app_label:
return True
return None
def allow_syncdb(self, db, model):
if db == 'default':
return model._meta.app_label == self.app_label
elif model._meta.app_label == self.app_label:
return False
return None
def allow_migrate(self, db, *args, **kwargs):
if db in ['remote-db1']:
return False
class DefaultRouter(MasterRouter):
def __init__(self):
super(DefaultRouter, self).__init__('default', 'default')
class the-appRouter(MasterRouter):
def __init__(self):
super(the-appRouter, self).__init__('the-app', 'remote-db1')
在app/views.py的中,您有:
def foo (request):
try:
curfile = ModelName.objects.get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, ModelName.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t find sample in remote-db1; attempting to connect to remote-db2')
try:
curfile = ModelName.objects.using('remote-db2').get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, ModelName.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
return render(request, 'foo.html')
except (OperationalError,) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db2.')
traceback.print_exc() # debugging
return render(request, 'invalid.html')
except (OperationalError) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db1. Trying remote-db2.')
traceback.print_exc() # debugging
try:
curfile = ModelName.objects.using('remote-db2').get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, SampleFile.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
return render(request, 'view_info.html')
except (OperationalError,) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to either remote-db1 nor to remote-db2.')
traceback.print_exc() # debugging
return render(request, 'invalid.html')
查看traceback
日志,似乎发生了这样的情况:尽管我用告诉Django。使用('remote-db2')
连接到remote-db2
,它还是会再次尝试连接到remote-db1
在我这方面,有没有什么地方可以处理这个操作错误(代码2003)?它(第205行)这可能是不可能的(),但必须有某种方式以某种方式优雅地处理此问题,而不是呈现一个错误页面,上面写着“稍后再试”
非常感谢您花时间阅读,以及您能给我的任何帮助:)
编辑:我既不管理旧数据库也不管理新数据库,因此我无法在数据库端轻松实现任何类型的负载平衡或故障切换策略。我被引导到django failover:github.com/brianjaystanley/django-failover(很抱歉,由于n00b状态,一篇文章中不能做超过2个链接),但我使用的是python 3.5,如果它仍然适用于django 1.11,则必须更新包!此外,两个远程数据库的模式略有不同,尽管它们包含关于相同对象的信息,因此django故障切换将不适用
相关职位:
stackoverflow.com/questions/18174910/django-database-routers-failover-scenario
stackoverflow.com/questions/28554740/in-django-1-6-handle-mysql-failover-while-use-database-routers
(我在写这篇文章之前读过其他人的文章,但问题与错误配置有关)你为什么要这样做?为什么不是一个数据库呢?我必须操作一个旧数据库和一个更新的数据库;传统数据库remote_db1
,包含一大堆大多数进程不再需要的表,而且由于记录的数量太多,很难进行搜索。较新的数据库remote_db2
,包含remote_db1
中的数据截断(仅1个月前),以及原始表的子集。对一些表的模式也进行了一些小的更改。但是,如果旧数据库出现问题,那么我希望故障切换到新的数据库。为什么要这样做?为什么不是一个数据库呢?我必须操作一个旧数据库和一个更新的数据库;传统数据库remote_db1
,包含一大堆大多数进程不再需要的表,而且由于记录的数量太多,很难进行搜索。较新的数据库remote_db2
,包含remote_db1
中的数据截断(仅1个月前),以及原始表的子集。对一些表的模式也进行了一些小的更改。但是,如果遗留数据库出现问题,那么我希望故障切换到新的数据库。
def foo (request):
try:
curfile = ModelName.objects.get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, ModelName.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t find sample in remote-db1; attempting to connect to remote-db2')
try:
curfile = ModelName.objects.using('remote-db2').get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, ModelName.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
return render(request, 'foo.html')
except (OperationalError,) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db2.')
traceback.print_exc() # debugging
return render(request, 'invalid.html')
except (OperationalError) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to remote-db1. Trying remote-db2.')
traceback.print_exc() # debugging
try:
curfile = ModelName.objects.using('remote-db2').get(**arg_dict)
return _fetch_info(request, curfile)
except (KeyError, SampleFile.DoesNotExist) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t fetch sample data.')
return render(request, 'view_info.html')
except (OperationalError,) as e:
messages.add_message(request, messages.ERROR, 'Couldn\'t connect to either remote-db1 nor to remote-db2.')
traceback.print_exc() # debugging
return render(request, 'invalid.html')