package com.elab.core.dao;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.fastjson.JSON;
import com.elab.core.bean.PageModel;
import com.elab.core.dao.model.JdbcParamsModel;
import com.elab.core.dao.model.ListDynamicSearch;
import com.elab.core.dao.model.SqlResult;
import com.elab.core.dao.params.BeanSqlParameterSource;
import com.elab.core.dao.params.MapDataSqlParameterSource;
import com.elab.core.dao.params.NamedParameterUtils2;
import com.elab.core.dao.params.ParsedSql2;
import com.elab.core.dao.row.ThirdRowMapper;
import com.elab.core.exception.CoreException;
import com.elab.core.spring.method.*;
import com.elab.core.sql.config.SqlCommandType;
import com.elab.core.utils.BeanPropertyUtils;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.namedparam.*;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.JdbcUtils;

import javax.persistence.Column;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * 增强的持久层操作
 *
 * @author Liukx
 * @create 2018-04-20 15:36
 * @email liukx@elab-plus.com
 **/
public class BasicBaseDao implements ApplicationContextAware, InitializingBean {

    private Logger logger = LoggerFactory.getLogger(BasicBaseDao.class);

    private JdbcTemplate jdbcTemplate;

    private CheckSqlProcess checkSqlProcess = new DefaultCheckSQLProcess();

    private List<SQLEventHandler> sqlEventHandlerList;

    private List<SQLPostProcess> sqlPostProcessorList;

    private ApplicationContext applicationContext;

    /**
     * 默认的基础类型
     */
    private Set<Class> basicTypes =
        Sets.newHashSet(String.class, Integer.class, Double.class, Long.class, Float.class, Date.class);

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, CheckSqlProcess> beansOfType = this.applicationContext.getBeansOfType(CheckSqlProcess.class);
        Map<String, SQLEventHandler> SQLEventHandlerMap = this.applicationContext.getBeansOfType(SQLEventHandler.class);
        if (SQLEventHandlerMap != null && SQLEventHandlerMap.size() > 0) {
            this.sqlEventHandlerList = new ArrayList<>();
            SQLEventHandlerMap.forEach((K, V) -> {
                this.sqlEventHandlerList.add(V);
            });
        }

