diff --git a/src/main/java/client/Character.java b/src/main/java/client/Character.java index 59ec146921..dbbfe28a99 100644 --- a/src/main/java/client/Character.java +++ b/src/main/java/client/Character.java @@ -8438,7 +8438,7 @@ public class Character extends AbstractCharacterObject { } private void saveCharacter(Connection con) throws SQLException { - SaveStats stats = getSaveStats(); + CharacterStats stats = getCharacterStats(); try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, exp = ?, gachaexp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, meso = ?, hpMpUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, mountlevel = ?, mountexp = ?, mounttiredness= ?, equipslots = ?, useslots = ?, setupslots = ?, etcslots = ?, monsterbookcover = ?, vanquisherStage = ?, dojoPoints = ?, lastDojoStage = ?, finishedDojoTutorial = ?, vanquisherKills = ?, matchcardwins = ?, matchcardlosses = ?, matchcardties = ?, omokwins = ?, omoklosses = ?, omokties = ?, dataString = ?, fquest = ?, jailexpire = ?, partnerId = ?, marriageItemId = ?, lastExpGainTime = ?, ariantPoints = ?, partySearch = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) { ps.setInt(1, stats.level()); ps.setInt(2, stats.fame()); @@ -8504,8 +8504,8 @@ public class Character extends AbstractCharacterObject { } } - private SaveStats getSaveStats() { - SaveStats.SaveStatsBuilder builder = SaveStats.builder() + public CharacterStats getCharacterStats() { + CharacterStats.CharacterStatsBuilder builder = CharacterStats.builder() .id(id) .level(level) .fame(fame) diff --git a/src/main/java/client/SaveStats.java b/src/main/java/client/CharacterStats.java similarity index 97% rename from src/main/java/client/SaveStats.java rename to src/main/java/client/CharacterStats.java index 9bae227511..3d004d4342 100644 --- a/src/main/java/client/SaveStats.java +++ b/src/main/java/client/CharacterStats.java @@ -3,7 +3,7 @@ package client; import lombok.Builder; @Builder -public record SaveStats( +public record CharacterStats( int id, int level, int fame, diff --git a/src/main/java/database/character/CharacterSaver.java b/src/main/java/database/character/CharacterSaver.java index 95756ad30f..33bd9b6bd5 100644 --- a/src/main/java/database/character/CharacterSaver.java +++ b/src/main/java/database/character/CharacterSaver.java @@ -1,19 +1,26 @@ package database.character; import client.Character; +import database.PgDatabaseConnection; import database.monsterbook.MonsterCardRepository; +import org.jdbi.v3.core.Handle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tools.DatabaseConnection; import java.sql.Connection; import java.sql.SQLException; +import java.time.Duration; +import java.time.Instant; public class CharacterSaver { private static final Logger log = LoggerFactory.getLogger(CharacterSaver.class); + private final PgDatabaseConnection pgConnection; private final MonsterCardRepository monsterCardRepository; - public CharacterSaver(MonsterCardRepository monsterCardRepository) { + public CharacterSaver(PgDatabaseConnection pgConnection, + MonsterCardRepository monsterCardRepository) { + this.pgConnection = pgConnection; this.monsterCardRepository = monsterCardRepository; } @@ -23,6 +30,12 @@ public class CharacterSaver { } log.debug("Saving chr {}", chr.getName()); + saveToMysql(chr); + saveToPostgres(chr); + } + + private void saveToMysql(Character chr) { + Instant before = Instant.now(); try (Connection con = DatabaseConnection.getConnection()) { con.setAutoCommit(false); con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); @@ -38,11 +51,24 @@ public class CharacterSaver { } } catch (SQLException e) { log.error("Error saving chr {}, level: {}, job: {}", chr.getName(), chr.getLevel(), chr.getJob().getId(), e); - return; + } + Duration saveDuration = Duration.between(before, Instant.now()); + log.debug("Saved {} to MySQL in {} ms", chr.getName(), saveDuration.toMillis()); + } + + private void saveToPostgres(Character chr) { + Instant before = Instant.now(); + + try (Handle handle = pgConnection.getHandle()) { + handle.useTransaction(h -> doPostgresSave(h, chr)); } - // Saving monster cards to both MySQL and Postgres for now - monsterCardRepository.save(chr.getId(), chr.getMonsterBook().getCards()); + Duration saveDuration = Duration.between(before, Instant.now()); + log.debug("Saved {} to Postgres in {} ms", chr.getName(), saveDuration.toMillis()); + } + + private void doPostgresSave(Handle handle, Character chr) { + monsterCardRepository.save(handle, chr.getId(), chr.getMonsterBook().getCards()); } } diff --git a/src/main/java/database/monsterbook/MonsterCardRepository.java b/src/main/java/database/monsterbook/MonsterCardRepository.java index 597c1c9ad3..148b983fc1 100644 --- a/src/main/java/database/monsterbook/MonsterCardRepository.java +++ b/src/main/java/database/monsterbook/MonsterCardRepository.java @@ -29,8 +29,8 @@ public class MonsterCardRepository { } } - public void save(int chrId, List cards) { - try (Handle handle = connection.getHandle()) { + public void save(Handle handle, int chrId, List cards) { + try { PreparedBatch batch = handle.prepareBatch(""" INSERT INTO monster_card (chr_id, card_id, level) VALUES (?, ?, ?) diff --git a/src/main/java/net/server/Server.java b/src/main/java/net/server/Server.java index 3f3b6707b7..cb6d409a69 100644 --- a/src/main/java/net/server/Server.java +++ b/src/main/java/net/server/Server.java @@ -1004,7 +1004,7 @@ public class Server { private ChannelDependencies registerChannelDependencies(PgDatabaseConnection connection) { MonsterCardRepository monsterCardRepository = new MonsterCardRepository(connection); CharacterLoader characterLoader = new CharacterLoader(monsterCardRepository); - CharacterSaver characterSaver = new CharacterSaver(monsterCardRepository); + CharacterSaver characterSaver = new CharacterSaver(connection, monsterCardRepository); TransitionService transitionService = new TransitionService(characterSaver); BanService banService = new BanService(transitionService); NoteService noteService = new NoteService(new NoteDao(connection));