mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#919 - io.ebean package initial
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 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) {
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
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) {
|
||||
bindLog.append(logPlaceHolder).append(" ");
|
||||
}
|
||||
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.
|
||||
* <p>
|
||||
* GeneratedProperty values are likely going to be used for optimistic
|
||||
* concurrency checking. This includes 'counter' and 'update timestamp'
|
||||
* generation.
|
||||
* </p>
|
||||
*/
|
||||
@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.
|
||||
int[] columns = {1};
|
||||
return conn.prepareStatement(sql, 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();
|
||||
PreparedStatement stmt = batch.getStmt(sql, request);
|
||||
|
||||
if (stmt != null) {
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt = getPstmt(t, sql, genKeys);
|
||||
|
||||
BatchedPstmt bs = new BatchedPstmt(stmt, genKeys, sql);
|
||||
batch.addStmt(bs, request);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user