package org.sothis.dal;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.slf4j.Logger;
import org.sothis.core.util.Cursor;
import org.sothis.core.util.ExecuteCounter;
import org.sothis.core.util.LoggerFactory;
import org.sothis.core.util.Pager;
import org.sothis.dal.query.Chain;
import org.sothis.dal.query.Cnd;
import org.sothis.dal.query.DaoCursor;
/**
* Dao的虚基类,已经通过反射得到了实际的实体类。并提供了一些常用方法。
*
* @author velna
*
* @param <E>
* @param <K>
*/
public abstract class AbstractDao<E extends Entity, K extends Serializable> implements Dao<E, K> {
/**
* 用来记录性能日志数据的ThreadLocal key。
*
* @see {@link ExecuteCounter}
*/
public final static String EXECUTE_COUNTER_KEY = "org.sothis.dal.EntityDao.EXECUTE_COUNTER_KEY";
private final Logger PERFORMANCE_LOGGER = LoggerFactory.getPerformanceLogger(this.getClass());
private final long MAX_EXECUTE_TIME = 100;
protected final Class<E> entityClass;
@SuppressWarnings("unchecked")
public AbstractDao() {
Type type = this.getClass().getGenericSuperclass();
if (null == type || !(type instanceof ParameterizedType)) {
throw new RuntimeException("no entity class defined of " + this.getClass().getName());
}
ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
Type[] ts = parameterizedType.getActualTypeArguments();
if (null == ts || ts.length == 0) {
throw new RuntimeException("no entity class defined of " + this.getClass().getName());
}
entityClass = (Class<E>) ts[0];
}
/**
* 对当前线程的数据库访问进行计数,并记录花费的时间
*
* @param operation
* 操作类型
* @param time
* 花费时间,单位:毫秒
*/
protected final void increaseExecuteCounter(String operation, long time, Object... queryParams) {
ExecuteCounter.getThreadLocalInstance(EXECUTE_COUNTER_KEY).increase(entityClass.getSimpleName(), operation, time);
if (time > MAX_EXECUTE_TIME) {
StringBuilder builder = new StringBuilder();
builder.append("\ttype:performance\ttime:").append(time);
builder.append("\tentity:").append(entityClass.getSimpleName());
builder.append("\toperation:").append(operation);
builder.append("\tquery:");
if (null != queryParams) {
builder.append('[');
for (int j = 0; j < queryParams.length; j++) {
Object param = queryParams[j];
if (null != param && param.getClass().isArray()) {
int length = Array.getLength(param);
builder.append('[');
for (int i = 0; i < length; i++) {
builder.append(Array.get(param, i));
if (i < length - 1) {
builder.append(',');
}
}
builder.append(']');
} else {
builder.append(param);
}
if (j < queryParams.length - 1) {
builder.append(',');
}
}
builder.append(']');
}
if (time < MAX_EXECUTE_TIME * 5) {
PERFORMANCE_LOGGER.warn(builder.toString());
} else {
PERFORMANCE_LOGGER.error(builder.toString());
}
}
}
@Override
public List<E> find(Cnd cnd, Pager pager) {
return find(cnd, pager, null);
}
@Override
public List<E> find(Cnd cnd) {
return find(cnd, null, null);
}
@Override
public E findOne(Cnd cnd, Chain chain) {
List<E> list = find(cnd, Pager.make(0, 1), null);
return list.size() > 0 ? list.get(0) : null;
}
@Override
public E findOne(Cnd cnd) {
return findOne(cnd, null);
}
@Override
public int count() {
return count(null);
}
@Override
public Class<E> getEntityClass() {
return entityClass;
}
@Override
public List<E> findAndCount(Cnd cnd, Pager pager, Chain chain) {
List<E> list = this.find(cnd, pager, chain);
pager.setTotalRows(this.count(cnd));
return list;
}
@Override
public List<E> findAndCount(Cnd cnd, Pager pager) {
return findAndCount(cnd, pager, null);
}
@Override
public Cursor<E> cursor(Cnd cnd, Chain chain) {
return new DaoCursor<E, K>(this, cnd, chain);
}
@Override
public List<E> insert(List<E> entityList) {
for (E e : entityList) {
insert(e);
}
return entityList;
}
}