io.ebeaninternal.server.persist.dml.DmlHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ebean Show documentation
Show all versions of ebean Show documentation
composite of common runtime dependencies for all platforms
package io.ebeaninternal.server.persist.dml;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.lib.Str;
import io.ebeaninternal.server.persist.BatchedPstmt;
import io.ebeaninternal.server.persist.BatchedPstmtHolder;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
import io.ebeaninternal.server.type.DataBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.OptimisticLockException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* Base class for Handler implementations.
*/
public abstract class DmlHandler implements PersistHandler, BindableRequest {
private static final Logger logger = LoggerFactory.getLogger(DmlHandler.class);
private static final int[] GENERATED_KEY_COLUMNS = new int[]{1};
private static final int BATCHED_FIRST = 1;
private static final int BATCHED = 2;
/**
* The originating request.
*/
final PersistRequestBean> persistRequest;
private final StringBuilder bindLog;
final SpiTransaction transaction;
private final boolean logLevelSql;
private final long now;
/**
* The PreparedStatement used for the dml.
*/
DataBind dataBind;
BatchedPstmt batchedPstmt;
String sql;
private short batchedStatus;
DmlHandler(PersistRequestBean> persistRequest) {
this.now = System.currentTimeMillis();
this.persistRequest = persistRequest;
this.transaction = persistRequest.getTransaction();
this.logLevelSql = transaction.isLogSql();
if (logLevelSql) {
this.bindLog = new StringBuilder(50);
} else {
this.bindLog = null;
}
}
@Override
public long now() {
return now;
}
@Override
public PersistRequestBean> getPersistRequest() {
return persistRequest;
}
/**
* Bind to the statement returning the DataBind.
*/
DataBind bind(PreparedStatement stmt) {
return new DataBind(persistRequest.getDataTimeZone(), stmt, transaction.getInternalConnection());
}
/**
* Get the sql and bind the statement.
*/
@Override
public abstract void bind() throws SQLException;
/**
* Execute now for non-batch execution.
*/
@Override
public abstract int execute() throws SQLException;
@Override
public final int executeNoBatch() throws SQLException {
final long startNanos = System.nanoTime();
try {
return execute();
} finally {
persistRequest.addTimingNoBatch(startNanos);
}
}
/**
* Check the rowCount.
*/
void checkRowCount(int rowCount) throws OptimisticLockException {
try {
persistRequest.checkRowCount(rowCount);
persistRequest.postExecute();
} catch (OptimisticLockException e) {
// add the SQL and bind values to error message
String m = e.getMessage() + " sql[" + sql + "] bind[" + bindLog + "]";
persistRequest.getTransaction().logSummary("OptimisticLockException:" + m);
throw new OptimisticLockException(m, null, e.getEntity());
}
}
/**
* Add this for batch execution.
*/
@Override
public void addBatch() throws SQLException {
dataBind.getPstmt().addBatch();
}
/**
* Close the underlying statement.
*/
@Override
public void close() {
try {
if (dataBind != null) {
dataBind.close();
}
} catch (SQLException ex) {
logger.error(null, ex);
}
}
/**
* Set the Id value that was bound. This value is used for logging summary
* level information.
*/
@Override
public void setIdValue(Object idValue) {
persistRequest.setBoundId(idValue);
}
/**
* Log the sql to the transaction log.
*/
void logSql(String sql) {
if (logLevelSql) {
switch (batchedStatus) {
case BATCHED_FIRST: {
transaction.logSql(sql);
transaction.logSql(Str.add(" -- bind(", bindLog.toString(), ")"));
return;
}
case BATCHED: {
transaction.logSql(Str.add(" -- bind(", bindLog.toString(), ")"));
return;
}
default: {
transaction.logSql(Str.add(sql, "; -- bind(", bindLog.toString(), ")"));
}
}
}
}
/**
* Bind a raw value. Used to bind the discriminator column.
*/
@Override
public void bind(Object value, int sqlType) throws SQLException {
if (logLevelSql) {
if (bindLog.length() > 0) {
bindLog.append(",");
}
if (value == null) {
bindLog.append("null");
} else {
String sval = value.toString();
if (sval.length() > 50) {
bindLog.append(sval, 0, 47).append("...");
} else {
bindLog.append(sval);
}
}
}
dataBind.setObject(value, sqlType);
}
@Override
public void bindNoLog(Object value, int sqlType, String logPlaceHolder) throws SQLException {
if (logLevelSql) {
if (bindLog.length() > 0) {
bindLog.append(",");
}
bindLog.append(logPlaceHolder);
}
dataBind.setObject(value, sqlType);
}
/**
* Bind the value to the preparedStatement.
*/
@Override
public void bind(Object value, BeanProperty prop) throws SQLException {
bindInternal(logLevelSql, value, prop);
}
/**
* Bind the value to the preparedStatement without logging.
*/
@Override
public void bindNoLog(Object value, BeanProperty prop) throws SQLException {
bindInternal(false, value, prop);
}
private void bindInternal(boolean log, Object value, BeanProperty prop) throws SQLException {
if (log) {
if (bindLog.length() > 0) {
bindLog.append(",");
}
if (prop.isLob()) {
bindLog.append("[LOB]");
} else {
String sv = String.valueOf(value);
if (sv.length() > 50) {
sv = sv.substring(0, 47) + "...";
}
bindLog.append(sv);
}
}
// do the actual binding to PreparedStatement
prop.bind(dataBind, value);
}
/**
* Check with useGeneratedKeys to get appropriate PreparedStatement.
*/
PreparedStatement getPstmt(SpiTransaction t, String sql, boolean genKeys) throws SQLException {
Connection conn = t.getInternalConnection();
if (genKeys) {
// the Id generated is always the first column
// Required to stop Oracle10 giving us Oracle rowId??
// Other jdbc drivers seem fine without this hint.
return conn.prepareStatement(sql, GENERATED_KEY_COLUMNS);
} else {
return conn.prepareStatement(sql);
}
}
/**
* Return a prepared statement taking into account batch requirements.
*/
PreparedStatement getPstmtBatch(SpiTransaction t, String sql, PersistRequestBean> request, boolean genKeys) throws SQLException {
BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
batchedPstmt = batch.getBatchedPstmt(sql);
if (batchedPstmt != null) {
batchedStatus = BATCHED;
return batchedPstmt.getStatement(request);
}
batchedStatus = BATCHED_FIRST;
PreparedStatement stmt = getPstmt(t, sql, genKeys);
batchedPstmt = new BatchedPstmt(stmt, genKeys, sql, t);
batch.addStmt(batchedPstmt, request);
return stmt;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy