/** * Copyright 2014 Duan Bingnan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.pinus4j.datalayer; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.pinus4j.api.SQL; import org.pinus4j.api.query.IQuery; import org.pinus4j.api.query.impl.DefaultQueryImpl; import org.pinus4j.api.query.impl.DefaultQueryImpl.OrderBy; import org.pinus4j.constant.Const; import org.pinus4j.entity.DefaultEntityMetaManager; import org.pinus4j.entity.IEntityMetaManager; import org.pinus4j.entity.meta.EntityPK; import org.pinus4j.entity.meta.PKName; import org.pinus4j.entity.meta.PKValue; import org.pinus4j.utils.BeansUtil; import org.pinus4j.utils.StringUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** * SQL工具类. * * @author duanbn */ public class SQLBuilder { public static final Logger LOG = LoggerFactory.getLogger(SQLBuilder.class); /** * select count语句缓存. */ private static final Map<String, String> _selectCountCache = new ConcurrentHashMap<String, String>(); private static IEntityMetaManager entityMetaManager = DefaultEntityMetaManager.getInstance(); /** * 拼装sql. SELECT pkName FROM tableName {IQuery.getSql()} * * @return sql语句. */ public static <T> SQL buildSelectPkByQuery(Class<T> clazz, int tableIndex, IQuery<T> query) { String tableName = entityMetaManager.getTableName(clazz, tableIndex); PKName[] pkNames = entityMetaManager.getPkName(clazz); StringBuilder pkField = new StringBuilder(); for (PKName pkName : pkNames) { pkField.append('`').append(pkName.getValue()).append('`').append(','); } pkField.deleteCharAt(pkField.length() - 1); SQL querySQL = ((DefaultQueryImpl<T>) query).getWhereSql(); StringBuilder sqlText = new StringBuilder("SELECT " + pkField.toString() + " FROM "); sqlText.append('`').append(tableName).append('`'); String whereSql = querySQL.getSql(); if (StringUtil.isNotBlank(whereSql)) sqlText.append(whereSql); SQL sql = SQL.valueOf(sqlText.toString(), querySQL.getParams()); debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return sql; } /** * 拼装sql. SELECT {fields} FROM tableName {IQuery.getSql()} * * @return sql语句. */ public static <T> SQL buildSelectByQuery(Class<T> clazz, int tableIndex, IQuery<T> query) { String tableName = entityMetaManager.getTableName(clazz, tableIndex); StringBuilder fields = new StringBuilder(); if (((DefaultQueryImpl<T>) query).hasQueryFields()) { for (String field : ((DefaultQueryImpl<T>) query).getFields()) { fields.append('`').append(field).append('`').append(","); } fields.deleteCharAt(fields.length() - 1); } else { fields.append("*"); } SQL querySQL = ((DefaultQueryImpl<T>) query).getWhereSql(); StringBuilder sqlText = new StringBuilder("SELECT "); sqlText.append(fields.toString()).append(" FROM "); sqlText.append('`').append(tableName).append('`'); String whereSql = querySQL.getSql(); if (StringUtil.isNotBlank(whereSql)) sqlText.append(((DefaultQueryImpl<T>) query).getWhereSql()); SQL sql = SQL.valueOf(sqlText.toString(), querySQL.getParams()); debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return sql; } public static <T> SQL buildSelectCountByQuery(Class<T> clazz, int tableIndex, IQuery<T> query) { String tableName = entityMetaManager.getTableName(clazz, tableIndex); StringBuilder sqlText = new StringBuilder("SELECT count(*) FROM "); sqlText.append('`').append(tableName).append('`'); SQL querySQL = ((DefaultQueryImpl<T>) query).getWhereSql(); String whereSql = querySQL.getSql(); if (StringUtil.isNotBlank(whereSql)) sqlText.append(((DefaultQueryImpl<T>) query).getWhereSql()); SQL sql = SQL.valueOf(sqlText.toString(), querySQL.getParams()); debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return sql; } public static PreparedStatement buildSelectBySqlGlobal(Connection conn, SQL sql) throws SQLException { PreparedStatement ps = conn.prepareStatement(sql.getSql()); List<Object> params = sql.getParams(); if (params != null) { for (int i = 1; i <= params.size(); i++) { ps.setObject(i, params.get(i - 1)); } } debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return ps; } /** * 拼装sql. 根据SQL对象生成查询语句, 此sql语句不能包含limit * * @param conn 数据库连接 * @param sql 查询对象 * @param tableIndex 分表下标 * @return PreparedStatement * @throws SQLException */ public static PreparedStatement buildSelectBySql(Connection conn, SQL sql, int tableIndex) throws SQLException { String s = SQLParser.addTableIndex(sql.getSql(), tableIndex); PreparedStatement ps = conn.prepareStatement(s); List<Object> params = sql.getParams(); if (params != null) { for (int i = 1; i <= params.size(); i++) { ps.setObject(i, params.get(i - 1)); } } debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return ps; } public static String buildSelectCountGlobalSql(Class<?> clazz) { String tableName = entityMetaManager.getTableName(clazz, -1); StringBuilder SQL = new StringBuilder("SELECT count(*) ").append("FROM "); SQL.append('`').append(tableName).append('`'); debugSQL(SQL.toString()); return SQL.toString(); } /** * 拼装sql. SELECT count(*) FROM tableName * * @param clazz 数据对象class * @param tableIndex 分表下标 * @return SELECT count(*) FROM tableName */ public static String buildSelectCountSql(Class<?> clazz, int tableIndex) { String sql = _selectCountCache.get(clazz.getName() + tableIndex); if (sql != null) { debugSQL(sql); return sql; } String tableName = entityMetaManager.getTableName(clazz, tableIndex); StringBuilder SQL = new StringBuilder("SELECT count(*) ").append("FROM "); SQL.append('`').append(tableName).append('`'); _selectCountCache.put(clazz.getName() + tableIndex, SQL.toString()); debugSQL(SQL.toString()); return SQL.toString(); } /** * 拼装select sql. SELECT field, field FROM tableName WHERE pk in (?, ?, ?) * * @param clazz 数据对象 * @param tableIndex 表下标 * @param pks 主键 * @return sql语句 * @throws SQLException */ public static SQL buildSelectByPks(EntityPK[] pks, List<OrderBy> orders, Class<?> clazz, int tableIndex) throws SQLException { Field[] fields = BeansUtil.getFields(clazz, true); String tableName = entityMetaManager.getTableName(clazz, tableIndex); StringBuilder whereSql = new StringBuilder(); StringBuilder orderSql = new StringBuilder(); StringBuilder findInSet = new StringBuilder(); // build where // build find in set just only not union pk. List<Object> paramList = Lists.newArrayList(); if (entityMetaManager.isUnionKey(clazz)) { // union pk, build (pk1 = ? and pk2 = ?) or (pk1 = ? and pk2 = ?) for (EntityPK pk : pks) { whereSql.append("("); for (int i = 0; i < pk.getPkNames().length; i++) { whereSql.append('`').append(pk.getPkNames()[i].getValue()).append('`'); whereSql.append("=").append('?'); whereSql.append(" and "); paramList.add(formatValue(pk.getPkValues()[i].getValue())); } whereSql.delete(whereSql.length() - 5, whereSql.length()); whereSql.append(")"); whereSql.append(" or "); } whereSql.delete(whereSql.length() - 4, whereSql.length()); } else { // not union pk, build pk in (?,?,?) String pkName = entityMetaManager.getNotUnionPkName(clazz).getValue(); findInSet.append("find_in_set(").append(pkName).append(",'"); whereSql.append(pkName).append(" in ("); for (EntityPK pk : pks) { whereSql.append("?,"); findInSet.append(pk.getPkValues()[0].getValue()).append(','); paramList.add(formatValue(pk.getPkValues()[0].getValue())); } whereSql.deleteCharAt(whereSql.length() - 1); whereSql.append(")"); findInSet.deleteCharAt(findInSet.length() - 1); findInSet.append("')"); } // build order if (orders != null && !orders.isEmpty()) { orderSql.append(" order by "); for (OrderBy orderBy : orders) { orderSql.append('`').append(orderBy.getField()).append('`'); orderSql.append(" "); orderSql.append(orderBy.getOrder().getValue()); orderSql.append(","); } orderSql.deleteCharAt(orderSql.length() - 1); } else if (StringUtil.isNotBlank(findInSet.toString())) { orderSql.append(" order by "); orderSql.append(findInSet); } // build sql StringBuilder sqlText = new StringBuilder("SELECT "); for (Field field : fields) { sqlText.append('`').append(BeansUtil.getFieldName(field)).append('`').append(","); } sqlText.deleteCharAt(sqlText.length() - 1); sqlText.append(" FROM ").append('`').append(tableName).append('`'); sqlText.append(" WHERE ").append(whereSql.toString()); if (StringUtil.isNotBlank(orderSql.toString())) { sqlText.append(orderSql); } SQL sql = SQL.valueOf(sqlText.toString(), paramList); debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return sql; } /** * 拼装sql. DELETE FROM tableName WHERE pk in (...) * * @return DELETE语句 * @throws SQLException */ public static SQL buildDeleteByPks(Class<?> clazz, int tableIndex, List<EntityPK> pks) throws SQLException { String tableName = entityMetaManager.getTableName(clazz, tableIndex); StringBuilder whereSql = new StringBuilder(); List<Object> paramList = Lists.newArrayList(); for (EntityPK pk : pks) { whereSql.append("("); for (int i = 0; i < pk.getPkNames().length; i++) { whereSql.append('`').append(pk.getPkNames()[i].getValue()).append('`'); whereSql.append("=").append('?'); whereSql.append(" and "); paramList.add(formatValue(pk.getPkValues()[i].getValue())); } whereSql.delete(whereSql.length() - 5, whereSql.length()); whereSql.append(")"); whereSql.append(" or "); } whereSql.delete(whereSql.length() - 4, whereSql.length()); StringBuilder sqlText = new StringBuilder("DELETE FROM ").append('`').append(tableName).append('`'); sqlText.append(" WHERE ").append(whereSql.toString()); SQL sql = SQL.valueOf(sqlText.toString(), paramList); debugSQL(sql.getSql()); debugSQLParam(sql.getParams()); return sql; } /** * 获取update PreparedStatement. * * @param conn 数据库连接 * @param entities 数据对象 * @param tableIndex 分表下标 * @return PreparedStatement * @throws SQLException */ public static SQL getUpdate(Object entity, int tableIndex) throws SQLException { // 获取表名. String tableName = entityMetaManager.getTableName(entity, tableIndex); // 批量添加 Map<String, Object> entityProperty = null; try { entityProperty = BeansUtil.describe(entity, true); } catch (Exception e) { throw new SQLException("解析实体对象失败", e); } // 拼装主键条件 EntityPK entityPk = entityMetaManager.getEntityPK(entity); StringBuilder pkWhereSql = new StringBuilder(); List<Object> whereParam = Lists.newArrayList(); for (int i = 0; i < entityPk.getPkNames().length; i++) { pkWhereSql.append('`').append(entityPk.getPkNames()[i].getValue()).append('`'); pkWhereSql.append("=").append('?'); pkWhereSql.append(" and "); whereParam.add(formatValue(entityPk.getPkValues()[i].getValue())); } pkWhereSql.delete(pkWhereSql.length() - 5, pkWhereSql.length()); // 生成update语句. List<Object> paramList = Lists.newArrayList(); Set<Map.Entry<String, Object>> propertyEntrySet = entityProperty.entrySet(); StringBuilder sqlText = new StringBuilder("UPDATE `" + tableName + "` SET "); Object value = null; for (Map.Entry<String, Object> propertyEntry : propertyEntrySet) { value = propertyEntry.getValue(); sqlText.append('`').append(propertyEntry.getKey()).append('`'); sqlText.append("=").append("?"); sqlText.append(","); paramList.add(formatValue(value)); } sqlText.deleteCharAt(sqlText.length() - 1); sqlText.append(" WHERE ").append(pkWhereSql.toString()); paramList.addAll(whereParam); SQL sql = SQL.valueOf(sqlText.toString(), paramList); debugSQL(sqlText.toString()); debugSQLParam(paramList); return sql; } /** * 根据指定对象创建一个SQL语句. * * @param conn 数据库连接引用 * @param entity 数据对象 * @param tableIndex 分表下标 * @return SQL语句 * @throws SQLException 操作失败 */ public static SQL getInsert(Object entity, int tableIndex) throws SQLException { // 获取表名. String tableName = entityMetaManager.getTableName(entity, tableIndex); // 批量添加 Map<String, Object> entityProperty = null; try { // 获取需要被插入数据库的字段. entityProperty = BeansUtil.describe(entity, true); } catch (Exception e) { throw new SQLException("解析实体对象失败", e); } // 生成insert语句. Set<Map.Entry<String, Object>> propertyEntrySet = entityProperty.entrySet(); List<Object> paramList = Lists.newArrayList(); StringBuilder sqlText = new StringBuilder("INSERT INTO `" + tableName + "` ("); StringBuilder var = new StringBuilder(); for (Map.Entry<String, Object> propertyEntry : propertyEntrySet) { sqlText.append('`').append(propertyEntry.getKey()).append('`').append(","); var.append('?').append(','); paramList.add(formatValue(propertyEntry.getValue())); } sqlText.deleteCharAt(sqlText.length() - 1); sqlText.append(") VALUES ("); sqlText.append(var.deleteCharAt(var.length() - 1).toString()); sqlText.append(")"); SQL sql = SQL.valueOf(sqlText.toString(), paramList); debugSQL(sqlText.toString()); debugSQLParam(paramList); return sql; } /** * 给定数据库查询结果集创建数据对性. * * @param rs 数据库查询结果集 * @return 数据对象列表 */ public static List<Map<String, Object>> createResultObject(ResultSet rs) throws SQLException { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); ResultSetMetaData rsmd = rs.getMetaData(); Map<String, Object> one = null; while (rs.next()) { try { one = Maps.newLinkedHashMap(); String fieldName = null; Object value = null; for (int i = 1; i <= rsmd.getColumnCount(); i++) { fieldName = rsmd.getColumnName(i); value = rs.getObject(i); one.put(fieldName, value); } list.add(one); } catch (Exception e) { throw new SQLException(e); } } return list; } /** * 给定数据库查询结果集创建数据对性. * * @param clazz 数据对象class * @param rs 数据库查询结果集 * @return 数据对象列表 */ public static <T> List<T> createResultObject(Class<T> clazz, ResultSet rs) throws SQLException { List<T> list = new ArrayList<T>(); ResultSetMetaData rsmd = rs.getMetaData(); T one = null; while (rs.next()) { try { one = (T) clazz.newInstance(); String fieldName = null; Field f = null; Object value = null; for (int i = 1; i <= rsmd.getColumnCount(); i++) { fieldName = rsmd.getColumnName(i); f = BeansUtil.getField(clazz, fieldName); if (f == null) { continue; } value = _getRsValue(rs, f, i); BeansUtil.setProperty(one, fieldName, value); } list.add(one); } catch (Exception e) { throw new SQLException(e); } } return list; } /** * 将数据转换为数据对象 * * @param clazz 数据对象 * @param rs 结果集 * @return {pkValue, Object} * @throws SQLException */ public static <T> Map<EntityPK, T> createResultObjectAsMap(Class<T> clazz, ResultSet rs) throws SQLException { Map<EntityPK, T> map = Maps.newLinkedHashMap(); ResultSetMetaData rsmd = rs.getMetaData(); T one = null; String fieldName = null; PKName[] pkNames = entityMetaManager.getPkName(clazz); PKValue[] pkValues = null; Field f = null; Object value = null; while (rs.next()) { try { one = (T) clazz.newInstance(); for (int i = 1; i <= rsmd.getColumnCount(); i++) { fieldName = rsmd.getColumnName(i); f = BeansUtil.getField(clazz, fieldName); if (f == null) { continue; } value = _getRsValue(rs, f, i); BeansUtil.setProperty(one, fieldName, value); } pkValues = new PKValue[pkNames.length]; for (int i = 0; i < pkNames.length; i++) { pkValues[i] = PKValue.valueOf(rs.getObject(pkNames[i].getValue())); } map.put(EntityPK.valueOf(pkNames, pkValues), one); } catch (Exception e) { throw new SQLException(e); } } return map; } private static Object _getRsValue(ResultSet rs, Field f, int i) throws SQLException { Object value = rs.getObject(i); if (value != null) { if (f.getType() == Boolean.TYPE || f.getType() == Boolean.class) { value = rs.getString(i).equals(Const.TRUE) ? true : false; } else if (f.getType() == Byte.TYPE || f.getType() == Byte.class) { value = rs.getByte(i); } else if (f.getType() == Character.TYPE || f.getType() == Character.class) { String s = rs.getString(i); if (s.length() > 0) value = rs.getString(i).charAt(0); else value = new Character('\u0000'); } else if (f.getType() == Short.TYPE || f.getType() == Short.class) { value = rs.getShort(i); } else if (f.getType() == Long.TYPE || f.getType() == Long.class) { value = rs.getLong(i); } else if (f.getType() == Integer.TYPE || f.getType() == Integer.class) { if (value instanceof Boolean) { if ((Boolean) value) { value = new Integer(1); } else { value = new Integer(0); } } } } return value; } /** * 格式化数据库值. 过滤特殊字符 */ public static Object formatValue(Object value) { Object format = null; if (value instanceof Character && ((int) (Character) value) == 39) { format = "'\\" + (Character) value + "'"; } else { format = value; } return format; } public static void debugSQL(String sql) { if (LOG.isDebugEnabled()) { LOG.debug(sql); } } /** * 打印SQL日志. */ public static void debugSQLParam(List<Object> params) { if (LOG.isDebugEnabled()) { if (params != null && !params.isEmpty()) { StringBuilder paramText = new StringBuilder(); for (Object param : params) { paramText.append(param).append(','); } paramText.deleteCharAt(paramText.length() - 1); LOG.debug(paramText.toString()); } } } }