From 18bf611eba2805f08f1e46853ebb06094fa1df46 Mon Sep 17 00:00:00 2001 From: Jonas <77726472+kobolol@users.noreply.github.com> Date: Fri, 21 Nov 2025 23:15:26 +0100 Subject: [PATCH] Refactor database managers to use per-request connections --- backend/src/Database/DataBaseManager.js | 25 ++-- .../src/Database/ScoreManager/ScoreManager.js | 85 +++++++----- .../src/Database/UserManager/UserManager.js | 125 +++++++++++------- 3 files changed, 143 insertions(+), 92 deletions(-) diff --git a/backend/src/Database/DataBaseManager.js b/backend/src/Database/DataBaseManager.js index 91afeec..2c138de 100644 --- a/backend/src/Database/DataBaseManager.js +++ b/backend/src/Database/DataBaseManager.js @@ -5,23 +5,28 @@ require("dotenv").config(); class DataBaseManager { constructor(host, database) { - this.connection = mySql.createConnection({ + this.connectionConfig = { host: host, port: process.env.DB_PORT || 3306, user: "root", password: process.env.DB_PASSWORD || undefined, database: database + }; + + const connectionFactory = () => this.createConnection(); + + this.usermanager = new UserManager(connectionFactory); + this.scoremanager = new ScoreManager(connectionFactory); + } + + createConnection() { + const connection = mySql.createConnection(this.connectionConfig); + + connection.on("error", (error) => { + console.error("Database connection error:", error); }); - this.connection.connect((err) => { - if (err) { - throw err; - - } - }); - - this.usermanager = new UserManager(this.connection); - this.scoremanager = new ScoreManager(this.connection); + return connection; } } diff --git a/backend/src/Database/ScoreManager/ScoreManager.js b/backend/src/Database/ScoreManager/ScoreManager.js index 08075d3..ca984f1 100644 --- a/backend/src/Database/ScoreManager/ScoreManager.js +++ b/backend/src/Database/ScoreManager/ScoreManager.js @@ -2,42 +2,59 @@ const mySql = require("mysql2"); const Score = require("./Score"); class ScoreManager{ - /**@param {mySql.Connection} connection*/ - constructor(connection) { - this.connection = connection; + /**@param {() => mySql.Connection} connectionFactory*/ + constructor(connectionFactory) { + this.connectionFactory = connectionFactory; this.splitLimit = 25; } - async getAllScores(){ - const response = await this.connection.promise().query("SELECT * FROM scores ORDER BY score DESC"); - const sortedScores = response[0].map((scoreData, index) => new Score(scoreData, index + 1)); + async withConnection(callback) { + const connection = this.connectionFactory(); - return sortedScores; + try { + return await callback(connection); + } + finally { + connection.end(); + } + } + + async getAllScores(){ + return await this.withConnection(async (connection) => { + const response = await connection.promise().query("SELECT * FROM scores ORDER BY score DESC"); + const sortedScores = response[0].map((scoreData, index) => new Score(scoreData, index + 1)); + + return sortedScores; + }); } async createScore(newScoreJson){ - const sql = "INSERT INTO scores (user1, user2, score) VALUES (?, ?, ?)"; + return await this.withConnection(async (connection) => { + const sql = "INSERT INTO scores (user1, user2, score) VALUES (?, ?, ?)"; - const insertResult = await this.connection - .promise() - .query(sql, [newScoreJson.user1, newScoreJson.user2, newScoreJson.score]); - const insertId = insertResult[0].insertId; + const insertResult = await connection + .promise() + .query(sql, [newScoreJson.user1, newScoreJson.user2, newScoreJson.score]); + const insertId = insertResult[0].insertId; - const selectSql = "SELECT * FROM scores WHERE id = ?"; - const selectResult = await this.connection.promise().query(selectSql, [insertId]); + const selectSql = "SELECT * FROM scores WHERE id = ?"; + const selectResult = await connection.promise().query(selectSql, [insertId]); - const rank = await this.getRankById(insertId); + const rank = await this.getRankById(insertId); - return new Score(selectResult[0][0], rank); + return new Score(selectResult[0][0], rank); + }); } async getScoreById(id){ - const response = await this.connection.promise().query("SELECT * FROM scores WHERE id = ?", [id]); + return await this.withConnection(async (connection) => { + const response = await connection.promise().query("SELECT * FROM scores WHERE id = ?", [id]); - const rank = await this.getRankById(id); + const rank = await this.getRankById(id); - return new Score(response[0][0], rank); + return new Score(response[0][0], rank); + }); } async getSplitedScoreCount(){ @@ -51,26 +68,30 @@ class ScoreManager{ async getSpiltedScore(count){ const offset = (count - 1) * this.splitLimit; - const response = await this.connection.promise().query( - `SELECT * FROM scores ORDER BY score DESC LIMIT ${this.splitLimit} OFFSET ${offset}`, - ); + return await this.withConnection(async (connection) => { + const response = await connection.promise().query( + `SELECT * FROM scores ORDER BY score DESC LIMIT ${this.splitLimit} OFFSET ${offset}`, + ); - const sortedScoreSplit = response[0].map((scoreData, index) => { - const rank = offset + index + 1; - return new Score(scoreData, rank); + const sortedScoreSplit = response[0].map((scoreData, index) => { + const rank = offset + index + 1; + return new Score(scoreData, rank); + }); + + return sortedScoreSplit; }); - - return sortedScoreSplit; } async getRankById(id){ - const rankSql = - "SELECT COUNT(*) + 1 AS rank_position FROM scores WHERE score > (SELECT score FROM scores WHERE id = ?)"; - const rankResult = await this.connection.promise().query(rankSql, [id]); + return await this.withConnection(async (connection) => { + const rankSql = + "SELECT COUNT(*) + 1 AS rank_position FROM scores WHERE score > (SELECT score FROM scores WHERE id = ?)"; + const rankResult = await connection.promise().query(rankSql, [id]); - const rank = rankResult[0][0]?.rank_position ?? null; + const rank = rankResult[0][0]?.rank_position ?? null; - return rank; + return rank; + }); } } diff --git a/backend/src/Database/UserManager/UserManager.js b/backend/src/Database/UserManager/UserManager.js index 3b82465..3ffa3a4 100644 --- a/backend/src/Database/UserManager/UserManager.js +++ b/backend/src/Database/UserManager/UserManager.js @@ -3,9 +3,20 @@ const bcrypt = require("bcrypt") const User = require("./User") class UserManager { - /**@param {mySql.Connection} connection*/ - constructor(connection) { - this.connection = connection; + /**@param {() => mySql.Connection} connectionFactory*/ + constructor(connectionFactory) { + this.connectionFactory = connectionFactory; + } + + async withConnection(callback) { + const connection = this.connectionFactory(); + + try { + return await callback(connection); + } + finally { + connection.end(); + } } // Gebe zumindest {username: "x", password: "x"} mit! @@ -16,14 +27,20 @@ class UserManager { const user = await this.getUser({username: userJson.username}); if(user) return 0; - try { - const passHash = await bcrypt.hash(userJson.password, 10); - this.connection.query(`INSERT INTO users (username, email, password, fullName) VALUES ("${userJson.username}",` + - ` ${userJson.email ? `"${userJson.email}"` : "NULL"}, "${passHash}", ${userJson.fullName ? `"${userJson.fullName}"` : "NULL"})`); - return 1; - } catch (error) { - console.log(error); - } + return await this.withConnection(async (connection) => { + try { + const passHash = await bcrypt.hash(userJson.password, 10); + await connection + .promise() + .query( + `INSERT INTO users (username, email, password, fullName) VALUES ("${userJson.username}",` + + ` ${userJson.email ? `"${userJson.email}"` : "NULL"}, "${passHash}", ${userJson.fullName ? `"${userJson.fullName}"` : "NULL"})` + ); + return 1; + } catch (error) { + console.log(error); + } + }); } // Gebe nichts mit um alle user zu bekommen oder {id: 1} oder {username: "x"} um darauf einen bestimmten zu bekommen; @@ -37,30 +54,32 @@ class UserManager { selectionString = `SELECT * FROM users WHERE username="${userData.username}"`; } - try { - const response = await this.connection.promise().query(selectionString); - - if(response[0].length === 0){ - return null; - } - else if(response[0].length === 1){ - const x = response[0][0]; - return new User(x); - } - else{ - let userArray = []; - - response[0].forEach(x => { - const user = new User(x); + return await this.withConnection(async (connection) => { + try { + const response = await connection.promise().query(selectionString); - userArray.push(user); - }); + if(response[0].length === 0){ + return null; + } + else if(response[0].length === 1){ + const x = response[0][0]; + return new User(x); + } + else{ + let userArray = []; - return userArray; + response[0].forEach(x => { + const user = new User(x); + + userArray.push(user); + }); + + return userArray; + } + } catch (error) { + console.log(error); } - } catch (error) { - console.log(error); - } + }); } // 0: User Existiert nicht | 1: Funktioniert @@ -70,19 +89,23 @@ class UserManager { if(!user) return 0; if(!newUserData.password) return 0; - try { - this.connection.query( - `UPDATE users SET - username="${newUserData.username}", - email=${newUserData.email ? `"${newUserData.email}"` : "NULL"}, - fullName=${newUserData.fullName ? `"${newUserData.fullName}"` : "NULL"}, - password="${newUserData.password}" + return await this.withConnection(async (connection) => { + try { + await connection + .promise() + .query( + `UPDATE users SET + username="${newUserData.username}", + email=${newUserData.email ? `"${newUserData.email}"` : "NULL"}, + fullName=${newUserData.fullName ? `"${newUserData.fullName}"` : "NULL"}, + password="${newUserData.password}" WHERE id = ${id}` - ) - return 1; - } catch (error) { - console.log(error) - } + ); + return 1; + } catch (error) { + console.log(error) + } + }); } // 0: Es gibt den User nicht | 1: Funktioniert @@ -90,12 +113,14 @@ class UserManager { const user = await this.getUser({id}); if(!user) return 0; - try { - this.connection.query(`DELETE FROM users where id=${id}`); - return 1; - } catch (error) { - console.log(error) - } + return await this.withConnection(async (connection) => { + try { + await connection.promise().query(`DELETE FROM users where id=${id}`); + return 1; + } catch (error) { + console.log(error) + } + }); } }