""" Databaseverbindingen. - execute_query / get_db_connection → de database van de HUIDIGE school - central_query / get_central_connection → de centrale database (Scholen, Gebruikers, rechten, Logs, Bugs) Per database wordt lui een connection pool aangemaakt. """ import threading import mysql.connector from mysql.connector import pooling from config import Config _pools = {} _lock = threading.Lock() POOL_SIZE = Config.DB_POOL_SIZE # config.ini › [database] › pool_size (standaard 3) def _pool(host, user, password, database, port=None): key = (host, port or Config.DB_PORT, user, database) pool = _pools.get(key) if pool is None: with _lock: pool = _pools.get(key) if pool is None: naam = f"p{len(_pools)}_{database}"[:60] pool = pooling.MySQLConnectionPool( pool_name=naam, pool_size=POOL_SIZE, host=host, port=port or Config.DB_PORT, user=user, password=password, database=database, connection_timeout=10, # zelfde collatie als de tabellen (sql/*.sql); anders geeft MySQL 8 bij vergelijkingen # "Illegal mix of collations (utf8mb4_0900_ai_ci / utf8mb4_unicode_ci)" charset='utf8mb4', collation='utf8mb4_unicode_ci', # autocommit: elke query ziet meteen de laatste gegevens (ook na wijzigingen via een # andere verbinding uit de pool). Wie meerdere statements samen wil, gebruikt # conn.start_transaction() ... conn.commit(). autocommit=True) _pools[key] = pool return pool def vergeet_pools(database=None): """Na het wijzigen van de DB-gegevens van een school: pools opnieuw laten opbouwen.""" with _lock: for k in [k for k in _pools if database is None or k[3] == database]: _pools.pop(k, None) def get_db_connection(): """Verbinding met de database van de huidige school.""" from tenancy import huidige_school cfg = huidige_school().db_config() return _pool(cfg['host'], cfg['user'], cfg['password'], cfg['database']).get_connection() def get_central_connection(): return _pool(Config.DB_HOST, Config.DB_USER, Config.DB_PASSWORD, Config.DB_CENTRAAL).get_connection() def _run(conn, query, params, commit): cursor = conn.cursor(dictionary=True) try: cursor.execute(query, params) if commit: conn.commit() return cursor.rowcount return cursor.fetchall() finally: cursor.close() conn.close() # terug naar de pool def execute_query(query, params=(), commit=False): return _run(get_db_connection(), query, params, commit) def execute_insert(query, params=()): """INSERT in de database van de huidige school; geeft het nieuwe AUTO_INCREMENT-id terug.""" conn = get_db_connection() cursor = conn.cursor() try: cursor.execute(query, params) conn.commit() return cursor.lastrowid finally: cursor.close() conn.close() def central_query(query, params=(), commit=False): return _run(get_central_connection(), query, params, commit) def central_insert(query, params=()): """INSERT in de centrale database; geeft het nieuwe AUTO_INCREMENT-id terug.""" conn = get_central_connection() cursor = conn.cursor() try: cursor.execute(query, params) conn.commit() return cursor.lastrowid finally: cursor.close() conn.close()