Kısa cevap. discord.py botunuza aiomysql ekleyin, setup_hook içinde autocommit=True ile tek bir havuz oluşturun ve her sorguyu %s yer tutucularıyla bu havuz üzerinden çalıştırın. autocommit=True olmadan (ya da her yazmadan sonra bir commit() olmadan) aiomysql INSERT’lerinizi kaydetmez. PlayNHost’ta her bot planı bir MySQL veritabanı içerir: onu Veritabanları sayfasında oluşturun, bilgilerini Ortam bölmesine yapıştırın, aşağıdaki kod olduğu gibi çalışır. Veritabanı, PlayNHost sunucularınızdan ve phpMyAdmin’den gelen bağlantıları kabul eder; kendi bilgisayarınızdan gelenleri kabul etmez. Bu kodu 6 Kasım 2026’da discord.py 2.7.1, aiomysql 0.3.2 ve Python 3.12 ile, bizimki gibi ayarlanmış bir veritabanı hesabıyla (20 bağlantı, 120 saniyelik sorgu sınırı) MariaDB 10.11 üzerinde denedik: başlatma, tablo ve /warn komutu, ancak gerçek bir Discord girişi değil.
Bot sunucunuzu panelde açın ve Veritabanları seçeneğine tıklayın.
Yeni veritabanı seçeneğine tıklayın. Etiket alanı isteğe bağlıdır; Şu adla oluşturulacak: alanı tam adı gösterir. Veritabanı oluştur düğmesine tıklayın.
Yeni veritabanının sayfası açılır (daha sonra Veritabanlarınız bölümünden ona tıklayın). Bağlantı kartında Sunucu adresi, Port, Veritabanı, Kullanıcı Adı ve Şifre görünür. Hazır yapılandırma altında, Şunun için yapılandırma içinde aynı değerlerin doldurulduğu bir Python (aiomysql) parçası bulunur.
import os
import aiomysql
import discord
from discord import app_commands
class Bot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
self.pool = None
async def setup_hook(self):
# One pool for the whole bot. The values come from the Environment pane.
self.pool = await aiomysql.create_pool(
host=os.environ["DB_HOST"],
port=int(os.environ["DB_PORT"]),
user=os.environ["DB_USER"],
password=os.environ["DB_PASSWORD"],
db=os.environ["DB_NAME"],
autocommit=True,
maxsize=5,
)
async with self.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(
"CREATE TABLE IF NOT EXISTS warnings ("
"id INT AUTO_INCREMENT PRIMARY KEY, "
"guild_id BIGINT UNSIGNED NOT NULL, "
"user_id BIGINT UNSIGNED NOT NULL, "
"reason VARCHAR(200) NOT NULL, "
"created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
"KEY guild_user (guild_id, user_id))"
)
print("Database ready")
await self.tree.sync()
async def close(self):
if self.pool is not None:
self.pool.close()
await self.pool.wait_closed()
await super().close()
bot = Bot()
@bot.tree.command(description="Warn a member and count their warnings")
@app_commands.guild_only()
@app_commands.describe(user="Who to warn", reason="Why")
async def warn(interaction: discord.Interaction, user: discord.Member, reason: app_commands.Range[str, 1, 200]):
async with bot.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(
"INSERT INTO warnings (guild_id, user_id, reason) VALUES (%s, %s, %s)",
(interaction.guild_id, user.id, reason),
)
await cur.execute(
"SELECT COUNT(*) FROM warnings WHERE guild_id = %s AND user_id = %s",
(interaction.guild_id, user.id),
)
(total,) = await cur.fetchone()
await interaction.response.send_message(f"{user.mention} has {total} warning(s).")
@bot.event
async def on_ready():
print(f"Logged in as {bot.user}")
bot.run(os.environ["DISCORD_TOKEN"])
Ne yapar: discord.py setup_hook işlevini giriş sırasında, herhangi bir olay gelmeden önce bir kez çalıştırır; böylece havuz ve warnings tablosu ilk komut gelmeden önce hazır olur. Sonra /warn komutunu Discord’a kaydeder. @app_commands.guild_only(), komutu uyarının kaydedileceği bir sunucunun olmadığı özel mesajların dışında tutar. Discord kimlikleri BIGINT UNSIGNED içine sığar. %s yer tutucularını sürücü doldurur, bu yüzden '); DROP TABLE warnings; -- gibi bir neden düz metin olarak kaydedilir. SQL’i asla bir f-string ile oluşturmayın.
4. Çalıştırın
bot.py ve requirements.txt dosyalarını Dosyalar bölümünden yükleyin.
Başlat düğmesine basın ve Konsol bölümünü açın. Başlatma, requirements.txt içindeki paketleri kurar, ardından [PlayNHost] Starting your bot ve Database ready görünür.
Discord’da /warn yazın. Satırlara bakmak için veritabanının sayfasını açın ve phpMyAdmin’de aç düğmesine tıklayın.
autocommit tuzağı
aiomysql bağlantıları autocommit kapalı olarak açar. Bu durumda bir INSERT açık bir işlemin içinde kalır. Bağlantı o işlem hâlâ açıkken havuza döndüğünde aiomysql onu kapatır ve MariaDB onaylanmamış satırı atar. Testimizde, autocommit=True olmayan bir havuzda eklenen satırı 0 başka bağlantı gördü. Ya yukarıdaki gibi autocommit=True değerini create_pool işlevine verin ya da yazmalarınızdan sonra await conn.commit() çağırın.
Havuzunuz için önemli sınırlar
Veritabanı kullanıcısı başına aynı anda 20 bağlantı. Aynı girişi kullanan her işlem sayılır. 21. bağlantı (1226, "User '...' has exceeded the 'max_user_connections' resource (current value: 20)") ile reddedilir. maxsize=5 botu bunun epey altında tutar.
120 saniyeden uzun süren bir sorgu durdurulur. MariaDB onu 1969 hatasıyla, Query execution was interrupted (max_statement_time exceeded), sonlandırır. Testimizde bu 120.03 saniye sonra oldu. Bir botun sorguları normalde milisaniyeler sürer, yani bu yalnızca kontrolden çıkmış bir sorguyu etkiler.
Veritabanı başına 500 MB.Veritabanları sayfası ne kadarının kullanıldığını gösterir. 500 MB’a gelince, siz satırları silene kadar yazma işlemleri durdurulur.
Sunucu yedekleri veritabanını içermez. Zaman zaman phpMyAdmin’den dışa aktarın.
Hatalar ve ne anlama geldikleri
Bunlar aiomysql’in testimizde verdiği tam hatalardır (aiomysql’in altta kullandığı PyMySQL’den gelirler):
pymysql.err.OperationalError (1045, "Access denied for user ..."): yanlış DB_USER ya da DB_PASSWORD. Bağlantı kartında Şifreyi sıfırla işleminden sonra eski şifre hemen çalışmaz: DB_PASSWORD değerini değiştirin ve botu yeniden başlatın.
pymysql.err.OperationalError (2003, "Can't connect to MySQL server on ..."): yanlış sunucu adresi ya da port, ya da PlayNHost dışından bir bağlantı. Veritabanı yalnızca PlayNHost sunucularından ve phpMyAdmin’den gelen bağlantıları kabul eder, bu yüzden kendi bilgisayarınızda da bunu alırsınız.
(1226, ... 'max_user_connections' ...): çok fazla bağlantı açık, yukarıdaki sınırlara bakın.
Ortam içinde eksik bir değişken botu bağlanmadan önce KeyError: 'DB_HOST' ya da eksik olanın adıyla durdurur, çünkü kod her değeri os.environ[...] ile okur. Onu ekleyin, sonra botu yeniden başlatın: değişkenler bir sonraki başlatmada geçerli olur.
discord.py ve aiomysql’i pip ile sıfırdan kurmak testimizde en çok 78 MB bellek kullandı, en küçük bot planımız gibi 512 MB ile sınırlı bir konteynerde. Çalışan botun ne kadar belleğe ihtiyaç duyduğu çoğunlukla kaç sunucuda olduğuna bağlıdır: Bir Discord botunun ne kadar RAM’e ihtiyacı var?
Sitenin çalışması, nasıl kullanıldığını anlamamız ve pazarlamamızı ölçmemiz için çerez kullanıyoruz. Tümünü kabul edebilir, yalnızca zorunlu çerezleri kabul edebilir veya kategori bazında seçebilirsiniz.Sitenin çalışması, nasıl kullanıldığını anlamamız ve pazarlamamızı ölçmemiz için çerez kullanıyoruz. Burada varsayılan olarak açıktır. İstemediklerinizi kapatabilirsiniz.Gizlilik politikamızı okuyun