package com.walker.connector.support; import com.walker.connector.AbstractConnector; import com.walker.db.DatabaseException; import com.walker.db.DatabaseExistException; import com.walker.db.DatabaseType; import com.walker.db.page.GenericPager; import com.walker.db.page.ListPageContext; import com.walker.infrastructure.utils.StringUtils; import com.walker.jdbc.ds.MyDruidDataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import javax.sql.DataSource; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * 基于数据库实现的连接器对象,目前仅能查询数据集合 * @author shikeying * @date 2015年12月15日 * */ public abstract class DatabaseConnector extends AbstractConnector { public static final String OPTION_USER = "user"; public static final String OPTION_PASSWORD = "password"; public static final String OPTION_MAX_ACTIVE = "maxActive"; public static final String OPTION_MAX_IDLE = "maxIdle"; public static final String OPTION_INIT_SIZE = "initialSize"; public static final String SQL_CREATE_DB_PREF = "CREATE DATABASE "; public static final String SQL_CREATE_DB_SUF = " DEFAULT CHARSET utf8 COLLATE utf8_general_ci;"; // private SupportDBTypeDataSource dataSource = null; // 2023-05-08 统一使用平台配置数据源,不再创建独立数据源。 // private DataSource dataSource = null; protected JdbcTemplate jdbcTemplate = null; protected NamedParameterJdbcTemplate namedJdbcTemplate; /* 管理模式:不设置数据库名字,可以创建数据库,应该也可以管理 */ private boolean manageMode = false; private DataSource dataSource = null; /** * 没有数据源,只能通过设置参数方式初始化连接器,最后要调用{@link this.initialize()}方法初始化 */ public DatabaseConnector(){} /** * 如果从外部传入数据源,则通过构造函数直接创建即可。 * @param dataSource */ public DatabaseConnector(DataSource dataSource){ if(dataSource == null){ throw new IllegalArgumentException("dataSource必须设置!"); } this.dataSource = dataSource; jdbcTemplate = new JdbcTemplate(dataSource); namedJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); } public DataSource getDataSource() { // return (DataSource) JdbcInspector.getInstance().getPrimaryDataSourceMeta(); return this.dataSource; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public NamedParameterJdbcTemplate getNamedJdbcTemplate() { return namedJdbcTemplate; } /** * 返回是否管理模式,管理模式中没有数据库名字,用于处理各种数据库命令 * @return */ public boolean isManageMode() { return manageMode; } /** * 设置为管理模式:没有数据库名字 */ public void setManageMode() { this.manageMode = true; this.setServiceName(StringUtils.EMPTY_STRING); } /** * 执行命令:创建数据库 * @param databaseName * @throws DatabaseException */ public void exeCreateDatabase(String databaseName) throws DatabaseException { try{ jdbcTemplate.execute(new StringBuilder() .append(SQL_CREATE_DB_PREF) .append(databaseName) .append(SQL_CREATE_DB_SUF).toString()); } catch(DataAccessException ex){ SQLException sqlEx = (SQLException)ex.getRootCause(); if(sqlEx.getErrorCode() == 1007){ throw new DatabaseExistException(databaseName); } else throw new DatabaseException("createDatabase异常", ex); } } /** * 根据SQL语句创建表结构 * @param sql * @throws DatabaseException */ public void exeCreateTable(String sql) throws DatabaseException{ try{ jdbcTemplate.execute(sql); logger.debug("执行创建表SQL = " + sql); } catch(DataAccessException ex){ // SQLException sqlEx = (SQLException)ex.getRootCause(); // if(sqlEx.getErrorCode() == 1007){ // throw new DatabaseExistException("ddddddd"); // } else throw new DatabaseException("createTable异常", ex); } } /** * 批量写入数据库记录 * @param sql * @param spsArray * @transaction 注意:方法名前缀为"exec"的会走事务处理,不过需要在DatabaseStore中设置参数 */ public int execBatchInsert(String sql, MapSqlParameterSource[] spsArray){ int[] res = namedJdbcTemplate.batchUpdate(sql, spsArray); return res[0]; } /** * 使用JdbcTemplate实现批量更新。

* 通过?替换变量数据即可。 * @param sql * @param batchArgs */ public void execBatchUpdateForJdbc(String sql, List batchArgs){ jdbcTemplate.batchUpdate(sql, batchArgs); } public void execute(String sql) throws DatabaseException{ try{ jdbcTemplate.execute(sql); } catch(DataAccessException ex){ throw new DatabaseException("execute(sql)异常", ex); } } // /** // * 返回指定的数据库存在表数量 // * @param schema // * @return // */ // public int queryTableSize(String schema){ // return 0; // } /** * 根据sql语句,检索列表数据,返回的一条记录是一个map对象。 * @param sql * @param args * @return */ public List> queryForList(String sql, Object[] args){ return getJdbcTemplate().queryForList(sql, args); } public List queryForRowMapper(String sql, Object[] args, RowMapper rowMapper){ return getJdbcTemplate().query(sql, args, rowMapper); } /** * 查询自定义rowMapper对象,该方法主要使用namedJdbcTemplate来查询。
* 因为对于有些类似:where in (:ids)的查询必须使用命名参数,使用jdbcTemplate则无法查询 * @param sql * @param rowMapper * @param paramSource * @return */ public List queryForRowMapper(String sql, RowMapper rowMapper, SqlParameterSource paramSource){ return namedJdbcTemplate.query(sql, paramSource, rowMapper); } /** * 根据sql语句查询一个整数值,如:总数等 * @param sql * @param args * @return */ public int queryForInt(String sql, Object[] args){ // logger.debug("+++++++++++++++ jdbcTemplate = " + this.jdbcTemplate); Integer maxValue = this.getJdbcTemplate().queryForObject(sql, Integer.class, args); if(maxValue == null){ return 0; } return maxValue; } public long queryForLong(String sql, Object[] args){ Long maxValue = this.getJdbcTemplate().queryForObject(sql, Long.class, args); if(maxValue == null){ return 0; } return maxValue; } /** * 给定统计公式,返回单个统计值。 * @param sql * @param args * @param clazz * @return */ public E sqlMathQuery(String sql, Object[] args, Class clazz){ return this.jdbcTemplate.queryForObject(sql, clazz, args); } /** * 查询自定义rowMapper对象,该方法主要使用namedJdbcTemplate来查询。
* 因为对于有些类似:where in (:ids)的查询必须使用命名参数,使用jdbcTemplate则无法查询 * @param sql * @param rowMapper * @param paramSource * @return */ public List sqlListObjectWhereIn(String sql, RowMapper rowMapper, SqlParameterSource paramSource){ return this.namedJdbcTemplate.query(sql, paramSource, rowMapper); } /** * 实现简单的分页数据返回,需要提供对象转换接口,使用了Spring框架的RowMapper.
* @param sql * @param args * @param rowMapper // * @param pageIndex 当前页(如:第五页则值为5) // * @param pageSize * @param pageSql 分页的sql语句,不同数据库不一样。如:mysql为" select * from table [limit ? offset ?]" * @return */ public GenericPager sqlSimpleQueryPager(String sql, Object[] args, RowMapper rowMapper // , int pageIndex, int pageSize , String pageSql){ StringBuilder sqlCount = new StringBuilder(); sqlCount.append("select count(*) cnt from ("); sqlCount.append(sql); sqlCount.append(") t"); int count = jdbcTemplate.queryForObject(sqlCount.toString(), Integer.class, args); int pageIndex = ListPageContext.getCurrentPageIndex(); int pageSize = ListPageContext.getCurrentPageSize(); GenericPager pager = ListPageContext.createGenericPager(pageIndex, pageSize, count); // logger.debug("...........page count = " + count); // logger.debug("..........."+sqlCount.toString()); // if(args != null){ // for(Object obj : args){ // logger.debug("参数:" + obj); // } // } /* 设置分页参数 */ List datas = jdbcTemplate.query(pageSql, rowMapper, getSqlPageArgs(args, (int)pager.getFirstRowIndexInPage(), pageSize)); // logger.debug("记录索引值:" + pager.getFirstRowIndexInPage() + ", " + pager.getPageIndex()); logger.debug(pageSql); // logger.debug(datas); return pager.setDatas(datas); } /** * 组装并返回分页需要的参数数组 * @param args * @param firstRowIndex * @param pageSize * @return */ protected Object[] getSqlPageArgs(Object[] args, int firstRowIndex, int pageSize){ Object[] params = null; int j = 0; if(args == null || args.length == 0){ params = new Object[2]; } else { params = new Object[args.length+2]; for(; j)param[2], (Object[])param[1]); } else { return jdbcTemplate.queryForList((String)param[0], (Object[])param[1]); } } @Override public void initialize() { super.initialize(); if(!this.manageMode && StringUtils.isEmpty(getServiceName())){ throw new IllegalArgumentException("未提供数据库名称:serviceName"); } Map params = getParameters(); if(params.size() <= 0){ throw new IllegalArgumentException("未找到数据库连接参数"); } if(params.get(OPTION_USER) == null || params.get(OPTION_PASSWORD) == null){ throw new IllegalArgumentException("未找到数据库连接参数:用户名或密码"); } /* DefaultDataSource dataSource = new DefaultDataSource(); DefaultDataSource ds = (DefaultDataSource)dataSource; ds.setDatabaseType(this.getDatabaseType().getTypeIndex()); ds.setIp(getUrl()); ds.setPort(getPort()); ds.setDatabaseName(getServiceName()); ds.setUsername(params.get(OPTION_USER)); ds.setPassword(params.get(OPTION_PASSWORD)); // 设置连接池参数 // dataSource.setMaxWait(10000); // dataSource.setRemoveAbandoned(true); // dataSource.setRemoveAbandonedTimeout(300); // dataSource.setTimeBetweenEvictionRunsMillis(60000); // dataSource.setNumTestsPerEvictionRun(10); // dataSource.setMinEvictableIdleTimeMillis(10000); // dataSource.setTestWhileIdle(true); // if(params.get(OPTION_MAX_ACTIVE) != null){ // dataSource.setMaxActive(Integer.parseInt(params.get(OPTION_MAX_ACTIVE))); // } else { // dataSource.setMaxActive(10); // } // if(params.get(OPTION_MAX_IDLE) != null){ // dataSource.setMaxIdle(Integer.parseInt(params.get(OPTION_MAX_IDLE))); // } else { // dataSource.setMaxIdle(5); // } // if(params.get(OPTION_INIT_SIZE) != null){ // dataSource.setInitialSize(Integer.parseInt(params.get(OPTION_INIT_SIZE))); // } else { // dataSource.setInitialSize(2); // } // 连接池 if(params.get(OPTION_MAX_ACTIVE) != null){ ds.setMaximumPoolSize(Integer.parseInt(params.get(OPTION_MAX_ACTIVE))); } else { ds.setMaximumPoolSize(10); } if(params.get(OPTION_INIT_SIZE) != null){ ds.setMinimumIdle(Integer.parseInt(params.get(OPTION_INIT_SIZE))); } else { ds.setMinimumIdle(2); } ds.setIdleTimeout(300); ds.setConnectionTimeout(12000);*/ // 2023-05-08 使用平台数据源。 // DataSource dataSource = (DataSource) JdbcInspector.getInstance().getPrimaryDataSourceMeta(); DataSource ds = this.acquireDruidDataSource(params); jdbcTemplate = new JdbcTemplate(ds); namedJdbcTemplate = new NamedParameterJdbcTemplate(ds); this.dataSource = ds; } protected DataSource acquireDruidDataSource(Map params){ MyDruidDataSource druidDataSource = new MyDruidDataSource(); druidDataSource.setIp(getUrl()); druidDataSource.setPort(getPort()); druidDataSource.setDatabaseType(this.getDatabaseType().getTypeIndex()); druidDataSource.setDatabaseName(getServiceName()); druidDataSource.setUsername(params.get(OPTION_USER)); druidDataSource.setPassword(params.get(OPTION_PASSWORD)); if(params.get(OPTION_MAX_ACTIVE) != null){ druidDataSource.setMaxActive(Integer.parseInt(params.get(OPTION_MAX_ACTIVE))); } else { druidDataSource.setMaxActive(20); } if(params.get(OPTION_INIT_SIZE) != null){ druidDataSource.setInitialSize(Integer.parseInt(params.get(OPTION_INIT_SIZE))); } else { druidDataSource.setInitialSize(5); } druidDataSource.setMinIdle(10); druidDataSource.setMaxWait(60000); druidDataSource.setTimeBetweenEvictionRunsMillis(60000); druidDataSource.setMinEvictableIdleTimeMillis(30000); druidDataSource.setMaxEvictableIdleTimeMillis(180000); druidDataSource.setValidationQuery("select 1"); druidDataSource.setTestWhileIdle(true); druidDataSource.setTestOnBorrow(false); druidDataSource.setTestOnReturn(false); druidDataSource.setMaxOpenPreparedStatements(64); return druidDataSource; } @Override public void destroy() { // if(dataSource != null){ // try { // if(dataSource instanceof DefaultDataSource){ // ((DefaultDataSource)dataSource).close(); // } // } catch (Exception e) { // logger.error("销毁 DatabaseConnector 失败:" + ((DefaultDataSource) dataSource).getDatabaseName(), e); // } // } } /** * 返回数据库类型,子类实现 * @return */ protected abstract DatabaseType getDatabaseType(); }