From 54103f47adb654df1e3bc9050f5745638100eb65 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 4 Aug 2022 11:35:17 -0500 Subject: [PATCH] Changes pushed to qqq-backend-module-rdbms (solo-repo) in 0.2 support --- .../rdbms/actions/RDBMSInsertAction.java | 47 +++++- .../rdbms/actions/RDBMSTransaction.java | 141 ++++++++++++++++++ .../module/rdbms/jdbc/QueryManager.java | 22 +++ 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java index 3c32d746..b9e76476 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java @@ -28,6 +28,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; @@ -92,7 +93,20 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte List outputRecords = new ArrayList<>(); rs.setRecords(outputRecords); - try(Connection connection = getConnection(insertInput)) + Connection connection; + boolean needToCloseConnection = false; + if(insertInput.getTransaction() != null && insertInput.getTransaction() instanceof RDBMSTransaction rdbmsTransaction) + { + LOG.debug("Using connection from insertInput [" + rdbmsTransaction.getConnection() + "]"); + connection = rdbmsTransaction.getConnection(); + } + else + { + connection = getConnection(insertInput); + needToCloseConnection = true; + } + + try { for(List page : CollectionUtils.getPages(insertInput.getRecords(), QueryManager.PAGE_SIZE)) { @@ -130,6 +144,13 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte } } } + finally + { + if(needToCloseConnection) + { + connection.close(); + } + } return rs; } @@ -139,4 +160,28 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte } } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public QBackendTransaction openTransaction(InsertInput insertInput) throws QException + { + try + { + LOG.info("Opening transaction"); + Connection connection = getConnection(insertInput); + connection.setAutoCommit(false); + System.out.println("Set connection [" + connection + "] to auto-commit false"); + + return (new RDBMSTransaction(connection)); + } + catch(Exception e) + { + throw new QException("Error opening transaction: " + e.getMessage(), e); + } + } + + } diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java new file mode 100644 index 00000000..529f69ff --- /dev/null +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java @@ -0,0 +1,141 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.module.rdbms.actions; + + +import java.io.IOException; +import java.sql.Connection; +import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; +import com.kingsrook.qqq.backend.core.exceptions.QException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + +/******************************************************************************* + ** RDBMS implementation of backend transaction. + ** + ** Stores a jdbc connection, which is set to autoCommit(false). + *******************************************************************************/ +public class RDBMSTransaction extends QBackendTransaction +{ + private static final Logger LOG = LogManager.getLogger(RDBMSTransaction.class); + + private Connection connection; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public RDBMSTransaction(Connection connection) + { + this.connection = connection; + } + + + + /******************************************************************************* + ** Getter for connection + ** + *******************************************************************************/ + public Connection getConnection() + { + return connection; + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void commit() throws QException + { + try + { + RDBMSTransaction.LOG.info("Committing transaction"); + System.out.println("Calling commit on connection [" + connection + "]"); + connection.commit(); + RDBMSTransaction.LOG.info("Commit complete"); + } + catch(Exception e) + { + RDBMSTransaction.LOG.error("Error committing transaction", e); + throw new QException("Error committing transaction: " + e.getMessage(), e); + } + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public void rollback() throws QException + { + try + { + RDBMSTransaction.LOG.info("Rolling back transaction"); + connection.rollback(); + RDBMSTransaction.LOG.info("Rollback complete"); + } + catch(Exception e) + { + RDBMSTransaction.LOG.error("Error rolling back transaction", e); + throw new QException("Error rolling back transaction: " + e.getMessage(), e); + } + } + + + + /******************************************************************************* + * Closes this stream and releases any system resources associated + * with it. If the stream is already closed then invoking this + * method has no effect. + * + *

As noted in {@link AutoCloseable#close()}, cases where the + * close may fail require careful attention. It is strongly advised + * to relinquish the underlying resources and to internally + * mark the {@code Closeable} as closed, prior to throwing + * the {@code IOException}. + * + * @throws IOException + * if an I/O error occurs + *******************************************************************************/ + @Override + public void close() + { + try + { + if(connection.isClosed()) + { + return; + } + + connection.close(); + } + catch(Exception e) + { + LOG.error("Error closing connection - possible jdbc connection leak", e); + } + } +} diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/QueryManager.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/QueryManager.java index fbd634e5..47e25f6f 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/QueryManager.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/QueryManager.java @@ -685,6 +685,11 @@ public class QueryManager bindParam(statement, index, l.intValue()); return (1); } + else if(value instanceof Double d) + { + bindParam(statement, index, d.doubleValue()); + return (1); + } else if(value instanceof String s) { bindParam(statement, index, s); @@ -851,6 +856,23 @@ public class QueryManager + /******************************************************************************* + * + *******************************************************************************/ + public static void bindParam(PreparedStatement statement, int index, Double value) throws SQLException + { + if(value == null) + { + statement.setNull(index, Types.DOUBLE); + } + else + { + statement.setDouble(index, value); + } + } + + + /******************************************************************************* * *******************************************************************************/