import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.sql.*;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
/**
* Update a table by iterating a sub-set of rows. For each row a SQL UPDATE request
public class MassUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(MassUpdater.class);
- private static final int DEFAULT_GROUP_SIZE = 1000;
+ private static final int DEFAULT_GROUP_SIZE = 250;
private final Database db;
private final int groupSize;
boolean update(Connection writeConnection) throws SQLException;
}
+ public List<Long> selectLong(String sql) {
+ Connection readConnection = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ readConnection = db.getDataSource().getConnection();
+ readConnection.setAutoCommit(false);
+
+ stmt = initStatement(sql, readConnection);
+ rs = stmt.executeQuery();
+ List<Long> rows = new ArrayList<Long>();
+ while (rs.next()) {
+ if (!rs.wasNull()) {
+ rows.add(rs.getLong(1));
+ }
+ }
+ return rows;
+ } catch (Exception e) {
+ throw processError(e);
+ } finally {
+ DbUtils.closeQuietly(readConnection, stmt, rs);
+ }
+ }
+
public <S> void execute(InputLoader<S> inputLoader, InputConverter<S> converter) {
execute(inputLoader, converter, null);
}
public <S> void execute(InputLoader<S> inputLoader, InputConverter<S> converter, @Nullable PeriodicUpdater periodicUpdater) {
long count = 0;
Connection readConnection = null, writeConnection = null;
- Statement stmt = null;
+ PreparedStatement stmt = null;
ResultSet rs = null;
PreparedStatement writeStatement = null;
try {
readConnection = db.getDataSource().getConnection();
readConnection.setAutoCommit(false);
+ if (readConnection.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)) {
+ readConnection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
+ }
- stmt = initStatement(readConnection);
- rs = stmt.executeQuery(convertSelectSql(inputLoader.selectSql(), db));
+ stmt = initStatement(convertSelectSql(inputLoader.selectSql(), db), readConnection);
+ rs = stmt.executeQuery();
int cursor = 0;
while (rs.next()) {
continue;
}
- if (writeConnection==null) {
+ if (writeConnection == null) {
// do not open the write connection too early
// else if the select on read connection is long, then mysql
// write connection fails with communication failure error because
}
if (cursor == groupSize) {
- commit(writeConnection, writeStatement, periodicUpdater);
+ commit(writeStatement, periodicUpdater);
cursor = 0;
}
}
if (cursor > 0) {
- commit(writeConnection, writeStatement, periodicUpdater);
+ commit(writeStatement, periodicUpdater);
}
} catch (SQLException e) {
}
}
- private Statement initStatement(Connection readConnection) throws SQLException {
- Statement stmt = readConnection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+ private PreparedStatement initStatement(String sql, Connection readConnection) throws SQLException {
+ PreparedStatement stmt = readConnection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
if (db.getDialect().getId().equals(MySql.ID)) {
stmt.setFetchSize(Integer.MIN_VALUE);
} else {
- stmt.setFetchSize(groupSize);
+ stmt.setFetchSize(1000);
}
return stmt;
}
- private void commit(Connection writeConnection, PreparedStatement writeStatement, @Nullable PeriodicUpdater periodicUpdater) throws SQLException {
+ private void commit(PreparedStatement writeStatement, @Nullable PeriodicUpdater periodicUpdater) throws SQLException {
writeStatement.executeBatch();
if (periodicUpdater != null) {
- periodicUpdater.update(writeConnection);
+ periodicUpdater.update(writeStatement.getConnection());
}
- writeConnection.commit();
+ writeStatement.getConnection().commit();
}
private static RuntimeException processError(Exception e) {
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
+import java.util.List;
/**
* Used in the Active Record Migration 515
+ *
* @since 4.3
*/
public class TechnicalDebtMeasuresMigration implements DatabaseMigration {
- private static final String SELECT_SQL = "SELECT pm.id, pm.value " +
- ", pm.variation_value_1 , pm.variation_value_2, pm.variation_value_3 " +
- ", pm.variation_value_4 , pm.variation_value_5 " +
- " FROM project_measures pm INNER JOIN metrics m on m.id=pm.metric_id " +
- " WHERE (m.name='sqale_index' or m.name='new_technical_debt' " +
- // SQALE measures
- " or m.name='sqale_effort_to_grade_a' or m.name='sqale_effort_to_grade_b' or m.name='sqale_effort_to_grade_c' or m.name='sqale_effort_to_grade_d' " +
- " or m.name='blocker_remediation_cost' or m.name='critical_remediation_cost' or m.name='major_remediation_cost' or m.name='minor_remediation_cost' " +
- " or m.name='info_remediation_cost' " +
- ")";
-
private static final String UPDATE_SQL = "UPDATE project_measures SET value=?," +
"variation_value_1=?,variation_value_2=?,variation_value_3=?,variation_value_4=?,variation_value_5=? WHERE id=?";
public void execute() {
workDurationConvertor.init();
- new MassUpdater(db).execute(
- new MassUpdater.InputLoader<Row>() {
- @Override
- public String selectSql() {
- return SELECT_SQL;
- }
-
- @Override
- public Row load(ResultSet rs) throws SQLException {
- Row row = new Row();
- row.id = SqlUtil.getLong(rs, 1);
- row.value = SqlUtil.getDouble(rs, 2);
- row.var1 = SqlUtil.getDouble(rs, 3);
- row.var2 = SqlUtil.getDouble(rs, 4);
- row.var3 = SqlUtil.getDouble(rs, 5);
- row.var4 = SqlUtil.getDouble(rs, 6);
- row.var5 = SqlUtil.getDouble(rs, 7);
- return row;
+ MassUpdater massUpdater = new MassUpdater(db);
+
+ final List<Long> metricIds = massUpdater.selectLong("select id from metrics " +
+ "where name='sqale_index' or name='new_technical_debt' " +
+ "or name='sqale_effort_to_grade_a' or name='sqale_effort_to_grade_b' or name='sqale_effort_to_grade_c' " +
+ "or name='sqale_effort_to_grade_d' or name='blocker_remediation_cost' or name='critical_remediation_cost' " +
+ "or name='major_remediation_cost' or name='minor_remediation_cost' or name='info_remediation_cost'");
+
+ if (!metricIds.isEmpty()) {
+ massUpdater.execute(
+ new MassUpdater.InputLoader<Row>() {
+ @Override
+ public String selectSql() {
+ StringBuilder sql = new StringBuilder("SELECT pm.id, pm.value " +
+ ", pm.variation_value_1 , pm.variation_value_2, pm.variation_value_3 " +
+ ", pm.variation_value_4 , pm.variation_value_5 " +
+ " FROM project_measures pm " +
+ " WHERE pm.metric_id IN (");
+ for (int i = 0; i < metricIds.size(); i++) {
+ sql.append(Long.toString(metricIds.get(i)));
+ if (i < metricIds.size() - 1) {
+ sql.append(",");
+ }
+ }
+ sql.append(")");
+ return sql.toString();
+ }
+
+ @Override
+ public Row load(ResultSet rs) throws SQLException {
+ Row row = new Row();
+ row.id = SqlUtil.getLong(rs, 1);
+ row.value = SqlUtil.getDouble(rs, 2);
+ row.var1 = SqlUtil.getDouble(rs, 3);
+ row.var2 = SqlUtil.getDouble(rs, 4);
+ row.var3 = SqlUtil.getDouble(rs, 5);
+ row.var4 = SqlUtil.getDouble(rs, 6);
+ row.var5 = SqlUtil.getDouble(rs, 7);
+ return row;
+ }
+ },
+ new MassUpdater.InputConverter<Row>() {
+ @Override
+ public String updateSql() {
+ return UPDATE_SQL;
+ }
+
+ @Override
+ public boolean convert(Row row, PreparedStatement updateStatement) throws SQLException {
+ setDouble(updateStatement, 1, row.value);
+ setDouble(updateStatement, 2, row.var1);
+ setDouble(updateStatement, 3, row.var2);
+ setDouble(updateStatement, 4, row.var3);
+ setDouble(updateStatement, 5, row.var4);
+ setDouble(updateStatement, 6, row.var5);
+ updateStatement.setLong(7, row.id);
+ return true;
+ }
}
- },
- new MassUpdater.InputConverter<Row>() {
- @Override
- public String updateSql() {
- return UPDATE_SQL;
- }
-
- @Override
- public boolean convert(Row row, PreparedStatement updateStatement) throws SQLException {
- setDouble(updateStatement, 1, row.value);
- setDouble(updateStatement, 2, row.var1);
- setDouble(updateStatement, 3, row.var2);
- setDouble(updateStatement, 4, row.var3);
- setDouble(updateStatement, 5, row.var4);
- setDouble(updateStatement, 6, row.var5);
- updateStatement.setLong(7, row.id);
- return true;
- }
- }
- );
+ );
+ }
}
private void setDouble(PreparedStatement statement, int index, Double value) throws SQLException {