package com.cashbus.mybatis;
import com.cashbus.mybatis.exception.ObjectOptimisticLockingFailureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created zhoushengsheng on 2016/5/8.
*/
@Slf4j
public abstract class GenericDao implements IGenericDao {
protected Map<String, Class> mapperMap;
abstract protected SqlSession getSession();
public <T> T getMapper(Class<T> modelClass) {
return getSession().getMapper(modelClass);
}
protected <T extends GenericMapper> Class<T> getMapperClass(Class modelClass) {
try {
if (mapperMap == null && getInterface() != null && getBasePackage() != null) {
MapperClassPathScanningProvider mapperClassPathScanningProvider = new MapperClassPathScanningProvider();
mapperMap = mapperClassPathScanningProvider.findMapper(getBasePackage(), getInterface());
}
if (mapperMap != null && mapperMap.containsKey(modelClass.getName())) {
return mapperMap.get(modelClass.getName());
}
Class mapperClass = Class.forName(getMapperFullClassName(modelClass));
return mapperClass;
} catch (Exception e) {
return null;
}
}
protected <T extends GenericMapper> Class<T> getFirstMapperClass() {
try {
if (mapperMap == null && getInterface() != null && getBasePackage() != null) {
MapperClassPathScanningProvider mapperClassPathScanningProvider = new MapperClassPathScanningProvider();
mapperMap = mapperClassPathScanningProvider.findMapper(getBasePackage(), getInterface());
}
return (Class<T>) mapperMap.values().toArray()[0];
} catch (Exception e) {
return null;
}
}
protected GenericMapper getModelMapper(Class modelClass) {
return getSession().getMapper(getMapperClass(modelClass));
}
private void updateVersion(Object model) {
try {
if (model instanceof GenericModel) {
GenericModel genericModel = (GenericModel) model;
genericModel.setVersion(genericModel.getVersion() + 1);
genericModel.setUpdated(new Date());
}
if (model instanceof SequenceModel) {
SequenceModel sequenceModel = (SequenceModel) model;
sequenceModel.setVersion(sequenceModel.getVersion() + 1);
sequenceModel.setUpdated(new Date());
}
} catch (Exception e) {
}
}
private void setDeleted(Object model) {
try {
if (model instanceof GenericModel) {
GenericModel genericModel = (GenericModel) model;
genericModel.setDeleted(new Date());
genericModel.setUpdated(new Date());
genericModel.setVersion(genericModel.getVersion() + 1);
}
if (model instanceof SequenceModel) {
SequenceModel sequenceModel = (SequenceModel) model;
sequenceModel.setDeleted(new Date());
sequenceModel.setUpdated(new Date());
sequenceModel.setVersion(sequenceModel.getVersion() + 1);
}
} catch (Exception e) {
}
}
private void setAllBaseFieldsDefault(Object model) {
try {
if (model instanceof GenericReadOnlyModel) {
GenericReadOnlyModel genericReadOnlyModel = (GenericReadOnlyModel) model;
if (null == genericReadOnlyModel.getCreated()) {
genericReadOnlyModel.setCreated(new Date());
}
}
if (model instanceof GenericModel) {
GenericModel genericModel = (GenericModel) model;
genericModel.setUpdated(new Date());
genericModel.setVersion(0);
}
if (model instanceof SequenceReadOnlyModel) {
SequenceReadOnlyModel sequenceReadOnlyModel = (SequenceReadOnlyModel) model;
sequenceReadOnlyModel.setCreated(new Date());
}
if (model instanceof SequenceModel) {
SequenceModel sequenceModel = (SequenceModel) model;
sequenceModel.setUpdated(new Date());
sequenceModel.setVersion(0);
}
} catch (Exception e) {
}
}
//保存一个实体,null的属性也会保存,不会使用数据库默认值
public <T> int insert(T model) {
GenericMapper<T> mapper = getModelMapper(model.getClass());
setAllBaseFieldsDefault(model);
int num = mapper.insert(model);
if (model instanceof GenericReadOnlyModel) {
log.info("insert {} id = {}", model.getClass().getName(), ((GenericReadOnlyModel) model).getId());
}
return num;
}
//根据主键更新实体全部字段
public <T> int update(T model) {
GenericMapper<T> mapper = getModelMapper(model.getClass());
updateVersion(model);
int num = 0;
if (model instanceof GenericModel) {
Condition condition = new Condition(model.getClass());
GenericModel genericModel = (GenericModel) model;
condition.createCriteria()
.andEqualTo("id", genericModel.getId())
.andCondition("version = " + (genericModel.getVersion() - 1));
num = mapper.updateByCondition(model, condition);
if (num == 0) {
throw new ObjectOptimisticLockingFailureException("update [" + model.getClass().getName() + "] id = " + genericModel.getId() + " optimistic locking error (or not find id)");
}
} else {
num = mapper.updateByPrimaryKey(model);
}
if (model instanceof GenericModel) {
log.info("updated {} id = {} version = {}", model.getClass().getName(), ((GenericModel) model).getId(), ((GenericModel) model).getVersion());
} else if (model instanceof GenericReadOnlyModel) {
log.info("updated {} id = {}", model.getClass().getName(), ((GenericReadOnlyModel) model).getId());
}
return num;
}
public <T> int updateNoLock(T model) {
GenericMapper<T> mapper = getModelMapper(model.getClass());
updateVersion(model);
int num = mapper.updateByPrimaryKey(model);
if (model instanceof GenericModel) {
log.info("updated {} id = {} version = {}", model.getClass().getName(), ((GenericModel) model).getId(), ((GenericModel) model).getVersion());
} else if (model instanceof GenericReadOnlyModel) {
log.info("updated {} id = {}", model.getClass().getName(), ((GenericReadOnlyModel) model).getId());
}
return num;
}
//根据主键逻辑删除
public <T extends GenericModel> int remove(T model) {
GenericMapper<T> mapper = getModelMapper(model.getClass());
setDeleted(model);
int num = mapper.updateByPrimaryKey(model);
if (model instanceof GenericReadOnlyModel) {
log.info("removed {} id = {}", model.getClass().getName(), ((GenericReadOnlyModel) model).getId());
}
return num;
}
public <T> int delete(Class modelClass, Long id) {
GenericMapper<T> mapper = getModelMapper(modelClass);
int num = mapper.deleteByPrimaryKey(id);
log.info("removed {} id = {}", modelClass.getName(), id);
return num;
}
//根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号
public <T> T getById(Class<T> modelClass, Long id) {
GenericMapper<T> mapper = getModelMapper(mo