All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bixuebihui.jdbc.DbHelper Maven / Gradle / Ivy

Go to download

a fast small database connection pool and a active record flavor mini framework

There is a newer version: 1.15.3.3
Show newest version
package com.bixuebihui.jdbc;

import com.bixuebihui.DbException;
import com.bixuebihui.util.DbUtils;
import javax.validation.constraints.NotNull;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.sql.*;
import java.sql.Date;
import java.util.*;


/**
 * 

DbHelper class.

* * @author xingwx * @version $Id: $Id */ public class DbHelper implements IDbHelper { private static final Logger LOG = LoggerFactory.getLogger(DbHelper.class); private Connection connection = null; private DataSource dataSource = null; /** *

Constructor for DbHelper.

*/ public DbHelper() { // use this constructor } /** * for test only, not use in real application * * @param cn db connection */ public DbHelper(Connection cn) { connection = cn; } /** *

freeConnection.

* * @param cn a {@link java.sql.Connection} object. */ public static void freeConnection(Connection cn) { try { cn.close(); } catch (SQLException e) { throw new DbException(e); } } /** * public java.sql.Result exeSql(String strSQl) { *

* return new Result(); } * * @param stmt statement to be closed */ public static void close(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { LOG.error("", e); } } } /** *

close.

* * @param rs a {@link java.sql.ResultSet} object. */ public static void close(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { LOG.error("", e); } } } /** *

close.

* * @param conn a {@link java.sql.Connection} object. */ public static void close(Connection conn) { try { if (conn != null && !conn.isClosed()) { freeConnection(conn); } } catch (SQLException e) { LOG.error("", e); } } private static void dumpSql(SQLException ex, String sql, Object[] params) { if(LOG.isWarnEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(ex.getMessage()).append("\n"); sb.append("===" + sql).append("\n"); if (params != null) { for (Object o : params) { sb.append("===" + o).append("\n"); } } LOG.warn(sb.toString()); } } private static void dumpSql(Exception ex, String[] sql) { if(LOG.isWarnEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(ex.getMessage()).append("\n"); for (String s : sql) { sb.append("==" + s).append("\n"); } LOG.warn(sb.toString()); } } public static String clob2Str(Clob clobObject) { InputStream in; try { in = clobObject.getAsciiStream(); StringWriter w = new StringWriter(); IOUtils.copy(in, w, Charset.defaultCharset()); return w.toString(); } catch (SQLException | IOException e) { throw new DbException(e); } } /** * {@inheritDoc} */ @Override public DataSource getDataSource() { return dataSource; } /** * {@inheritDoc} */ @Override public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } // 用于事务处理 /** *

Getter for the field connection.

* * @return a {@link java.sql.Connection} object. */ @Override public Connection getConnection() throws DbException { try { return connection != null ? connection : dataSource.getConnection(); } catch (SQLException e) { throw new DbException(e); } } // 用于事务处理 /** * {@inheritDoc} *

