Я работаю в игровом интернет-кафе, и у нас здесь есть система (smartlaunch), которая отслеживает игровые лицензии. Я написал программу, которая взаимодействует с этой системой (на самом деле, с ее базой данных MySQL). Программа предназначена для запуска на клиентском ПК и (1) запрашивает базу данных, чтобы выбрать неиспользуемую лицензию из доступного пула, а затем (2) помечает эту лицензию как используемую на клиентском ПК.
Проблема в том, что у меня ошибка параллелизма. Программа предназначена для одновременного запуска на нескольких машинах, и когда это происходит, некоторые машины часто пытаются получить одну и ту же лицензию. Я думаю, что это потому, что шаги (1) и (2) не синхронизированы, то есть одна программа определяет, что лицензия # 5 доступна и выбирает ее, но прежде чем она может пометить # 5 как другую копию программы на другом ПК пытается получить ту же лицензию.
Я пытался решить эту проблему, используя транзакции и блокировку таблиц, но, похоже, это не имеет значения - правильно ли я это делаю? Вот следующий код:
public LicenseKey Acquire() throws SmartLaunchException, SQLException {
Connection conn = SmartLaunchDB.getConnection();
int PCID = SmartLaunchDB.getCurrentPCID();
conn.createStatement().execute("LOCK TABLE `licensekeys` WRITE");
String sql = "SELECT * FROM `licensekeys` WHERE `InUseByPC` = 0 AND LicenseSetupID = ? ORDER BY `ID` DESC LIMIT 1";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setInt(1, this.id);
ResultSet results = statement.executeQuery();
if (results.next()) {
int licenseID = results.getInt("ID");
sql = "UPDATE `licensekeys` SET `InUseByPC` = ? WHERE `ID` = ?";
statement = conn.prepareStatement(sql);
statement.setInt(1, PCID);
statement.setInt(2, licenseID);
statement.executeUpdate();
statement.close();
conn.commit();
conn.createStatement().execute("UNLOCK TABLES");
return new LicenseKey(results.getInt("ID"), this, results.getString("LicenseKey"), results.getInt("LicenseKeyType"));
} else {
throw new SmartLaunchException("All licenses of type " + this.name + "are in use");
}
}