ru.vyarus.guicey.jdbi3.unit.UnitManager Maven / Gradle / Ivy
package ru.vyarus.guicey.jdbi3.unit;
import com.google.common.base.Preconditions;
import org.jdbi.v3.core.Handle;
import org.jdbi.v3.core.Jdbi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.vyarus.guicey.jdbi3.tx.TransactionTemplate;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.inject.Singleton;
/**
* Manages JDBI {@link Handle} for current unit of work. This handle must be used by all JDBI proxies.
* Unit of work is thread-bound (all actions in one thread participate in one unit of work).
* It is not intended to be used directly (only in really rare cases when manual unit required
* without opening transaction).
*
* Raw provider may be injected to obtain current handle: {@code @Inject Provider}.
* In all other cases transaction annotation must be used to wrap code into unit of work using guice aop.
*
* @author Vyacheslav Rusakov
* @see TransactionTemplate for manual transaction definition
* @since 31.08.2018
*/
@Singleton
public class UnitManager implements Provider {
private final Logger logger = LoggerFactory.getLogger(UnitManager.class);
private final Jdbi jdbi;
private final ThreadLocal unit = new ThreadLocal<>();
@Inject
public UnitManager(final Jdbi jdbi) {
this.jdbi = jdbi;
}
@Override
public Handle get() {
Preconditions.checkState(isUnitStarted(), "Unit of work not started yet");
return unit.get();
}
/**
* @return true if unit of work started (and handle could be obtained), false otherwise
*/
public boolean isUnitStarted() {
return unit.get() != null;
}
/**
* Starts unit of work.
*
* @throws IllegalStateException if unit of work already started
*/
public void beginUnit() {
Preconditions.checkState(!isUnitStarted(), "Unit of work already started");
final Handle handle = jdbi.open();
unit.set(handle);
logger.trace("Transaction start");
}
/**
* Finish unit of work. Note: does not commit transaction, but only close context handle.
*
* @throws IllegalStateException when no opened unit of work
*/
public void endUnit() {
Preconditions.checkState(isUnitStarted(), "Stop called outside of unit of work");
final Handle handle = unit.get();
// first remove handle to avoid stale handles in any case
unit.remove();
try {
handle.close();
} catch (Exception ex) {
// not entire stacktrace to avoid confusion: it may appear here only because of connection damage
// and so there will already be logged traces indicating connection problem
logger.warn("JDBI handle close error ({})", ex.getMessage());
}
logger.trace("Transaction end");
}
}