* this method for subclass override */ @Override public Connection getConnection(boolean readOnly) { return getConnection(); } /** * {@inheritDoc} */ @Override public void close() { if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } /** * do not use this if you don't know what to do... * because it leading to resource leaking * * @param sql sql * @param cn connection * @return ResultSet must closed after using * @deprecated ResultSet must closed, before close the connection, is not recommend to use this */ @Deprecated public ResultSet executeQuery(String sql, @NotNull Connection cn) { ResultSet rs; try (Statement stmt = cn.createStatement()) { rs = stmt.executeQuery(sql); } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } return rs; } /** *

executeNoQuery.

* * @param sql a {@link java.lang.String} object. * @return a int. */ @Override public int executeNoQuery(String sql) { Connection cn = this.getConnection(false); try (Statement stmt = cn.createStatement()) { return stmt.executeUpdate(sql); } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } finally { close(cn); } } /* * (non-Javadoc) * * @see com.bixuebihui.zichan.dal.IDbHelper#executeQuery(java.lang.String, * com.bixuebihui.util.db.RowCallbackHandler) */ /** *

executeNoQuery.

* * @param sql a {@link java.lang.String} object. * @param cn a {@link java.sql.Connection} object. * @return a int. */ public int executeNoQuery(String sql, @NotNull Connection cn) { try (Statement stmt = cn.createStatement()) { return stmt.executeUpdate(sql); } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } } /** * {@inheritDoc} */ @Override public int executeNoQueryBatch(String strSql, Iterable params) { return executeNoQueryBatch(strSql, params, null); } /** * {@inheritDoc} */ @Override public int executeNoQueryBatch(String strSql, int total, ParamsIterator.CurrentParameters cur, Connection cn) { return executeNoQueryBatch(strSql, new ParamsIterator(total, cur), cn); } /** * {@inheritDoc} */ @Override public Object executeScalar(String strSql) { return executeScalarSession(strSql, null); } /** *

executeNoQuery.

* * @param sql an array of {@link java.lang.String} objects. * @return a count of influenced records. */ @Override public int executeNoQuery(String[] sql) { Connection cn = this.getConnection(false); try { cn.setAutoCommit(false); } catch (SQLException e) { LOG.warn("", e); } int n = 0; try (Statement stmt = cn.createStatement()) { for (String s : sql) { if (StringUtils.isNotBlank(s)) { n += stmt.executeUpdate(s); } } cn.commit(); } catch (SQLException ex) { try { cn.rollback(); } catch (SQLException e) { LOG.warn("", e); } dumpSql(ex, sql); throw new DbException(ex); } finally { try { cn.setAutoCommit(true); } catch (SQLException e) { LOG.warn("", e); } close(cn); } return n; } /** * 批量在事条里执行SQL语句数组 * * @param sqls 批量在事条里执行SQL语句数组 * @return 每一个SQL执行结果的数组 */ public int[] executeUpdate(String[] sqls) { if (sqls == null || sqls.length < 1) { return new int[0]; } Connection cn = getConnection(false); int[] j = new int[sqls.length]; int step = -1; try { cn.setAutoCommit(false); try (Statement oStmt = cn.createStatement()) { for (int i = 0; i < sqls.length; i++) { j[i] = oStmt.executeUpdate(sqls[i]); //NOSONAR step = i; } cn.commit(); } } catch (SQLException e) { try { cn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } DbException ex = new DbException("执行SQL语句出错" + (step < 0 ? "" : ":" + sqls[step]) + " DbHelper.ExecuteUpdate" + e.getMessage()); dumpSql(ex, sqls); throw ex; } finally { close(cn); } return j; } /** * {@inheritDoc} */ @Override public @NotNull List> exeQuery(String sql) { Connection cn = getConnection(true); try (Statement stmt = cn.createStatement(); ResultSet rset = stmt.executeQuery(sql)) { return resultSet2Vector(rset); } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } finally { close(cn); } } /** *

executeNoQuery.

* * @param strSql an array of {@link java.lang.String} objects. * @param cn a {@link java.sql.Connection} object. * @return a int. */ @Override public int executeNoQuery(String[] strSql, @NotNull Connection cn) { int n = 0; try (Statement stmt = cn.createStatement()) { for (String s : strSql) { if (!StringUtils.isNotBlank(s)) { continue; } n += stmt.executeUpdate(s); } } catch (SQLException ex) { dumpSql(ex, strSql); throw new DbException(ex); } return n; } /** * {@inheritDoc} */ @Override public int executeNoQuery(String sql, Object[] params, @NotNull Connection cn) { try (Statement p = ArrayUtils.isEmpty(params) ? cn.createStatement() : cn.prepareStatement(sql)) { if (p instanceof PreparedStatement) { PreparedStatement pre = (PreparedStatement) p; this.fillParameter((PreparedStatement) p, params, null); return pre.executeUpdate(); } else { return p.executeUpdate(sql); } } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } } /** * {@inheritDoc} *

* 批处里数组, 用于Insert, delete或update */ @Override public int executeNoQueryBatch(String sql, Iterable params, Connection cn) { boolean needRelease = false; if (cn == null) { cn = this.getConnection(false); needRelease = true; } int n; try (PreparedStatement p = cn.prepareStatement(sql)) { for (Object[] param : params) { this.fillParameter(p, param, null); p.addBatch(); } int[] updateCounts = p.executeBatch(); p.getGeneratedKeys(); n = updateCounts.length; // updateCounts[0] A number greater than or equal to zero -- indicates that the // * command was processed successfully and is an update count giving the // * number of rows in the database that were affected by the command's // * execution } catch (SQLException ex) { for (Object[] ps : params) { dumpSql(ex, sql, ps); } throw new DbException(ex); } finally { if (needRelease) { close(cn); } } return n; } /** * {@inheritDoc} */ @Override public void executeQuery(String sql, RowCallbackHandler handle) { Connection cn = this.getConnection(true); try (Statement stmt = cn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { handle.processRow(rs); } } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } finally { close(cn); } } /** * (non-Javadoc) * * @param cn connection * @param sql sql语句 * @return single object, may be integer or string * @see IDbHelper#executeScalar(java.lang.String) */ public Object executeScalarSession(String sql, Connection cn) { boolean localCn = cn == null; cn = localCn ? this.getConnection(true) : cn; try ( Statement stmt = cn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { if (rs.next()) { return rs.getObject(1); } return null; } catch (SQLException ex) { dumpSql(ex, sql, null); throw new DbException(ex); } finally { if (localCn) { close(cn); } } } /** *

resultSet2Vector.

* * @param rs a {@link java.sql.ResultSet} object. * @return a {@link java.util.List} object. */ public @NotNull List> resultSet2Vector(ResultSet rs) { List> result = new ArrayList<>(); try { if (!rs.isBeforeFirst()) { return result; } ResultSetMetaData metaData = rs.getMetaData(); int iColumnNumber = metaData.getColumnCount(); while (rs.next()) { Map mapColumn = new HashMap<>(32); for (int i = 1; i <= iColumnNumber; i++) { String colTypeName = metaData.getColumnTypeName(i).toUpperCase(); String colName = metaData.getColumnName(i); if (!StringUtils.isBlank(metaData.getColumnLabel(i))) { colName = metaData.getColumnLabel(i); } if (mapColumn.containsKey(colName) && rs.getObject(i) == null) { //同一列名的已存在且不为空,则保留当前值,用于多表联合查询,但后表无记录的情况 continue; } switch (colTypeName) { case "NUMBER": case "INT": case "INTEGER": case "TINYINT": case "TINYINT UNSIGNED": case "INTEGER IDENTITY": case "COUNTER": case "NUMERIC": case "DECIMAL": case "MEDIUMINT": case "INT UNSIGNED": case "MEDIUMINT UNSIGNED": dealNumber(rs, metaData, mapColumn, i, colTypeName, colName); break; case "BIGINT": case "BIGINT UNSIGNED": mapColumn.put(colName, rs.getLong(i)); break; case "SMALLINT": mapColumn.put(colName, rs.getInt(i)); break; case "VARCHAR2": case "VARCHAR": case "NVARCHAR2": case "NVARCHAR": case "TEXT": case "MEDIUMTEXT": case "LONGTEXT": case "CHAR": case "NTEXT": case "NCHAR": case "LONGVARCHAR": case "LONGCHAR": { String temp = rs.getString(i); if (temp == null) { temp = ""; } mapColumn.put(colName, temp); break; } case "DATETIME": case "TIMESTAMP": // 10.17 if (rs.getTimestamp(i) != null) { mapColumn.put(colName, rs.getTimestamp(i)); } else { // 1970 year Timestamp d1970 = new Timestamp(0); mapColumn.put(colName, d1970); } break; case "DATE": java.util.Date dt = rs.getDate(i); if (dt != null) { Timestamp tm = new Timestamp( dt.getTime()); mapColumn.put(colName, tm); } else { Timestamp d1970 = new Timestamp(0); mapColumn.put(colName, d1970); } break; case "LONG": { String temp = ""; byte[] mybyte = rs.getBytes(i); if (mybyte != null) { temp = new String(mybyte, Charset.defaultCharset()); } mapColumn.put(colName, temp); break; } case "RAW": case "VARCHAR () FOR BIT DATA": byte[] bb = rs.getBytes(i); mapColumn.put(colName, bb == null ? new byte[0] : bb); break; case "CLOB": { String temp = clob2Str(rs.getClob(i)); mapColumn.put(colName, temp); break; } case "BOOL": case "BIT": { Boolean temp = rs.getBoolean(i); mapColumn.put(colName, temp); break; } case "FLOAT": { Float temp = rs.getFloat(i); mapColumn.put(colName, temp); break; } case "DOUBLE": { Double temp = rs.getDouble(i); mapColumn.put(colName, temp); break; } default: mapColumn.put(colName, rs.getObject(i)); String string = " -colName:"; LOG.warn( "Unknow data type, ask [email protected] for adding this to DbHelper.resultSet2Vector colTypeName: " + colTypeName + string + colName); break; } } result.add(mapColumn); } return result; } catch (SQLException ex) { dumpSql(ex, "", null); throw new DbException(ex); } } private void dealNumber(ResultSet rset, ResultSetMetaData rsmdQuery, Map columnMap, int i, String colTypeName, String colName) throws SQLException { if ("TINYINT".equals(colTypeName) && rsmdQuery.getPrecision(i) == 1) { columnMap.put(colName, rset.getBoolean(i)); } else if ("TINYINT".equals(colTypeName) || "TINYINT UNSIGNED".equals(colTypeName)) { columnMap.put(colName, rset.getByte(i)); } else if (rsmdQuery.getScale(i) <= 0) { // BigDecimal or Integer if (rset.getObject(i) instanceof BigDecimal) { BigDecimal a = (BigDecimal) rset.getObject(i); if (a.scale() > 0 || a.compareTo(new BigDecimal( Integer.MAX_VALUE)) > 0) { columnMap.put(colName, rset.getObject(i)); } else { columnMap.put(colName, rset.getInt(i)); } } else if (rsmdQuery.getPrecision(i) > 9) { columnMap.put(colName, rset.getLong(i)); } else { columnMap.put(colName, rset.getInt(i)); } } else { columnMap.put(colName, rset.getDouble(i)); } } /** *

executeScalar.

* * @param sql a {@link java.lang.String} object. * @param params an array of {@link java.lang.Object} objects. * @return a {@link java.lang.Object} object. */ @Override public Object executeScalar(String sql, Object[] params) { return executeScalar(sql, params, null); } /** *

fillParameter.

* * @param p a {@link java.sql.PreparedStatement} object. * @param params an array of {@link java.lang.Object} objects. * @throws SQLException if any */ public void fillParameter(PreparedStatement p, Object[] params) throws SQLException { fillParameter(p, params, null); } /** * {@inheritDoc} */ @Override public Object executeScalar(String sql, Object[] params, Connection cn) { if (params == null || params.length == 0) { return executeScalarSession(sql, cn); } boolean localCn = cn == null; cn = localCn ? this.getConnection(true) : cn; try (PreparedStatement p = cn.prepareStatement(sql)) { fillParameter(p, params, null); try (ResultSet rs = p.executeQuery()) { if (rs.next()) { return rs.getObject(1); } } } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } finally { if (localCn) { close(cn); } } return null; } /** *

fillParameter.

* * @param p a {@link java.sql.PreparedStatement} object. * @param params an array of {@link java.lang.Object} objects. * @param targetSqlTypes an array of int objects. * @throws SQLException 数据库出错 */ public void fillParameter(PreparedStatement p, Object[] params, int[] targetSqlTypes) throws SQLException { if (ArrayUtils.isEmpty(params)) { return; } if (ArrayUtils.isNotEmpty(targetSqlTypes) && targetSqlTypes.length != params.length) { throw new DbException( "Intenal error: The params and the targetSqlTypes must have same length!"); } if (ArrayUtils.isNotEmpty(targetSqlTypes)) { for (int i = 1; i <= params.length; i++) { p.setObject(i, params[i - 1], targetSqlTypes[i - 1]); } } else { for (int i = 1; i <= params.length; i++) { Object pa = params[i - 1]; if (pa == null) { p.setNull(i, java.sql.Types.VARCHAR, "String"); LOG.debug("不支持空数据(参数[" + i + "])! Null is not support in DbHelper.executeNoQuery(String sql, Object[] params), there may be error!"); } else if (pa instanceof Integer) { p.setInt(i, (Integer) pa); } else if (pa instanceof Long) { p.setLong(i, (Long) pa); } else if (pa instanceof java.sql.Timestamp) { p.setTimestamp(i, (Timestamp) pa); } else if (pa instanceof java.sql.Date) { p.setDate(i, (Date) pa); }else if (pa instanceof java.sql.Time) { p.setTime(i, (Time) pa); } else if (pa instanceof java.util.Date) { p.setTimestamp(i, new java.sql.Timestamp(((java.util.Date) pa).getTime())); } else if (pa instanceof Double) { p.setDouble(i, (Double) pa); } else if (pa instanceof String) { p.setString(i, ((String) pa)); } else if (pa instanceof ClobString) { p.setObject(i, pa.toString()); } else { p.setObject(i, pa); } } } } /** * 用于执行带参数的非查询语句 * * @param sql 参数化sql语句 * @param params 参数 * @return (字段)) 结果集 */ @Override public List> executeQuery(String sql, Object[] params) { Connection cn = getConnection(true); ResultSet rs = null; try (Statement p = ArrayUtils.isEmpty(params) ? cn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY) : cn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY) ) { if (p instanceof PreparedStatement) { fillParameter((PreparedStatement) p, params); rs = ((PreparedStatement) p).executeQuery(); } else { rs = p.executeQuery(sql); } return this.resultSet2Vector(rs); } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } finally { close(rs); close(cn); } } /** *

executeNoQuery.

* * @param sql a {@link java.lang.String} object. * @param params an array of {@link java.lang.Object} objects. * @param targetSqlTypes an array of int objects. * @return a int. */ @Override public int executeNoQuery(String sql, Object[] params, int[] targetSqlTypes) { return executeNoQuery(sql, params, targetSqlTypes, null); } /** * {@inheritDoc} */ @Override public int executeNoQuery(String sql, Object[] params, int[] targetSqlTypes, Connection conn) { boolean localCn = conn == null; Connection cn = localCn ? getConnection(false) : conn; try (Statement p = ArrayUtils.isNotEmpty(params) ? cn.prepareStatement(sql) : cn.createStatement()) { if (p instanceof PreparedStatement) { fillParameter((PreparedStatement) p, params, targetSqlTypes); ((PreparedStatement) p).execute(); } else { p.execute(sql); } return p.getUpdateCount(); } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } finally { if (localCn) { close(cn); } } } /** * {@inheritDoc} */ @Override public long insertAndFetchLastId(String sql, Object[] params, int[] targetSqlTypes, Connection conn) { boolean localCn = conn == null; Connection cn = localCn ? getConnection(false) : conn; try (PreparedStatement p = cn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { if (ArrayUtils.isNotEmpty(params)) { fillParameter(p, params, targetSqlTypes); } p.execute(); ResultSet rs = p.getGeneratedKeys(); if (rs != null && rs.next()) { return Long.parseLong(rs.getObject(1).toString()); } return 0; } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } finally { if (localCn) { close(cn); } } } /** *

executeNoQuery.

* * @param sql a {@link java.lang.String} object. * @param params an array of {@link java.lang.Object} objects. * @return a int. */ @Override public int executeNoQuery(String sql, Object[] params) { return executeNoQuery(sql, params, new int[0]); } /** *

executeQuery.

* * @param sql a {@link java.lang.String} object. * @param params an array of {@link java.lang.Object} objects. * @param handle a {@link RowCallbackHandler} object. */ @Override public void executeQuery(String sql, Object[] params, RowCallbackHandler handle) { Connection cn = getConnection(true); try (Statement p = ArrayUtils.isNotEmpty(params) ? cn.prepareStatement(sql) : cn.createStatement()) { if (p instanceof PreparedStatement) { fillParameter((PreparedStatement) p, params, null); } try (ResultSet rs = (p instanceof PreparedStatement) ? ((PreparedStatement) p).executeQuery() : p.executeQuery(sql)) { while (rs.next()) { handle.processRow(rs); } } } catch (SQLException ex) { dumpSql(ex, sql, params); throw new DbException(ex); } finally { DbUtils.closeQuietly(cn); } } /** * {@inheritDoc} */ @Override public @NotNull List executeQuery(String sql, Object[] params, @NotNull RowMapperResultReader handle) { return executeQuery(sql, params, handle, null); } /** * {@inheritDoc} */ @Override public @NotNull List executeQuery(String sql, Object[] params, @NotNull RowMapperResultReader handle, Set returnFields) { Connection cn = getConnection(true); try (Statement p = ArrayUtils.isNotEmpty(params) ? cn.prepareStatement(sql) : cn.createStatement()) { if (p instanceof PreparedStatement) { fillParameter((PreparedStatement) p, params, null); } try (ResultSet rs = (p instanceof PreparedStatement) ? ((PreparedStatement) p).executeQuery() : p.executeQuery(sql)) { return handle.processResultSet(rs, returnFields); } } catch (SQLException ex) { //可能超时,输出sql和参数 dumpSql(ex, sql, params); throw new DbException(ex); } finally { DbUtils.closeQuietly(cn); } } @Override public @NotNull List executeQuery(String sql, Object[] params, @NotNull RowMapper handle) { return executeQuery( sql, params, new RowMapperResultReader<>(handle)); } @Override public @NotNull List executeQuery(String sql, Object[] params, @NotNull RowMapper handle, Set returnFields) { return executeQuery( sql, params, new RowMapperResultReader<>(handle), returnFields); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy