package com.ketayao.fensy.db;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.dbutils.DbUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ketayao.fensy.cache.CacheManager;
import com.ketayao.fensy.exception.DBException;
import com.ketayao.fensy.util.StringUtils;
/**
* 数据库对象的基类
*
* @author <a href="mailto:ketayao@gmail.com">ketayao</a>
* @since 2013年7月26日 下午4:10:55
*/
public class POJO extends BaseEntity {
private static final long serialVersionUID = -8293013385107724530L;
protected static final Logger logger = LoggerFactory.getLogger(POJO.class);
protected static final transient char OBJ_COUNT_CACHE_KEY = '#';
/**
* 插入对象到数据库表中
*
* @return
*/
public long save() {
if (getId() > 0)
insertObject(this);
else
setId(insertObject(this));
if (isCachedByID()) {
evictCache(OBJ_COUNT_CACHE_KEY);
putCache(getId(), this);
}
return getId();
}
/**
* 根据id主键删除对象
*
* @return
*/
public boolean delete() {
boolean dr = (QueryHelper.update("DELETE FROM " + getTableName() + " WHERE id=?",
getId()) == 1);
if (dr) {
CacheManager.evict(getCacheRegion(), OBJ_COUNT_CACHE_KEY);
evictCache(dr);
}
return dr;
}
/**
* 根据主键读取对象详细资料,根据预设方法自动判别是否需要缓存
*
* @param id
* @return
*/
@SuppressWarnings("unchecked")
public <T extends POJO> T get(long id) {
if (id <= 0)
return null;
String sql = "SELECT * FROM " + getTableName() + " WHERE id=?";
return (T) QueryHelper.readFromCache(getClass(), isCachedByID() ? getCacheRegion() : null,
id, sql, id);
}
/**
* 根据属性查找对象
*
* @param attrName
* @param attrValue
* @return
*/
@SuppressWarnings("unchecked")
public <T extends POJO> T getByAttr(String attrName, Object attrValue) {
String sql = "SELECT * FROM " + getTableName() + " WHERE " + attrName + " = ?";
return (T) QueryHelper.read(getClass(), sql, attrValue);
}
/**
* 更新属性
*
* @param attrName
* @param attrValue
* @return
*/
public boolean updateAttr(String attrName, Object attrValue) {
String sql = "UPDATE " + getTableName() + " SET " + attrName + " = ? WHERE id = ?";
int ret = QueryHelper.update(sql, attrValue, getId());
try {
if (ret > 0) {
BeanUtils.setProperty(this, attrName, attrValue);
} else {
// 更新失败删除缓存对象
if (isCachedByID()) {
evictCache(getId());
}
return false;
}
} catch (Exception e) {
// 更新失败删除缓存对象
if (isCachedByID()) {
evictCache(getId());
}
return false;
}
return true;
}
/**
* 更新属性
*
* @param attrNames
* @param attrValues
* @return
*/
public boolean updateAttrs(String[] attrNames, Object[] attrValues) {
int len = attrNames.length;
List<String> kvs = new ArrayList<String>(len);
for (String attr : attrNames) {
kvs.add(attr + " = ?");
}
String sql = "UPDATE " + getTableName() + " SET " + StringUtils.join(kvs, ',')
+ " WHERE id = ?";
List<Object> vals = new ArrayList<Object>();
for (Object val : attrValues) {
vals.add(val);
}
vals.add(getId());
int ret = QueryHelper.update(sql, vals.toArray());
try {
if (ret > 0) {
for (int i = 0; i < len; i++) {
BeanUtils.setProperty(this, attrNames[i], attrValues[i]);
}
} else {
// 更新失败删除缓存对象
if (isCachedByID()) {
evictCache(getId());
}
return false;
}
} catch (Exception e) {
// 更新失败删除缓存对象
if (isCachedByID()) {
evictCache(getId());
}
return false;
}
return true;
}
/**
* 直接从数据库获取 描述
*
* @param ids
* @return
*/
public List<? extends POJO> batchGet(List<Long> ids) {
if (ids == null || ids.size() == 0)
return null;
StringBuilder sql = new StringBuilder("SELECT * FROM " + getTableName() + " WHERE id IN (");
for (int i = 1; i <= ids.size(); i++) {
sql.append('?');
if (i < ids.size())
sql.append(',');
}
sql.append(')');
List<? extends POJO> beans = QueryHelper.query(getClass(), sql.toString(),
ids.toArray(new Object[ids.size()]));
if (isCachedByID()) {
for (Object bean : beans) {
putCache(((POJO) bean).getId(), (Serializable) bean);
}
}
return beans;
}
/**
* 返回所有对象
*
* @return
*/
public List<? extends POJO> list() {
String sql = "SELECT * FROM " + getTableName() + " ";
return QueryHelper.query(getClass(), sql);
}
/**
* 根据条件返回对象集合
*
* @param filter
* @return
*/
public List<? extends POJO> list(String filter) {
String sql = "SELECT * FROM " + getTableName() + " WHERE " + filter;
return QueryHelper.query(getClass(), sql);
}
/**
* 分页列出所有对象
*
* @param page
* @param size
* @return
*/
public List<? extends POJO> list(int page, int size) {
return list(page, size, "id DESC");
}
/**
* 根据排序条件,分页列出所有对象
*
* @param page
* @param size
* @return
*/
public List<? extends POJO> list(int page, int size, String orderBy) {
String sql = "SELECT * FROM " + getTableName() + " ";
if (StringUtils.isNotBlank(orderBy)) {
sql += " ORDER BY " + orderBy;
}
return QueryHelper.querySlice(getClass(), sql, page, size);
}
/**
* 根据查询条件,分页列出对象集合
*
* @param page
* @param size
* @param filter
* @return
*/
public List<? extends POJO> filter(int page, int size, String filter) {
return filter(page, size, filter, "id DESC");
}
/**
* 根据查询与排序条件,分页列出对象集合
*
* @param page
* @param size
* @param filter
* @param orderBy
* @return
*/
public List<? extends POJO> filter(int page, int size, String filter, String orderBy) {
String sql = "SELECT * FROM " + getTableName() + " WHERE " + filter;
if (StringUtils.isNotBlank(orderBy)) {
sql += " ORDER BY " + orderBy;
}
return QueryHelper.querySlice(getClass(), sql, page, size);
}
/**
* 返回对象总数量
*
* @return
*/
public long totalCount() {
if (isCachedByID())
return (long) QueryHelper.statFromCache(getCacheRegion(), OBJ_COUNT_CACHE_KEY,
"SELECT COUNT(*) FROM " + getTableName());
return (long) QueryHelper.stat("SELECT COUNT(*) FROM " + getTableName());
}
/**
* 得到满足条件的对象id集合,并放入查询缓存。 对这个cache的更新操作需要格外留意
*
* @param filter
* @param params
* @return
*/
public List<Long> getIds(String filter, Object... params) {
return getKeys("id", filter, params);
}
/**
* 得到满足条件的对象id集合,并放入查询缓存。 对这个cache的更新操作需要格外留意
*
* @param filter
* @param params
* @return
*/
public List<Long> getKeys(String key, String filter, Object... params) {
String sql = "SELECT " + key + " FROM " + getTableName() + " WHERE " + filter;
StringBuilder cacheKey = new StringBuilder(filter + "=");
for (Object obj : params) {
cacheKey.append(obj.toString() + ",");
}
cacheKey.deleteCharAt(cacheKey.length() - 1);
if (logger.isDebugEnabled()) {
logger.debug("FROM " + getCacheRegion() + ", cacheKey=" + cacheKey);
}
return QueryHelper.queryFromCache(Long.class, getQueryCacheRegion(), cacheKey, sql, params);
}
/**
* 根据条件,返回对象数量
*
* @return
*/
public long totalCount(String filter) {
return (long) QueryHelper
.stat("SELECT COUNT(*) FROM " + getTableName() + " WHERE " + filter);
}
/**
* 批量加载对象
*
* @param pids
* @return
*/
@SuppressWarnings("rawtypes")
public List loadList(final List<Long> ids) {
if (ids == null || ids.isEmpty())
return new ArrayList(0);
// 因为要保持有序,所以按照id顺序创建对象
List<POJO> prjs = new ArrayList<POJO>(ids.size()) {
private static final long serialVersionUID = 1L;
{
for (int i = 0; i < ids.size(); i++)
add(null);
}
};
List<Long> noCacheIds = new ArrayList<Long>();
for (int i = 0; i < ids.size(); i++) {
long id = ids.get(i);
POJO obj = (POJO) getCache(id);
if (obj != null)
prjs.set(i, obj);
else {
noCacheIds.add(id);
}
}
if (noCacheIds.size() > 0) {
List<? extends POJO> objs = batchGet(noCacheIds);
if (objs != null)
for (POJO obj : objs) {
prjs.set(ids.indexOf(obj.getId()), obj);
}
}
return prjs;
}
/**
* 插入对象
*
* @param obj
* @return 返回插入对象的主键
*/
private static long insertObject(POJO obj) {
Map<String, Object> pojo = obj.listInsertableFields();
String[] fields = pojo.keySet().toArray(new String[pojo.size()]);
StringBuilder sql = new StringBuilder("INSERT INTO ");
sql.append(obj.getTableName());
sql.append('(');
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append(fields[i]);
}
sql.append(") VALUES(");
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append('?');
}
sql.append(')');
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = QueryHelper.getConnection().prepareStatement(sql.toString(),
PreparedStatement.RETURN_GENERATED_KEYS);
for (int i = 0; i < fields.length; i++) {
ps.setObject(i + 1, pojo.get(fields[i]));
}
ps.executeUpdate();
rs = ps.getGeneratedKeys();
return rs.next() ? rs.getLong(1) : -1;
} catch (SQLException e) {
throw new DBException(e);
} finally {
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(ps);
sql = null;
fields = null;
pojo = null;
}
}
}