SQLAlchemy を使用してゲームサーバーを作成しています。
ゲームサーバーは非常に高速である必要があるため、ユーザー ID (整数) に応じてデータベースを分離することにしました。
たとえば、次のように成功しました。
from threading import Thread
from sqlalchemy import Column, Integer, String, DateTime, create_engine
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy.orm import sessionmaker
DeferredBase = declarative_base(cls=DeferredReflection)
class BuddyModel(DeferredBase):
__tablename__ = 'test_x'
id = Column(Integer(), primary_key=True, autoincrement=True)
value = Column(String(50), nullable=False)
次のコードは複数のデータベースを作成します。
test1 ~ test10 のデータベースがあります。
for i in range(10):
url = 'mysql://user@localhost/'
engine = create_engine(url, encoding='UTF-8', pool_recycle=300)
con = engine.connect()
con.execute('create database test%d' % i)
次のコードは、10 個の個別のエンジンを作成します。
get_engine() 関数は、ユーザー ID に応じてエンジンを提供します。
(ユーザーIDは整数)
engines = []
for i in range(10):
url = 'mysql://user@localhost/test%d'% i
engine = create_engine(url, encoding='UTF-8', pool_recycle=300)
DeferredBase.metadata.bind = engine
DeferredBase.metadata.create_all()
engines.append(engine)
def get_engine(user_id):
index = user_id%10
return engines[index]
prepare 関数を実行すると、BuddyModel クラスが準備され、エンジンにマッピングされます。
def prepare(user_id):
engine = get_engine(user_id)
DeferredBase.prepare(engine)
** 次のコードは、私がやりたいことを正確に実行します **
for user_id in range(100):
prepare(user_id)
engine = get_engine(user_id)
session = sessionmaker(engine)()
buddy = BuddyModel()
buddy.value = 'user_id: %d' % user_id
session.add(buddy)
session.commit()
しかし、問題は、複数のスレッドで実行するとエラーが発生することです
class MetalMultidatabaseThread(Thread):
def run(self):
for user_id in range(100):
prepare(user_id)
engine = get_engine(user_id)
session = sessionmaker(engine)()
buddy = BuddyModel()
buddy.value = 'user_id: %d' % user_id
session.add(buddy)
session.commit()
threads = []
for i in range(100):
t = MetalMultidatabaseThread()
t.setDaemon(True)
t.start()
threads.append(t)
for t in threads:
t.join()
エラーメッセージは...
ArgumentError: Class '<class '__main__.BuddyModel'>' already has a primary mapper defined. Use non_primary=True to create a non primary Mapper. clear_mappers() will remove *all* current mappers from all classes.
だから..私の質問は、SQLAlchemyを使用して上記のアーキテクチャのように複数のデータベースを実行するにはどうすればよいですか?