        Map<String, SQLPostProcess> sqlPostProcessMap = this.applicationContext.getBeansOfType(SQLPostProcess.class);
        if (sqlPostProcessMap != null && sqlPostProcessMap.size() > 0) {
            this.sqlPostProcessorList = new ArrayList<>();
            sqlPostProcessMap.forEach((K, V) -> {
                this.sqlPostProcessorList.add(V);
            });
        }
    }

    //    @Override
    //    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    //
    //    }

    //    @Override
    //    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    //        Map<String, CheckSqlProcess> beansOfType = this.applicationContext.getBeansOfType(CheckSqlProcess.class);
    //        Map<String, SQLEventHandler> SQLEventHandlerMap = this.applicationContext.getBeansOfType(SQLEventHandler.class);
    //        if (SQLEventHandlerMap != null && SQLEventHandlerMap.size() > 0) {
    //            this.sqlEventHandlerList = new ArrayList<>();
    //            SQLEventHandlerMap.forEach((K, V) -> {
    //                this.sqlEventHandlerList.add(V);
    //            });
    //        }
    //    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public List<SQLEventHandler> getSqlEventHandlerList() {
        return sqlEventHandlerList;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
        if (namedParameterJdbcTemplate == null) {
            namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
        }
        return namedParameterJdbcTemplate;
    }

    /**
     * 缓存大小
     */
    private volatile int cacheLimit = NamedParameterJdbcTemplate.DEFAULT_CACHE_LIMIT;

    public void setCacheLimit(int cacheLimit) {
        this.cacheLimit = cacheLimit;
    }

    public int getCacheLimit() {
        return this.cacheLimit;
    }

    @SuppressWarnings("serial")
    private final Map<String, ParsedSql2> parsedSqlCache =
        new LinkedHashMap<String, ParsedSql2>(cacheLimit, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<String, ParsedSql2> eldest) {
                return size() > getCacheLimit();
            }
        };

    /**
     * 参数转换 , 参数类型分别为 Map,Model
     *
     * @param params
     * @return
     */
    private SqlParameterSource getSqlParameterSource(Object params) {
        SqlParameterSource sqlParameterSource = null;
        if (params instanceof Map) {
            sqlParameterSource = new MapSqlParameterSource((Map)params);
        } else {
            sqlParameterSource = new BeanPropertySqlParameterSource(params);
        }
        return sqlParameterSource;
    }

    /**
     * 将解析后的sql对象存放到缓存当中
     * todo 不过开始觉得这样的缓存也没有多大的必要,因为每次都要将sql和参数进行绑定一遍,得到一样的概率太低了,命中率不高
     *
     * @param sql
     * @return
     */
    protected ParsedSql2 getParsedSql2(String sql) {
        if (getCacheLimit() <= 0) {
            return NamedParameterUtils2.parseSqlStatement(sql);
        }
        synchronized (this.parsedSqlCache) {
            ParsedSql2 parsedSql = this.parsedSqlCache.get(sql);
            if (parsedSql == null) {
                parsedSql = NamedParameterUtils2.parseSqlStatement(sql);
                this.parsedSqlCache.put(sql, parsedSql);
            }
            return parsedSql;
        }
    }

    /**
     * 通用sql处理方式
     *
     * @param sql   sql语句
     * @param param 参数
     * @return
     */
    public JdbcParamsModel commonParseSql(String sql, Object param) throws Exception {
        return this.commonParseSql(sql, param, null);
    }

    public JdbcParamsModel commonParseSql(String sql, Object param, ListDynamicSearch search) throws Exception {
        long start = System.currentTimeMillis();
        JdbcParamsModel model = new JdbcParamsModel();
        if (param instanceof String) {
            model.setSql(sql);
            model.setObjects(ArrayUtils.toArray(param));
            logger.debug(" 转换后的sql - " + sql);
            logger.debug(" 对应参数    -  " + param);
            return model;
        }
        // 将sql和参数进行绑定
        ParsedSql2 parsedSql = getParsedSql2(sql);
        // 解析参数类型 , 这里会根据Map和Object对象做装换
        SqlParameterSource sqlParameterSource = getSqlParameterSource(param);
        // 获取有效的参数,将为null和""的参数给替换掉
        Object[] data = NamedParameterUtils2.buildValueArray(parsedSql, sqlParameterSource, null);
        // 正常解析sql为jdbc与参数对应
        String s = NamedParameterUtils2.substituteNamedParameters(parsedSql, sqlParameterSource);
        // 校验第一个参数为空的情况下
        s = NamedParameterUtils2.validFirstCheckSql(sql, s, parsedSql, sqlParameterSource);
        // 替换动态表名存在的情况下
        s = NamedParameterUtils2.replaceDynamic(s, sqlParameterSource);

        if (search != null) {
            model = NamedParameterUtils2.appendSQLContent(s, data, search);
        } else {
            model.setSql(s);
            model.setObjects(data);
        }

        logger.debug(" 转换后的sql - " + model.getSql());
        logger.debug(" 对应参数    -  " + Arrays.toString(model.getObjects()));

        // 校验SQL是否符合规范
        if (this.checkSqlProcess != null) {
            this.checkSqlProcess.checkProcess(model, param);
        }
        long time = System.currentTimeMillis() - start;
        logger.debug(" sql 语句处理耗时 : " + time);
        return model;
    }

    /**
     * 查询列表对象
     *
     * @param sql         sql语句
     * @param o           参数对象
     * @param elementType 返回结果对象
     * @param <T>
     * @return
     */
    public <T> List<T> executeQueryList(String sql, Object o, Class<T> elementType) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        List<T> ts = (List<T>)this.jdbcTemplate.query(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(),
            new TimeRowMapperResultSetExtractor(new ThirdRowMapper<T>(elementType)));
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    public <T> List<T> executeQueryBasicTypeList(String sql, Object o, Class<T> elementType) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        List<T> ts = (List<T>)this.jdbcTemplate
            .query(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), new SingleColumnRowMapper<>(elementType));
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    /**
     * 查询一个集合对象并返回指定的类型
     *
     * @param sql         SQL语句
     * @param obj         SQL执行参数
     * @param search      查询补充的参数
     * @param elementType 返回的数据类型
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> List<T> executeQueryList(String sql, Object obj, ListDynamicSearch search, Class<T> elementType)
        throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, obj, search);
        List<T> ts = findForList(elementType, jdbcParamsModel);
        return ts;
    }

    private <T> List<T> findForList(Class<T> elementType, JdbcParamsModel jdbcParamsModel) {
        long start = System.currentTimeMillis();
        List<T> ts = (List<T>)this.jdbcTemplate.query(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(),
            new TimeRowMapperResultSetExtractor(getRowMapper(elementType)));
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    protected <T> RowMapper<T> getRowMapper(Class<T> elementType) {
        if (basicTypes.contains(elementType)) {
            return new SingleColumnRowMapper<>(elementType);
        } else {
            return new ThirdRowMapper<>(elementType);
        }
    }

    /**
     * 查询一个分页对象
     *
     * @param pageModel   实体对象
     * @param sql         具体的SQL语句
     * @param o           参数值
     * @param elementType 返回对象
     * @param <T>
     * @return
     */
    public <T> List<T> executeQueryPage(PageModel pageModel, String sql, Object o, Class<T> elementType)
        throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        List<T> ts = this.jdbcTemplate
            .query(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), new ThirdRowMapper<T>(elementType));
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    /**
     * 获取一个实体对象,这里已经是底层的了
     *
     * @param sql         SQL语句
     * @param obj         参数对象
     * @param elementType 返回对象封装
     * @param <T>
     * @return
     */
    public <T> List<T> queryForList(String sql, Object[] obj, Class<T> elementType) {
        List<T> ts = this.jdbcTemplate.query(sql, obj, new ThirdRowMapper<T>(elementType));
        return ts;
    }

    /**
     * 执行一个查询语句返回一个总数集合
     *
     * @param sql
     * @param arg
     * @return
     */
    public int executeQueryCount(String sql, Object arg) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, arg);
        long start = System.currentTimeMillis();
        Integer count =
            this.jdbcTemplate.queryForObject(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), Integer.class);
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        logger.debug(" 获取到的总数 : " + count);
        return count;
    }

    /**
     * 查询一个Map对象的集合
     *
     * @param sql SQL语句
     * @param o   参数
     * @return
     */
    public List<Map<String, Object>> executeQueryForListMap(String sql, Object o, ListDynamicSearch dynamicSearch)
        throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o, dynamicSearch);
        long start = System.currentTimeMillis();
        List<Map<String, Object>> maps =
            this.jdbcTemplate.queryForList(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects());
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return maps;
    }

    /**
     * 查询大量数据返回的情况下
     *
     * @param sql         SQL语句
     * @param o           参数值
     * @param elementType 返回对象
     * @param <T>
     * @return
     */
    public <T> List<T> executeQueryBigDataList(String sql, Object o, Class<T> elementType) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        List<T> ts = queryBigDataForList(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), elementType);
        return ts;
    }

    /**
     * 查询大数据量的情况下,返回对象集合列表
     *
     * @param sql         sql语句
     * @param args        参数  [Map or Model]
     * @param elementType 返回出参结果类型
     * @param <T>
     * @return
     * @throws DataAccessException
     */
    public <T> List<T> queryBigDataForList(String sql, Object[] args, Class<T> elementType) throws DataAccessException {
        long start = System.currentTimeMillis();
        List<T> query = (List<T>)this.jdbcTemplate
            .query(sql, args, new TimeRowMapperResultSetExtractor(new ThirdRowMapper<T>(elementType)));
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return query;
    }

    /**
     * 查询单个对象
     *
     * @param sql         SQL语句
     * @param o           默认可以传 Map、Model
     * @param elementType 出参类型指定
     * @param <T>
     * @return
     */
    public <T> T executeQueryObject(String sql, Object o, Class<T> elementType) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        RowMapper<T> rm = ThirdRowMapper.newInstance(elementType);
        T ts = this.jdbcTemplate.queryForObject(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), rm);
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    /**
     * 获取总数信息
     *
     * @param sql         SQL语句
     * @param o           参数类型
     * @param elementType 返回参数类型
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T executeQueryCount(String sql, Object o, ListDynamicSearch search, Class<T> elementType)
        throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o, search);
        long start = System.currentTimeMillis();
        T ts = executorQuerySingleObject(elementType, jdbcParamsModel);
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return ts;
    }

    /**
     * 查询单个对象，避免查询不到框架底层直接异常
     *
     * @param elementType
     * @param jdbcParamsModel
     * @param <T>
     * @return
     */
    private <T> T executorQuerySingleObject(Class<T> elementType, JdbcParamsModel jdbcParamsModel) {
        try {
            return this.jdbcTemplate
                .queryForObject(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), elementType);
        } catch (EmptyResultDataAccessException e) {
            return null;
        } catch (IncorrectResultSizeDataAccessException e) {
            logger.error("数据异常,只要查询一个,但是结果集是多个!", e);
            return null;
        }
    }

    /**
     * 查询一个数据集合对象,根据自定义的数据转换器返回
     *
     * @param sql SQL语句
     * @param o   参数对象
     * @param rm  返回对象接口
     * @param <T>
     * @return
     */
    public <T> List<T> executeQueryMapper(String sql, Object o, RowMapper<T> rm) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        List<T> resultList = this.jdbcTemplate.query(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), rm);
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return resultList;
    }

    /**
     * 查询返回一个实体对象
     *
     * @param sql sql语句
     * @param o   对象信息
     * @param rm  映射接口
     * @param <T> 返回对象
     * @return
     */
    public <T> T executeQueryObject(String sql, Object o, RowMapper<T> rm) {
        T result = null;
        try {
            JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
            long start = System.currentTimeMillis();
            result = this.jdbcTemplate.queryForObject(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects(), rm);
            long time = System.currentTimeMillis() - start;
            logger.debug(" SQL 执行耗时 : " + time);
        } catch (EmptyResultDataAccessException e) {
            return null;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public <T> T executeQuery(String sql, Object[] o, RowMapper<T> rm) {
        T result = this.jdbcTemplate.queryForObject(sql, o, rm);
        return result;
    }

    /**
     * 查询返回一个Map对象
     *
     * @param sql SQL语句
     * @param o   参数对象
     * @return
     */
    public Map<String, Object> executeQueryMap(String sql, Object o) throws Exception {
        JdbcParamsModel jdbcParamsModel = commonParseSql(sql, o);
        long start = System.currentTimeMillis();
        Map<String, Object> map = null;
        try {
            map = this.jdbcTemplate.queryForMap(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects());
        } catch (EmptyResultDataAccessException e) {

        } catch (IncorrectResultSizeDataAccessException e) {
            logger.error("数据异常,只要查询一个,但是结果集是多个!", e);
        }
        long time = System.currentTimeMillis() - start;
        logger.debug(" SQL 执行耗时 : " + time);
        return map;
    }

    public int insert(String sql, Object o) throws Exception {
        return insert("", "", sql, o);
    }

    /**
     * 添加数据操作
     *
     * @param sql     SQL语句
     * @param request 参数对象
     * @return
     */
    public int insert(String sqlId, String table, String sql, Object request) throws Exception {
        int result = 0;
        boolean isOk = false;
        try {
            SqlParameterSource sqlParameterSource = getSqlParameterSource(request);
            GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
            sqlInvokeBefore(SqlCommandType.INSERT, sqlId, table, sql, request);
            long start = System.currentTimeMillis();
            logger.debug("sql : " + sql + "\r\n" + JSON.toJSONString(request));
            this.getNamedParameterJdbcTemplate().update(sql, sqlParameterSource, keyHolder);
            // 如果存在自动生成的主键,不存在那么表示参数中已经涵盖了,不需要返回。
            if (keyHolder.getKey() != null) {
                result = keyHolder.getKey().intValue();
            }
            logger.debug(" 得到主键 : " + result);
            long time = System.currentTimeMillis() - start;
            logger.debug(" SQL 执行耗时 : " + time);
            sqlInvokeAfter(SqlCommandType.INSERT, sqlId, table, sql, request, result);
            sqlPostCallBack(SqlCommandType.INSERT, sqlId, table, sql, request, result, time, 1);
            isOk = true;
        } finally {
            if (!isOk) {
                sqlPostCallBack(SqlCommandType.INSERT, sqlId, table, sql, request, result, -1L, -1);
            }
        }
        return result;
    }

    /**
     * 将内部参数转换成对应的属性器
     *
     * @param bean
     * @param nameMap
     * @return
     */
    private SqlParameterSource getConvertSqlParameterSource(Object bean, Map<String, String> nameMap) {
        SqlParameterSource sqlParameterSource = null;
        if (bean instanceof Map) {
            sqlParameterSource = new MapDataSqlParameterSource((Map<String, ?>)bean);
        } else {
            sqlParameterSource = new BeanSqlParameterSource(bean);
            ((BeanSqlParameterSource)sqlParameterSource).setPropertyMap(nameMap);
        }
        return sqlParameterSource;
    }

    public int[] batchOperation(SqlCommandType sqlCommandType, String sql, List list) throws Exception {
        return batchOperation(sqlCommandType, "", "", sql, list);
    }

    /**
     * 批量操作
     *
     * @param sqlCommandType 执行的SQL命令类型
     * @param sql            sql语句
     * @param list           数据集合
     * @return
     */
    public int[] batchOperation(SqlCommandType sqlCommandType, String sqlId, String table, String sql, List list)
        throws Exception {
        if (list != null && list.size() > 0) {
            long start = System.currentTimeMillis();
            logger.debug("sql : " + sql);
            Object o = list.get(0);
            SqlParameterSource[] parameterSource = null;
            Map<String, String> nameMap = null;
            if (o instanceof Map) {
                parameterSource = new MapSqlParameterSource[list.size()];
            } else {
                parameterSource = new BeanSqlParameterSource[list.size()];
                nameMap = BeanPropertyUtils.getColumnProperty(o, Column.class, "name");
            }

            for (int i = 0; i < list.size(); i++) {
                Object bean = list.get(i);
                SqlParameterSource sqlParameterSource = getConvertSqlParameterSource(bean, nameMap);
                parameterSource[i] = sqlParameterSource;
            }

            int[] results;
            sqlInvokeBefore(sqlCommandType, sqlId, table, sql, list);
            // 如果是批量新增的情况，则要将新增的批量编号进行返回
            if (SqlCommandType.INSERT == sqlCommandType) {
                results = batchInsert(sql, parameterSource);
            } else {
                results = this.getNamedParameterJdbcTemplate().batchUpdate(sql, parameterSource);
            }
            sqlInvokeAfter(sqlCommandType, sqlId, table, sql, list, results);
            logger.debug(" params size : " + list.size());
            long time = System.currentTimeMillis() - start;
            logger.debug(" SQL 执行耗时 : " + time);
            sqlPostCallBack(SqlCommandType.UPDATE, sqlId, table, sql, list, results, time, 1);
            return results;
        } else {
            throw new CoreException("批量操作数据不能为空 ...");
        }
    }

    /**
     * 批量返回新增结果
     *
     * @param sql             要执行的SQL
     * @param parameterSource 参数对象
     * @return
     * @throws SQLException
     */
    private int[] batchInsert(String sql, SqlParameterSource[] parameterSource) throws SQLException {
        ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
        String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, parameterSource[0]);
        List<SqlParameter> declaredParameters =
            NamedParameterUtils.buildSqlParameterList(parsedSql, parameterSource[0]);
        PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
        /**
         * 参数执行处理
         */
        BatchPreparedStatementSetter pss = new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                // 将SQL的中的:参数转化成数组
                Object[] values = NamedParameterUtils.buildValueArray(parsedSql, parameterSource[i], null);
                // 转化成数组之后一个个和?对应填充
                pscf.newPreparedStatementSetter(values).setValues(ps);
            }

            @Override
            public int getBatchSize() {
                return parameterSource.length;
            }
        };
        /**
         * 创建Statement对象的时候，加上Statement.RETURN_GENERATED_KEYS参数
         */
        BatchPreparedStatementCreator batchPreparedStatementCreator = new BatchPreparedStatementCreator(sqlToUse);
        return jdbcTemplate.execute(batchPreparedStatementCreator, (PreparedStatementCallback<int[]>)ps -> {
            try {
                int batchSize = pss.getBatchSize();
                int[] keys = new int[batchSize];

                InterruptibleBatchPreparedStatementSetter ipss =
                    (pss instanceof InterruptibleBatchPreparedStatementSetter ?
                        (InterruptibleBatchPreparedStatementSetter)pss : null);
                if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
                    for (int i = 0; i < batchSize; i++) {
                        pss.setValues(ps, i);
                        if (ipss != null && ipss.isBatchExhausted(i)) {
                            break;
                        }
                        ps.addBatch();
                    }
                    ps.executeBatch();
                    // 将插入的主键值返回出来
                    ResultSet rs = ps.getGeneratedKeys();
                    int index = 0;
                    while (rs.next() && index < batchSize) {
                        keys[index] = rs.getInt(1);
                        index++;
                    }
                    return keys;
                } else {
                    List<Integer> rowsAffected = new ArrayList<>();
                    for (int i = 0; i < batchSize; i++) {
                        pss.setValues(ps, i);
                        if (ipss != null && ipss.isBatchExhausted(i)) {
                            break;
                        }
                        rowsAffected.add(ps.executeUpdate());
                    }
                    int[] rowsAffectedArray = new int[rowsAffected.size()];
                    for (int i = 0; i < rowsAffectedArray.length; i++) {
                        rowsAffectedArray[i] = rowsAffected.get(i);
                    }
                    return rowsAffectedArray;
                }
            } finally {
                if (pss instanceof ParameterDisposer) {
                    ((ParameterDisposer)pss).cleanupParameters();
                }
            }
        });
    }

    protected PreparedStatementCreatorFactory getPreparedStatementCreatorFactory(ParsedSql parsedSql,
        SqlParameterSource paramSource) {
        String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
        List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
        return new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
    }

    private void sqlInvokeBefore(SqlCommandType event, String sqlId, String table, String sql, Object o) {
        if (this.sqlEventHandlerList != null && this.sqlEventHandlerList.size() > 0) {
            for (int i = 0; i < sqlEventHandlerList.size(); i++) {
                SQLEventHandler sqlEventHandler = sqlEventHandlerList.get(i);
                sqlEventHandler.sqlInvokeBefore(event, sqlId, table, sql, o);
            }
        }
    }

    private void sqlInvokeAfter(SqlCommandType event, String sqlId, String table, String sql, Object request,
        Object result) {
        if (this.sqlEventHandlerList != null && this.sqlEventHandlerList.size() > 0) {
            for (int i = 0; i < sqlEventHandlerList.size(); i++) {
                SQLEventHandler sqlEventHandler = sqlEventHandlerList.get(i);
                sqlEventHandler.sqlInvokeAfter(event, sqlId, table, sql, request, result);
            }
        }
    }

    /**
     * SQL的后置触发器
     *
     * @param event   执行事件
     * @param sqlId   SQL编号
     * @param table   表名
     * @param sql     SQL内容
     * @param request SQL参数
     * @param result  结果集
     * @param time    耗时
     * @param status  状态
     */
    private void sqlPostCallBack(SqlCommandType event, String sqlId, String table, String sql, Object request,
        Object result, Long time, Integer status) {
        try {
            if (this.sqlPostProcessorList != null && this.sqlPostProcessorList.size() > 0) {
                for (int i = 0; i < sqlPostProcessorList.size(); i++) {
                    SqlResult sqlResult = new SqlResult();
                    sqlResult.setCommandType(event.name());
                    sqlResult.setSqlId(sqlId);
                    sqlResult.setTable(table);
                    sqlResult.setSql(sql);
                    sqlResult.setRequestParams(request);
                    sqlResult.setResult(result);
                    sqlResult.setTime(time);
                    if (result != null) {
                        if (result instanceof int[]) {
                            sqlResult.setAffectRows(((int[])result).length);
                            sqlResult.setCommandType("batch_" + event.name());
                        } else if (result instanceof Number) {
                            if (event == SqlCommandType.INSERT) {
                                sqlResult.setAffectRows(1);
                            } else {
                                sqlResult.setAffectRows((Integer)result);
                            }
                        }
                    }
                    sqlResult.setStatus(status);
                    SQLPostProcess sqlPostProcess = sqlPostProcessorList.get(i);
                    sqlPostProcess.callback(sqlResult);
                }
            }
        } catch (Exception e) {
            logger.warn("SQL 后置处理器失败 : ", e);
        }
    }

    /**
     * 执行修改
     *
     * @param sql
     * @param o
     * @return
     * @throws Exception
     */
    public int update(String sql, Object o) throws Exception {
        return update("", "", sql, o);
    }

    /**
     * 修改数据操作
     *
     * @param sql     SQL语句
     * @param request 对象
     * @return
     */
    public int update(String sqlId, String table, String sql, Object request) throws Exception {
        boolean isOk = false;
        try {
            JdbcParamsModel jdbcParamsModel = commonParseSql(sql, request);
            sqlInvokeBefore(SqlCommandType.UPDATE, sqlId, table, sql, request);
            long start = System.currentTimeMillis();
            int update = this.jdbcTemplate.update(jdbcParamsModel.getSql(), jdbcParamsModel.getObjects());
            long time = System.currentTimeMillis() - start;
            sqlInvokeAfter(SqlCommandType.UPDATE, sqlId, table, sql, request, update);
            logger.debug(" SQL 执行耗时 : " + time);
            sqlPostCallBack(SqlCommandType.UPDATE, sqlId, table, getFormatSQL(jdbcParamsModel), request, update, time,
                1);
            isOk = true;
            return update;
        } finally {
            if (!isOk) {
                sqlPostCallBack(SqlCommandType.UPDATE, sqlId, table, sql, request, null, -1L, -1);
            }
        }
    }

    private String getFormatSQL(JdbcParamsModel jdbcParamsModel) {
        String sql = jdbcParamsModel.getSql();
        try {
            Object[] objects = jdbcParamsModel.getObjects();
            return SQLUtils.format(sql, "MYSQL", Arrays.asList(objects));
        } catch (Exception e) {
            logger.warn("sql format error : " + e.getMessage());
            return sql;
        }
    }

}
