fix #10 by only using native queries in change processors

This commit is contained in:
f43nd1r 2018-06-24 20:48:57 +02:00
parent 21bf05a8ba
commit 36da250ceb
5 changed files with 59 additions and 37 deletions

View file

@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.faendir.acra.liquibase; package com.faendir.acra.liquibase;
import liquibase.changelog.ChangeSet; import liquibase.changelog.ChangeSet;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.Query;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
/** /**
* @author lukas * @author lukas
@ -29,6 +34,16 @@ public abstract class LiquibaseChangePostProcessor {
this.changeId = changeId; this.changeId = changeId;
} }
@Transactional
protected void iterate(Supplier<Query> supplier, Consumer<Object> consumer) {
int offset = 0;
List<?> list;
while (!(list = supplier.get().setFirstResult(offset).setMaxResults(64).getResultList()).isEmpty()) {
list.forEach(consumer::accept);
offset += list.size();
}
}
void handle(ChangeSet changeSet) { void handle(ChangeSet changeSet) {
if (changeId.equals(changeSet.getId())) { if (changeId.equals(changeSet.getId())) {
afterChange(); afterChange();

View file

@ -13,34 +13,45 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.faendir.acra.liquibase.change; package com.faendir.acra.liquibase.change;
import com.faendir.acra.liquibase.LiquibaseChangePostProcessor; import com.faendir.acra.liquibase.LiquibaseChangePostProcessor;
import com.faendir.acra.model.Report; import org.acra.ReportField;
import com.faendir.acra.service.DataService; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
/** /**
* @author lukas * @author lukas
* @since 01.06.18 * @since 01.06.18
*/ */
@Component @Component
public class ReportColumnsChange extends LiquibaseChangePostProcessor { public class ReportColumnsChange extends LiquibaseChangePostProcessor {
@NonNull private final EntityManager entityManager;
@NonNull private final DataService dataService;
@Autowired @Autowired
public ReportColumnsChange(@NonNull @Lazy DataService dataService) { public ReportColumnsChange(@NonNull @Lazy EntityManager entityManager) {
super("2018-06-01-add-report-columns"); super("2018-06-01-add-report-columns");
this.dataService = dataService; this.entityManager = entityManager;
} }
@Override @Override
protected void afterChange() { protected void afterChange() {
dataService.transformAllReports(Report::initFields); iterate(() -> entityManager.createNativeQuery("SELECT content FROM report"), o -> {
String content = (String) o;
JSONObject json = new JSONObject(content);
String id = json.getString(ReportField.REPORT_ID.name());
String brand = json.optString(ReportField.BRAND.name());
String installationId = json.optString(ReportField.INSTALLATION_ID.name());
entityManager.createNativeQuery("UPDATE report SET brand = ?1, installation_id = ?2 WHERE id = ?3")
.setParameter(1, brand)
.setParameter(2, installationId)
.setParameter(3, id)
.executeUpdate();
});
} }
} }

View file

