package com.ynxbd.common.config.db; import com.alibaba.druid.filter.Filter; import com.alibaba.druid.filter.stat.StatFilter; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallFilter; import com.ynxbd.common.helper.ProperHelper; import com.ynxbd.common.helper.common.ErrorHelper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.lang3.ObjectUtils; import java.lang.reflect.Field; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j public class DataBase { @FunctionalInterface public interface IPS { void setParams(PreparedStatement ps) throws SQLException; } static { // 解决BigDecimal类型转化报错 BeanUtilsBean.getInstance().getConvertUtils().register(false, false, 0); dataSource = init(); } private static DruidDataSource dataSource; protected synchronized static ProperHelper getConfig() { return new ProperHelper().read("druid-config.properties"); } private static synchronized DruidDataSource init() { if (dataSource != null) { return dataSource; } final DruidDataSource dataSource = new DruidDataSource(); try { ProperHelper config = getConfig(); dataSource.setDriverClassName(config.getString("master.driverClassName")); dataSource.setUrl(config.getString("master.jdbcUrl")); dataSource.setUsername(config.getString("master.username")); dataSource.setPassword(config.getString("master.password")); // 连接池配置 Integer min = config.getInteger("master.minIdle"); if (min != null) { dataSource.setMinIdle(min); } Integer max = config.getInteger("master.maxActive"); if (max != null) { dataSource.setMaxActive(max); } Integer initialSize = config.getInteger("master.initialSize"); if (initialSize != null) { dataSource.setInitialSize(initialSize); } dataSource.setMaxWait(60 * 1000); // 60s // 异步初始化连接 // dataSource.addDataSourceProperty("serverTimezone", ZoneId.systemDefault()); dataSource.setAsyncInit(true); dataSource.setValidationQuery("SELECT 1"); // 安全性 dataSource.setTestWhileIdle(true); dataSource.setTestOnBorrow(false); dataSource.setTestOnReturn(false); // 打开PSCache,并且指定每个连接上PSCache的大小 dataSource.setPoolPreparedStatements(true); dataSource.setMaxPoolPreparedStatementPerConnectionSize(120); // 连接泄露检查 dataSource.setRemoveAbandonedTimeoutMillis(300000); // 关闭连接时输出错误日志,这样出现连接泄露时可以通过错误日志定位忘记关闭连接的位置 dataSource.setLogAbandoned(true); dataSource.setMinEvictableIdleTimeMillis(300000); // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 dataSource.setTimeBetweenConnectErrorMillis(60000); dataSource.setFilters("stat,wall"); // statFilter---------------------------- StatFilter statFilter = new StatFilter(); statFilter.setDbType("mysql"); statFilter.setLogSlowSql(true); statFilter.setSlowSqlMillis(3000); WallConfig wallConfig = new WallConfig(); // 允许执行多条语句 wallConfig.setMultiStatementAllow(true); wallConfig.setNoneBaseStatementAllow(true); // 禁止创建表 wallConfig.setCreateTableAllow(false); // 禁止修改表 wallConfig.setDropTableAllow(false); // 禁止执行Alter Table语句 wallConfig.setAlterTableAllow(false); // wallFilter----------------------------- WallFilter wallFilter = new WallFilter(); wallFilter.setDbType("mysql"); wallFilter.setConfig(wallConfig); List filters = new ArrayList<>(); filters.add(statFilter); filters.add(wallFilter); dataSource.setProxyFilters(filters); } catch (SQLException e) { e.printStackTrace(); } return dataSource; } /** * 获取连接 */ public static Connection getConnection() { Connection conn = null; try { if (dataSource == null) { dataSource = init(); } conn = dataSource.getConnection(); } catch (SQLException e) { log.error("MySQL数据库连接失败!{}, {}", dataSource.getUrl(), e.getMessage()); if (dataSource != null) { dataSource.close(); dataSource = null; } } return conn; } /** * prepareStatement 赋值查询 * * @param clazz 集合类型 * @param ips 设置占位符数据 * @param 泛型 * @return 集合 */ public static List select(String sql, Class clazz, IPS ips) { return select(getConnection(), sql, clazz, ips); } /** * 拼接sql语句查询 * * @param sql SQL语句 * @param clazz 集合类型 * @param 泛型 * @return 泛型集合 */ public static List select(String sql, Class clazz) { return select(getConnection(), sql, clazz, null); } /** * 拼接sql语句查询 * * @param sql SQL语句 * @param clazz 集合类型 * @param 泛型 * @return 泛型集合 */ public static T selectOne(String sql, Class clazz, IPS ips) { List dataList = select(getConnection(), sql, clazz, ips); int size = dataList.size(); if (size == 1) { return dataList.get(0); } if (size > 1) { throw new RuntimeException("select one but fount " + size); } return null; } /** * [私有]查询方法封装 * * @param conn 连接 * @param sql sql语句 * @param clazz 类 * @param ips ips */ protected static List select(Connection conn, String sql, Class clazz, IPS ips) { List list = new ArrayList<>(); if (ips == null) { Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery(sql); list = executeSelect(clazz, rs); } catch (Exception e) { ErrorHelper.println(e); } finally { close(rs, stmt, conn); } } else { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); ips.setParams(ps); rs = ps.executeQuery(); list = executeSelect(clazz, rs); } catch (Exception e) { ErrorHelper.println(e); } finally { close(rs, ps, conn); } } return list; } /** * 核心-执行查询 * * @param clazz 类型 * @param rs rs * @return 集合 */ private static List executeSelect(Class clazz, ResultSet rs) throws Exception { List list = new ArrayList<>(); Field[] fields = clazz.getDeclaredFields(); Class superclass = clazz.getSuperclass(); Field[] superFields = {}; if (superclass != null) { superFields = superclass.getDeclaredFields(); } T bean; ResultSetMetaData rmd; String colName; Object value; Class valClazz; boolean isBreak; while (rs.next()) { bean = clazz.newInstance(); rmd = rs.getMetaData(); for (int i = 1; i <= rmd.getColumnCount(); i++) { colName = rmd.getColumnLabel(i).toLowerCase(); value = rs.getObject(i); if (value == null) { continue; } valClazz = value.getClass(); isBreak = false; for (Field f : fields) { f.setAccessible(true); if (f.getName().toLowerCase().equals(colName)) { isBreak = true; if (java.time.LocalDateTime.class == valClazz && java.time.LocalDateTime.class != f.getType()) { BeanUtils.setProperty(bean, f.getName(), rs.getTimestamp(i)); } else { BeanUtils.setProperty(bean, f.getName(), value); } break; } } if (isBreak) { continue; } for (Field f : superFields) { f.setAccessible(true); if (f.getName().toLowerCase().equals(colName)) { if (java.time.LocalDateTime.class == valClazz && java.time.LocalDateTime.class != f.getType()) { BeanUtils.setProperty(bean, f.getName(), rs.getTimestamp(i)); } else { BeanUtils.setProperty(bean, f.getName(), value); } break; } } } list.add(bean); } return list; } /** * 查询count * * @param sql SQL语句 * @param ips 通过匿名函数设定占位符,可为空 * @return clazz类型的数据 */ public static int selectCount(String sql, IPS ips) { int count = 0; Connection conn = getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); if (ips != null) ips.setParams(ps); rs = ps.executeQuery(); if (rs.next()) { count = rs.getInt(1); } } catch (Exception e) { ErrorHelper.println(e); } finally { close(rs, ps, conn); } return count; } /** * 查询某列 * * @param sql SQL语句 * @param clazz 指定查询的数据的类型 * @param ips 通过匿名函数设定占位符,可为空 * @return clazz类型的数据 */ public static T selectByColumn(String sql, Class clazz, IPS ips) { Connection conn = getConnection(); PreparedStatement ps = null; ResultSet rs = null; T value = null; try { ps = conn.prepareStatement(sql); if (ips != null) ips.setParams(ps); rs = ps.executeQuery(); if (rs.next()) { value = rs.getObject(1, clazz); } } catch (Exception e) { ErrorHelper.println(e); } finally { close(rs, ps, conn); } return value; } /** * 查询单个数据,主要用于count等单个字段的查询 * * @param sql SQL语句 * @param clazz 指定查询的数据的类型 * @return clazz类型的数据 */ public static T selectByColumn(String sql, Class clazz) { return selectByColumn(sql, clazz, null); } /** * 添加成功后返回自增ID * * @param sql SQL语句 * @param ips ips * @return 自增ID */ public static int insertGetId(String sql, IPS ips) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; int id = 0; try { conn = getConnection(); ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); if (ips != null) ips.setParams(ps); ps.executeUpdate(); rs = ps.getGeneratedKeys(); if (rs.next()) { id = rs.getInt(1); } ps.clearBatch(); } catch (SQLException e) { ErrorHelper.println(e); try { conn.rollback(); } catch (SQLException err) { ErrorHelper.println(err); } return 0; } finally { close(rs, ps, conn); } return id; } // public static void main(String[] args) { // List testList = new ArrayList<>(); // for (int i = 0; i < 500; i++) { // testList.add(String.valueOf(i)); // } // long begTime = System.currentTimeMillis(); // 开始时间 // String sql = "insert into a (a, date, time, dateTime,timesTamp) values(?, now(), now(), now(), now())"; // DataBase.insertBatch(sql, ps -> { // for (int i = 0; i < testList.size(); i++) { // if (i == 100) { // ps.setString(1, String.valueOf((1 / 0))); // } else { // System.out.println("Add"); // ps.setString(1, testList.get(i)); // } // ps.addBatch(); // } // }); // // long endTime = System.currentTimeMillis(); // 结束时间 // log.info("耗时:{}", ((endTime - begTime) / 1000) + "s(" + (endTime - begTime) + "ms)"); // } /** * 插入数据 * * @param sql SQL语句 * @param ips 设置占位符数据 * @return 修改成功行数 */ public static int insertBatch(String sql, IPS ips) { int rows = 0; try (Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { conn.setAutoCommit(false); if (ips != null) ips.setParams(ps); rows = ps.executeBatch().length; ps.clearBatch(); conn.commit(); } catch (Exception e) { ErrorHelper.println(e); } return rows; } /** * 插入数据 * * @param sql SQL语句 * @param ips 设置占位符数据 * @return 修改成功行数 */ public static int insert(String sql, IPS ips) { return update(sql, ips); } /** * 插入数据 * * @param sql SQL语句 * @param ips 设置占位符数据 * @return 修改成功行数 */ public static int delete(String sql, IPS ips) { return update(sql, ips); } /** * 增、删、改 * * @param sql SQL语句 * @param ips 设置占位符数据 * @return 修改成功行数 */ public static int update(String sql, IPS ips) { int rows = 0; try (Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { if (ips != null) ips.setParams(ps); rows = ps.executeUpdate(); } catch (Exception e) { ErrorHelper.println(e); } return rows; } /** * 关闭数据库 * * @param conn 数据库连接 */ public static void close(Connection conn) { close(null, null, conn); } public static void close(Statement stat, Connection conn) { close(null, stat, conn); } public static void close(ResultSet rs, Connection conn) { close(rs, null, conn); } /** * 关闭连接-先开后关 * * @param rs rs * @param stat ps * @param conn conn */ public static void close(ResultSet rs, Statement stat, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { ErrorHelper.println(e); } } if (stat != null) { try { stat.close(); } catch (SQLException e) { ErrorHelper.println(e); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { ErrorHelper.println(e); } } } public static int updateBatch(String tableName, Map>> setCaseList, List ids) { return updateBatch(tableName, null, setCaseList, null, ids); } /** * 批量修改 * * @param tableName 表名 * @param setMap 统一修改的值 * @param setByCaseList 分批修改的值 * @param whereMap 条件 * @param ids 条件集 */ public static int updateBatch(String tableName, Map setMap, Map>> setByCaseList, Map whereMap, List ids) { StringBuilder sb = new StringBuilder(); if (tableName == null || "".equals(tableName)) { return 0; } if (setByCaseList == null || setByCaseList.size() == 0 || ids == null || ids.size() == 0) { return 0; } sb.append("update ").append(tableName).append(" set "); int mapIndex = 0; Object value; if (setMap != null) { for (Map.Entry entry : setMap.entrySet()) { value = entry.getValue(); if (value != null && !"now()".equals(value)) { value = "'" + value + "'"; } sb.append(entry.getKey()).append("=").append(value); if ((mapIndex + 1) != setMap.entrySet().size()) { sb.append(","); } mapIndex++; } } if (setMap != null && setMap.entrySet().size() != 0) { sb.append(","); } mapIndex = 0; String key; List> valMapList; Map valMap; for (Map.Entry>> entry : setByCaseList.entrySet()) { key = entry.getKey(); valMapList = entry.getValue(); if (ObjectUtils.isEmpty(key) || valMapList == null || valMapList.size() == 0) { continue; } sb.append(key).append("= case id"); for (int i = 0; i < valMapList.size(); i++) { valMap = valMapList.get(i); for (Map.Entry item : valMap.entrySet()) { value = item.getValue(); if (value != null && !"now()".equals(value)) { value = "'" + value + "'"; } sb.append(" when ").append(item.getKey()).append(" then ").append(value); } if ((i + 1) == valMapList.size()) { sb.append(" end "); } } if ((mapIndex + 1) != setByCaseList.entrySet().size()) { sb.append(","); } mapIndex++; } mapIndex = 0; if (whereMap != null) { for (Map.Entry entry : whereMap.entrySet()) { if (mapIndex == 0) { sb.append(" where ").append(entry.getKey()).append("='").append(entry.getValue()).append("'"); } else { sb.append(" and ").append(entry.getKey()).append("='").append(entry.getValue()).append("'"); } mapIndex++; } } sb.append(" ").append(mapIndex == 0 ? "where" : "and").append(" id in ("); for (int i = 0; i < ids.size(); i++) { sb.append(ids.get(i)); if ((i + 1) != ids.size()) { sb.append(","); } } sb.append(")"); String sql = sb.toString(); log.info("sql={}", sql); if ("".equals(sb.toString())) { return 0; } return update(sql, null); } }