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.util.Str;
import io.ebeaninternal.server.persist.BatchedPstmt;
import io.ebeaninternal.server.persist.BatchedPstmtHolder;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
import io.ebeaninternal.server.transaction.TransactionManager;
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};
/**
* The originating request.
*/
protected final PersistRequestBean> persistRequest;
protected final StringBuilder bindLog;
protected final SpiTransaction transaction;
protected final boolean emptyStringToNull;
protected final boolean logLevelSql;
protected final long now;
/**
* The PreparedStatement used for the dml.
*/
protected DataBind dataBind;
protected BatchedPstmt batchedPstmt;
protected String sql;
/**
* The generated value for the @Version property. Must be set after where clause is bound.
*/
protected Object versionValue;
protected DmlHandler(PersistRequestBean> persistRequest, boolean emptyStringToNull) {
this.now = System.currentTimeMillis();
this.persistRequest = persistRequest;
this.emptyStringToNull = emptyStringToNull;
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.
*/
protected 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;
/**
* Check the rowCount.
*/
protected 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);
}
}
/**
* Return the bind log.
*/
@Override
public String getBindLog() {
return bindLog == null ? "" : bindLog.toString();
}
/**
* 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.
*/
protected void logSql(String sql) {
if (logLevelSql) {
sql = Str.add(sql, "; --bind(", bindLog.toString(), ")");
transaction.logSql(sql);
}
}
/**
* 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.substring(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);
}
/**
* Register a generated value on a update. This can not be set to the bean
* until after the where clause has been bound for concurrency checking.
*
* GeneratedProperty values are likely going to be used for optimistic
* concurrency checking. This includes 'counter' and 'update timestamp'
* generation.
*
*/
@Override
public void registerGeneratedVersion(Object versionValue) {
this.versionValue = versionValue;
}
/**
* Set any update generated values to the bean. Must be called after where
* clause has been bound.
*/
public void setUpdateGenValues() {
if (versionValue != null) {
persistRequest.setVersionValue(versionValue);
}
}
/**
* Check with useGeneratedKeys to get appropriate PreparedStatement.
*/
protected 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.
*/
protected PreparedStatement getPstmt(SpiTransaction t, String sql, PersistRequestBean> request, boolean genKeys) throws SQLException {
BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
batchedPstmt = batch.getBatchedPstmt(sql, request);
if (batchedPstmt != null) {
return batchedPstmt.getStatement();
}
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