@ -16,8 +16,6 @@
package com.faendir.acra.liquibase.change; package com.faendir.acra.liquibase.change;
import com.faendir.acra.liquibase.LiquibaseChangePostProcessor; import com.faendir.acra.liquibase.LiquibaseChangePostProcessor;
import com.faendir.acra.model.Stacktrace;
import com.faendir.acra.service.DataService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
@ -31,30 +29,42 @@ import javax.persistence.EntityManager;
*/ */
@Component @Component
public class StacktraceChange extends LiquibaseChangePostProcessor { public class StacktraceChange extends LiquibaseChangePostProcessor {
@NonNull private final DataService dataService;
@NonNull private final EntityManager entityManager; @NonNull private final EntityManager entityManager;
@Autowired @Autowired
public StacktraceChange(@NonNull @Lazy DataService dataService, @NonNull @Lazy EntityManager entityManager) { public StacktraceChange(@NonNull @Lazy EntityManager entityManager) {
super("2018-06-04-add-stacktrace-table"); super("2018-06-04-add-stacktrace-table");
this.dataService = dataService;
this.entityManager = entityManager; this.entityManager = entityManager;
} }
@Override @Override
protected void afterChange() { protected void afterChange() {
dataService.transformAllReports(report -> { iterate(() -> entityManager.createNativeQuery(
Object[] result = (Object[]) entityManager.createNativeQuery( "SELECT stacktrace, version_code, version_name, bug_id, id FROM report"), o -> {
"SELECT report.stacktrace, report.version_code, report.version_name, report.bug_id FROM report where report.id = ?1") Object[] result = (Object[]) o;
.setParameter(1, report.getId())
.getSingleResult();
String trace = (String) result[0]; String trace = (String) result[0];
int versionCode = (int) result[1]; int versionCode = (int) result[1];
String versionName = (String) result[2]; String versionName = (String) result[2];
int bugId = (int) result[3]; int bugId = (int) result[3];
Stacktrace stacktrace = dataService.findStacktrace(trace) int reportId = (int) result[4];
.orElseGet(() -> new Stacktrace(dataService.findBug(bugId).orElseThrow(IllegalStateException::new), trace, versionCode, versionName)); Long stacktraceId = (Long) entityManager.createNativeQuery("SELECT id FROM stacktrace WHERE stacktrace = ?1 AND version_code = ?2")
report.setStacktrace(stacktrace); .setParameter(1, trace)
.setParameter(2, versionCode)
.setMaxResults(1)
.getSingleResult();
if(stacktraceId == null) {
entityManager.createNativeQuery("INSERT INTO stacktrace (bug_id, stacktrace, version_code, version_name) VALUES(?1, ?2, ?3, ?4)")
.setParameter(1, bugId)
.setParameter(2, trace)
.setParameter(3, versionCode)
.setParameter(4, versionName)
.executeUpdate();
stacktraceId = (Long) entityManager.createNativeQuery("SELECT id FROM stacktrace ORDER BY id DESC").setMaxResults(1).getSingleResult();
}
entityManager.createNativeQuery("UPDATE report SET stacktrace_id = ?1 WHERE id = ?2")
.setParameter(1, stacktraceId)
.setParameter(2, reportId)
.executeUpdate();
}); });
} }
} }

View file

@ -62,10 +62,6 @@ public class Report {
public Report(@NonNull Stacktrace stacktrace, @NonNull String content) { public Report(@NonNull Stacktrace stacktrace, @NonNull String content) {
this.stacktrace = stacktrace; this.stacktrace = stacktrace;
this.content = content; this.content = content;
initFields();
}
public final void initFields() {
this.id = getJsonObject().getString(ReportField.REPORT_ID.name()); this.id = getJsonObject().getString(ReportField.REPORT_ID.name());
this.date = Utils.getDateFromString(getJsonObject().optString(ReportField.USER_CRASH_DATE.name())); this.date = Utils.getDateFromString(getJsonObject().optString(ReportField.USER_CRASH_DATE.name()));
this.userEmail = getJsonObject().optString(ReportField.USER_EMAIL.name()); this.userEmail = getJsonObject().optString(ReportField.USER_EMAIL.name());

View file

@ -56,6 +56,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
@ -338,17 +339,6 @@ public class DataService implements Serializable {
return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).select(select).distinct().orderBy(order.asc()).fetch(); return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).select(select).distinct().orderBy(order.asc()).fetch();
} }
@Transactional
public void transformAllReports(Consumer<Report> consumer) {
CloseableIterator<Report> iterator = new JPAQuery<>(entityManager).from(report).select(report).iterate();
while (iterator.hasNext()) {
Report report = iterator.next();
consumer.accept(report);
store(report);
}
iterator.close();
}
@NonNull @NonNull
public List<Stacktrace> getStacktraces(@NonNull Bug bug) { public List<Stacktrace> getStacktraces(@NonNull Bug bug) {
return new JPAQuery<>(entityManager).from(stacktrace1).where(stacktrace1.bug.eq(bug)).select(stacktrace1).fetch(); return new JPAQuery<>(entityManager).from(stacktrace1).where(stacktrace1.bug.eq(bug)).select(stacktrace1).fetch();