[英]How can I speed up the execution of a large amount of SQL updates in Java (JDBC)
我正在尝试为大型IRC频道(Twitch频道)编写系统代码
我要尝试做的一件事是记录每个用户的身份,并为他们提供聊天记录。 出于所有目的和目的,聊天只是一个大型IRC频道。 我正在从twitch API的大列表中检索用户,我将所有用户名放在一个大数组中,并使用while循环运行以下计时器:
timer = new Timer(900000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
updating = true;
try {
Arraynumber = 0;
TwitchBot.getDate();
arrayused = false;
System.out.println("trying to save users if theres enough stuff");
while(Arraynumber < TwitchBot.words.length){
TwitchBot.CheckUpdateUserSQL(TwitchBot.words[Arraynumber]);
Arraynumber++;
System.out.println("updating database");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
如您所见,这是一个简单的计时器,它从String []中选取名称,然后分别通过脚本运行每个名称。
updateuser看起来像这样:
public static void CheckUpdateUserSQL(String sqluser) throws ClassNotFoundException{
selectSQL(sqluser);
if (id == "thisuserdoesntexistforsure"){
InsertSQL(sqluser);
}
else{
int progress = CurrentTime - lastlogin;
int totalprogress = progress + totaltime;
if(progress < 60 && progress > 0){
c15 = null;
Statement stmt = null;
if(isonline == 1) {
coins = progress / 4;
}
else{
coins = progress / 5;
}
int coinsincrease = (int) Math.ceil(coins);
int coinstotal = coinsamount + coinsincrease;
Class.forName("org.sqlite.JDBC");
try {
c15 = DriverManager.getConnection("jdbc:sqlite:users.db");
c15.setAutoCommit(false);
stmt = c15.createStatement();
String sql = "UPDATE USERS set TOTALTIME = " + totalprogress + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql);
c15.commit();
String sql2 = "UPDATE USERS set LASTLOGIN = " + CurrentTime + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql2);
c15.commit();
String sql3 = "UPDATE USERS set TOTALCOIN = " + coinstotal + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql3);
c15.commit();
String sql4 = "UPDATE USERS set ISONLINE = 0 where NAME='" + sqluser + "';";
stmt.executeUpdate(sql4);
c15.commit();
stmt.close();
c15.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
Connection c = null;
Statement stmt = null;
try {
c = DriverManager.getConnection("jdbc:sqlite:users.db");
c.setAutoCommit(false);
stmt = c.createStatement();
String sql2 = "UPDATE USERS set LASTLOGIN = " + CurrentTime + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql2);
c.commit();
stmt.close();
c15.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
此代码检查用户是否存在。 (使用select方法,它很简洁,它只搜索用户名并返回ID,如果没有返回,则为'thisuderdoesntexistforsure')
如果用户存在,它将运行代码以计算其在线时间以及自上次访问以来的在线时间和积分增加。 然后更新代码。 如果它们不在线或时间以某种方式返回负值(或值太高),它将仅更新时间戳,而跳过其余的更新。 这确保了一天离开的用户第二天登录五分钟时不会仅获得1.400分钟的在线时间。
无论如何。 我的问题是; 如何修剪? 我遇到了一个问题,该问题需要6分钟才能更新整个用户列表。 在线拥有2000个用户并不罕见,并且需要2,000个循环来更新他们的while循环。 程序更新的频率更高,然后没有更新。 我试图减少代码以使其尽可能简洁,但是我不知道从哪里开始加快速度。
抱歉,如果我要成为moronic的人,那么我对SQL来说还比较陌生,这是我迄今为止在JAVA中所做的最大项目。
您可以使用批处理来执行更新,但是在给定的代码中,更简单的优化方法是使用一个update调用(而不是4个)来更新值。 另外,您可以使用PreparedStatement
并使用try-with-resources
close 。 就像是,
public static void CheckUpdateUserSQL(String sqluser) throws ClassNotFoundException {
selectSQL(sqluser);
if (id.equals("thisuserdoesntexistforsure")) {
InsertSQL(sqluser);
} else {
String sql = "UPDATE USERS set TOTALTIME = ?, LASTLOGIN = ?, "
+ "TOTALCOIN = ?, ISONLINE = 0 where NAME = ?";
String sql2 = "UPDATE USERS set LASTLOGIN = ? where NAME=?";
int progress = CurrentTime - lastlogin;
int totalprogress = progress + totaltime;
if (progress < 60 && progress > 0) {
if (isonline == 1) {
coins = progress / 4;
} else {
coins = progress / 5;
}
int coinsincrease = (int) Math.ceil(coins);
int coinstotal = coinsamount + coinsincrease;
Class.forName("org.sqlite.JDBC");
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:users.db");
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, totalprogress);
ps.setInt(2, CurrentTime);
ps.setInt(3, coinstotal);
ps.setString(4, sqluser);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
} else {
Class.forName("org.sqlite.JDBC");
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:users.db");
PreparedStatement ps = conn.prepareStatement(sql2)) {
ps.setInt(1, CurrentTime);
ps.setString(2, sqluser);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
您需要的是batchupdate。 在互联网上可以找到一些很好的教程。
示例如下:
stm = db.prepareStatement("INSERT INTO ITEM (ID, TYPE, TITEL, UITGELEEND) VALUES (?, ?, ?, ?)");
db.setAutoCommit(false);
for (int n = 0; n < ItemLijst.getItems().size(); n++) {
Item huidigItem = ItemLijst.getItemObvIdx(n);
stm.setString(1, huidigItem.getID().toString());
stm.setString(2, huidigItem.getType().toString());
stm.setString(3, huidigItem.getTitel());
stm.setString(4,String.valueOf(huidigItem.isUitgeleend()));
stm.addBatch();
}
String SQL = "UPDATE Employees SET age = 35 " +
"WHERE id = 100";
//在批处理中添加上述SQL语句。 stm.addBatch(SQL); stm.executeBatch(); db.commit();
也请尝试避免连接字符串,而应使用'?',否则它将受到sql注入攻击 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.