diff --git a/core/src/main/java/com/github/drinkjava2/jdbpro/DbPro.java b/core/src/main/java/com/github/drinkjava2/jdbpro/DbPro.java index 91c65a850128c691635e8688f64e40e022b5ec77..e50e4a00bad4d4fdc26324598da845ca983651d7 100644 --- a/core/src/main/java/com/github/drinkjava2/jdbpro/DbPro.java +++ b/core/src/main/java/com/github/drinkjava2/jdbpro/DbPro.java @@ -34,429 +34,433 @@ import com.github.drinkjava2.jdialects.Dialect; /** * DbPro is the enhanced version of Apache Commons DbUtils's QueryRunner, add * below improvements: - * + * *
  * 1)Use ConnectionManager to manage connection for better transaction support
  * 2)normal style methods but no longer throw SQLException, methods named as nXxxxx() format
  * 3)In-line style methods, methods named as iXxxxx() format
  * 4)SQL Template style methods, methods named as tXxxxx() format
  * 
- * + * * @author Yong Zhu * @since 1.7.0 */ -@SuppressWarnings({ "unchecked", "rawtypes" }) +@SuppressWarnings({"unchecked", "rawtypes"}) public class DbPro extends ImprovedQueryRunner implements NormalJdbcTool {// NOSONAR - public DbPro() { - super(); - } - - public DbPro(DataSource ds) { - super(ds); - } - - public DbPro(DataSource ds, Dialect dialect) { - super(ds, dialect); - } - - /** - * Quite execute a SQL, do not throw any exception, if any exception happen, - * return -1 - */ - public int quiteExecute(String... sqls) { - int result = 0; - for (String sql : sqls) - try { - execute(sql); - } catch (Exception e) { - result = -1; - } - return result; - } - - public void ________prepareMethods________() {// NOSONAR - } - - /** - * Prepare a PreparedSQL for iXxxx (Single SQL) style, unknown objects (include - * null) will automatically looked as SQL pieces, more detail see doPrepare - * method - */ - public PreparedSQL prepare(Object... items) { - return doPrepare(true, items); - } - - /** - * Prepare a PreparedSQL for iXxxx (In-line) style or pXxxx style, For in-line - * style, unknown items be treated as String, SQL parameters must written in - * param() method, for example: - * - * ctx.iQuery(new SimpleCacheHandler(), connection, "select u.** from users u - * where u.age>?", param(20)," and u.id=?", param("001"), MapListHandler.class); - * - * - * pXxxx style only allow first appeared String as SQL, left unknown items will - * be treated as SQL parameters, for example: - * - * ctx.pQuery(MapListHandler.class, "select * from users where age>? and id=?", - * 20 , "001" , connection, new PaginHandler(2,5), sql(" and name=?"), "Tom" ); - * - * In above examples connection and sqlHandlers are optional items, these - * optional items can appear at anywhere - * - * @param items - * SQL String / SQL Parameters / Connection / ResultSetHandler class - * or instance / SqlHandler class or instance - * @return a PreparedSQL instance - */ - private PreparedSQL doPrepare(boolean inlineStyle, Object... items) {// NOSONAR - PreparedSQL ps = dealSqlItems(null, inlineStyle, items); - ps.addGlobalAndThreadedHandlers(this); - return ps; - } - - /** Convert parameters to JDBC type, like java.util.Date to java.sql.Date */ - public void preparedParamsToJdbc(PreparedSQL ps) { - //empty method for child class override - } - - /** - * Deal with multiple SqlItems - */ - public PreparedSQL dealSqlItems(PreparedSQL lastPreSql, boolean inlineStyle, Object... items) {// NOSONAR - if (items == null || items.length == 0) - throw new DbProException("prepareSQL items can not be empty"); - PreparedSQL predSQL = lastPreSql; - if (predSQL == null) - predSQL = new PreparedSQL(); - for (Object item : items) { - if (item == null) { - if (inlineStyle) - throw new DbProException("null value can not append as SQL piece"); - else - predSQL.addParam(null); - } else if (!dealOneSqlItem(inlineStyle, predSQL, item)) { - if (item instanceof SqlItem) - throw new DbProException("One SqlItem did not find explainer, type=" + ((SqlItem) item).getType()); - if (item.getClass().isArray()) { - Object[] array = (Object[]) item; - if (array.length != 0) - dealSqlItems(predSQL, inlineStyle, (Object[]) item); - } else if (inlineStyle) - predSQL.addSql(item); // iXxxx style, unknown object look as SQL piece - else - predSQL.addParam(item); // pXxxx style, unknown object look as parameter - } - } - predSQL.setSql(predSQL.getSqlBuilder().toString()); - return predSQL; - } - - /** - * Here deal one SqlItem, if can deal it, return true, otherwise return false, - * subclass (like DbContext) can override this method - */ - protected boolean dealOneSqlItem(boolean inlineStyle, PreparedSQL predSQL, Object item) {// NOSONAR - if (item instanceof String) { - predSQL.addSqlOrParam(inlineStyle, (String) item); - } else if (item instanceof PreparedSQL) { - PreparedSQL psItem = (PreparedSQL) item; - if (psItem.getSql() != null) - predSQL.addSql(psItem.getSql()); - if (psItem.getParams() != null) - for (Object obj : psItem.getParams()) - predSQL.addParam(obj); - } else if (item instanceof SqlTemplateEngine) { - predSQL.setTemplateEngine((SqlTemplateEngine) item); - } else if (item instanceof Map) { - predSQL.addTemplateMap((Map) item); - } else if (item instanceof SqlOption) { - if (SqlOption.USE_MASTER.equals(item)) { - predSQL.setMasterSlaveOption(SqlOption.USE_MASTER); - } else if (SqlOption.USE_SLAVE.equals(item)) { - predSQL.setMasterSlaveOption(SqlOption.USE_SLAVE); - } else if (SqlOption.USE_AUTO.equals(item)) { - predSQL.setMasterSlaveOption(SqlOption.USE_AUTO); - } else if (SqlOption.USE_BOTH.equals(item)) { - predSQL.setMasterSlaveOption(SqlOption.USE_BOTH); - } else if (SqlOption.EXECUTE.equals(item)) { - predSQL.setOperationType(SqlOption.EXECUTE); - } else if (SqlOption.UPDATE.equals(item)) { - predSQL.setOperationType(SqlOption.UPDATE); - } else if (SqlOption.QUERY.equals(item)) { - predSQL.setOperationType(SqlOption.QUERY); - } else if (SqlOption.INSERT.equals(item)) { - predSQL.setOperationType(SqlOption.INSERT); - } else - return false; - } else if (item instanceof SqlItem) { - SqlItem sqItem = (SqlItem) item; - SqlOption sqlItemType = sqItem.getType(); - if (SqlOption.OTHER.equals(sqlItemType)) - predSQL.addOther(sqItem); - else if (SqlOption.PARAM.equals(sqlItemType)) { - if(sqItem.getParameters()==null ) - predSQL.addParam(null); - else for (Object pm : sqItem.getParameters()) - predSQL.addParam(pm); - } else if (SqlOption.BIND.equals(sqlItemType)) { - predSQL.addTemplateParam(sqItem); - } else if (SqlOption.SQL.equals(sqlItemType)) { - for (Object pm : sqItem.getParameters()) - predSQL.addSql(pm); - } else if (SqlOption.QUESTION_PARAM.equals(sqlItemType)) { - if (sqItem.getParameters() == null) { - predSQL.addParam(null); - predSQL.addSql("?"); - } else { - int i = 0; - for (Object pm : sqItem.getParameters()) { - predSQL.addParam(pm); - if (i > 0) - predSQL.addSql(","); - predSQL.addSql("?"); - i++; - } - } - } else if (SqlOption.VALUES_QUESTIONS.equals(sqlItemType)) { - predSQL.addSql(" values("); - for (int i = 0; i < predSQL.getParamSize(); i++) { - if (i > 0) - predSQL.addSql(","); - predSQL.addSql("?"); - } - predSQL.addSql(")"); - } else if (SqlOption.ENABLE_HANDLERS.equals(sqlItemType)) { - predSQL.enableAllHandlers(); - } else if (SqlOption.DISABLE_HANDLERS.equals(sqlItemType)) { - predSQL.disableHandlers((Object[]) sqItem.getParameters()); - } else if (SqlOption.SWITCHTO.equals(sqlItemType)) { - predSQL.setSwitchTo((DbPro) sqItem.getParameters()[0]); - } else - return false; - } else if (item instanceof Text) - predSQL.addSql(item.toString()); - else if (item instanceof Connection) - predSQL.setConnection((Connection) item); - else if (item instanceof DbPro) - predSQL.setSwitchTo((DbPro) item); - else if (item instanceof SqlHandler) - predSQL.addHandler((SqlHandler) item); - else if (item instanceof ResultSetHandler) - predSQL.setResultSetHandler((ResultSetHandler) item); - else if (item instanceof Class) { - if (Text.class.isAssignableFrom((Class) item)) { - String text = Text.classToString((Class) item); - predSQL.addSqlOrParam(inlineStyle, text); - return true; - } else - return false; - } else if (item instanceof CustomizedSqlItem) { - ((CustomizedSqlItem) item).doPrepare(predSQL); - } else if(sqlItemHandler!=null) - return sqlItemHandler.handle(predSQL, item); - else - return false; - return true; - } - - public void ________3letter_inlineStyles________() {// NOSONAR - } - - /** - * Executes the in-line style query statement - * - * @param inlineSQL - * the in-line style SQL - * @return An object generated by the handler. - */ - public T qry(Object... inlineSQL) { - PreparedSQL ps = prepare(inlineSQL); - ps.ifNullSetType(SqlOption.QUERY); - return (T) runPreparedSQL(ps); - } - - /** - * Execute an In-line style query for an Object, only return the first row and - * first column's value if more than one column or more than 1 rows returned - * - * @param inlineSQL - * @param params - * @return An Object or null value determined by SQL content - */ - public T qryObject(Object... inlineSQL) { - PreparedSQL ps = prepare(inlineSQL); - ps.ifNullSetType(SqlOption.QUERY); - if (ps.getResultSetHandler() == null) - ps.setResultSetHandler(new ScalarHandler(1)); - return (T) runPreparedSQL(ps); - } - - /** - * In-line style execute query and force return a long value, runtime exception - * may throw if result can not be cast to long. - */ - public long qryLongValue(Object... inlineSQL) { - return ((Number) qryObject(inlineSQL)).longValue();// NOSONAR - } - - /** - * In-line style execute query and force return a int, runtime exception may - * throw if result can not be cast to int. - */ - public int qryIntValue(Object... inlineSQL) { - return ((Number) qryObject(inlineSQL)).intValue();// NOSONAR - } - - /** + + public DbPro() { + super(); + } + + public DbPro(DataSource ds) { + super(ds); + } + + public DbPro(DataSource ds, Dialect dialect) { + super(ds, dialect); + } + + /** + * Quite execute a SQL, do not throw any exception, if any exception happen, + * return -1 + */ + public int quiteExecute(String... sqls) { + int result = 0; + for (String sql : sqls) + try { + execute(sql); + } catch (Exception e) { + result = -1; + } + return result; + } + + public void ________prepareMethods________() {// NOSONAR + } + + /** + * Prepare a PreparedSQL for iXxxx (Single SQL) style, unknown objects (include + * null) will automatically looked as SQL pieces, more detail see doPrepare + * method + */ + public PreparedSQL prepare(Object... items) { + return doPrepare(true, items); + } + + /** + * Prepare a PreparedSQL for iXxxx (In-line) style or pXxxx style, For in-line + * style, unknown items be treated as String, SQL parameters must written in + * param() method, for example: + *

+ * ctx.iQuery(new SimpleCacheHandler(), connection, "select u.** from users u + * where u.age>?", param(20)," and u.id=?", param("001"), MapListHandler.class); + *

+ *

+ * pXxxx style only allow first appeared String as SQL, left unknown items will + * be treated as SQL parameters, for example: + *

+ * ctx.pQuery(MapListHandler.class, "select * from users where age>? and id=?", + * 20 , "001" , connection, new PaginHandler(2,5), sql(" and name=?"), "Tom" ); + *

+ * In above examples connection and sqlHandlers are optional items, these + * optional items can appear at anywhere + * + * @param items SQL String / SQL Parameters / Connection / ResultSetHandler class + * or instance / SqlHandler class or instance + * @return a PreparedSQL instance + */ + private PreparedSQL doPrepare(boolean inlineStyle, Object... items) {// NOSONAR + PreparedSQL ps = dealSqlItems(null, inlineStyle, items); + ps.addGlobalAndThreadedHandlers(this); + return ps; + } + + /** + * Convert parameters to JDBC type, like java.util.Date to java.sql.Date + */ + public void preparedParamsToJdbc(PreparedSQL ps) { + //empty method for child class override + } + + /** + * Deal with multiple SqlItems + */ + public PreparedSQL dealSqlItems(PreparedSQL lastPreSql, boolean inlineStyle, Object... items) {// NOSONAR + if (items == null || items.length == 0) + throw new DbProException("prepareSQL items can not be empty"); + PreparedSQL predSQL = lastPreSql; + if (predSQL == null) + predSQL = new PreparedSQL(); + for (Object item : items) { + if (item == null) { + if (inlineStyle) + throw new DbProException("null value can not append as SQL piece"); + else + predSQL.addParam(null); + } else if (!dealOneSqlItem(inlineStyle, predSQL, item)) { + if (item instanceof SqlItem) + throw new DbProException("One SqlItem did not find explainer, type=" + ((SqlItem) item).getType()); + if (item.getClass().isArray()) { + Object[] array = (Object[]) item; + if (array.length != 0) + dealSqlItems(predSQL, inlineStyle, (Object[]) item); + } else if (inlineStyle) + predSQL.addSql(item); // iXxxx style, unknown object look as SQL piece + else + predSQL.addParam(item); // pXxxx style, unknown object look as parameter + } + } + predSQL.setSql(predSQL.getSqlBuilder().toString()); + return predSQL; + } + + /** + * Here deal one SqlItem, if can deal it, return true, otherwise return false, + * subclass (like DbContext) can override this method + */ + protected boolean dealOneSqlItem(boolean inlineStyle, PreparedSQL predSQL, Object item) {// NOSONAR + if (item instanceof String) { + predSQL.addSqlOrParam(inlineStyle, (String) item); + } else if (item instanceof PreparedSQL) { + PreparedSQL psItem = (PreparedSQL) item; + if (psItem.getSql() != null) + predSQL.addSql(psItem.getSql()); + if (psItem.getParams() != null) + for (Object obj : psItem.getParams()) + predSQL.addParam(obj); + } else if (item instanceof SqlTemplateEngine) { + predSQL.setTemplateEngine((SqlTemplateEngine) item); + } else if (item instanceof Map) { + predSQL.addTemplateMap((Map) item); + } else if (item instanceof SqlOption) { + if (SqlOption.USE_MASTER.equals(item)) { + predSQL.setMasterSlaveOption(SqlOption.USE_MASTER); + } else if (SqlOption.USE_SLAVE.equals(item)) { + predSQL.setMasterSlaveOption(SqlOption.USE_SLAVE); + } else if (SqlOption.USE_AUTO.equals(item)) { + predSQL.setMasterSlaveOption(SqlOption.USE_AUTO); + } else if (SqlOption.USE_BOTH.equals(item)) { + predSQL.setMasterSlaveOption(SqlOption.USE_BOTH); + } else if (SqlOption.EXECUTE.equals(item)) { + predSQL.setOperationType(SqlOption.EXECUTE); + } else if (SqlOption.UPDATE.equals(item)) { + predSQL.setOperationType(SqlOption.UPDATE); + } else if (SqlOption.QUERY.equals(item)) { + predSQL.setOperationType(SqlOption.QUERY); + } else if (SqlOption.INSERT.equals(item)) { + predSQL.setOperationType(SqlOption.INSERT); + } else + return false; + } else if (item instanceof SqlItem) { + SqlItem sqItem = (SqlItem) item; + SqlOption sqlItemType = sqItem.getType(); + if (SqlOption.OTHER.equals(sqlItemType)) + predSQL.addOther(sqItem); + else if (SqlOption.PARAM.equals(sqlItemType)) { + if (sqItem.getParameters() == null) + predSQL.addParam(null); + else for (Object pm : sqItem.getParameters()) + predSQL.addParam(pm); + } else if (SqlOption.BIND.equals(sqlItemType)) { + predSQL.addTemplateParam(sqItem); + } else if (SqlOption.SQL.equals(sqlItemType)) { + for (Object pm : sqItem.getParameters()) + predSQL.addSql(pm); + } else if (SqlOption.QUESTION_PARAM.equals(sqlItemType)) { + if (sqItem.getParameters() == null) { + predSQL.addParam(null); + predSQL.addSql("?"); + } else { + int i = 0; + for (Object pm : sqItem.getParameters()) { + predSQL.addParam(pm); + if (i > 0) + predSQL.addSql(","); + predSQL.addSql("?"); + i++; + } + } + } else if (SqlOption.VALUES_QUESTIONS.equals(sqlItemType)) { + predSQL.addSql(" values("); + for (int i = 0; i < predSQL.getParamSize(); i++) { + if (i > 0) + predSQL.addSql(","); + predSQL.addSql("?"); + } + predSQL.addSql(")"); + } else if (SqlOption.ENABLE_HANDLERS.equals(sqlItemType)) { + predSQL.enableAllHandlers(); + } else if (SqlOption.DISABLE_HANDLERS.equals(sqlItemType)) { + predSQL.disableHandlers((Object[]) sqItem.getParameters()); + } else if (SqlOption.SWITCHTO.equals(sqlItemType)) { + predSQL.setSwitchTo((DbPro) sqItem.getParameters()[0]); + } else if (SqlOption.TIMEOUT.equals(sqlItemType)) { + int seconds = 0; + if (sqItem.getParameters().length > 0) { + Object param = sqItem.getParameters()[0]; + if (param instanceof Integer) { + seconds = Integer.parseInt(param.toString()); + } + } + predSQL.setTimeoutSeconds(seconds); + } else + return false; + } else if (item instanceof Text) + predSQL.addSql(item.toString()); + else if (item instanceof Connection) + predSQL.setConnection((Connection) item); + else if (item instanceof DbPro) + predSQL.setSwitchTo((DbPro) item); + else if (item instanceof SqlHandler) + predSQL.addHandler((SqlHandler) item); + else if (item instanceof ResultSetHandler) + predSQL.setResultSetHandler((ResultSetHandler) item); + else if (item instanceof Class) { + if (Text.class.isAssignableFrom((Class) item)) { + String text = Text.classToString((Class) item); + predSQL.addSqlOrParam(inlineStyle, text); + return true; + } else + return false; + } else if (item instanceof CustomizedSqlItem) { + ((CustomizedSqlItem) item).doPrepare(predSQL); + } else if (sqlItemHandler != null) + return sqlItemHandler.handle(predSQL, item); + else + return false; + return true; + } + + public void ________3letter_inlineStyles________() {// NOSONAR + } + + /** + * Executes the in-line style query statement + * + * @param inlineSQL the in-line style SQL + * @return An object generated by the handler. + */ + public T qry(Object... inlineSQL) { + PreparedSQL ps = prepare(inlineSQL); + ps.ifNullSetType(SqlOption.QUERY); + return (T) runPreparedSQL(ps); + } + + /** + * Execute an In-line style query for an Object, only return the first row and + * first column's value if more than one column or more than 1 rows returned + * + * @param inlineSQL + * @param params + * @return An Object or null value determined by SQL content + */ + public T qryObject(Object... inlineSQL) { + PreparedSQL ps = prepare(inlineSQL); + ps.ifNullSetType(SqlOption.QUERY); + if (ps.getResultSetHandler() == null) + ps.setResultSetHandler(new ScalarHandler(1)); + return (T) runPreparedSQL(ps); + } + + /** + * In-line style execute query and force return a long value, runtime exception + * may throw if result can not be cast to long. + */ + public long qryLongValue(Object... inlineSQL) { + return ((Number) qryObject(inlineSQL)).longValue();// NOSONAR + } + + /** + * In-line style execute query and force return a int, runtime exception may + * throw if result can not be cast to int. + */ + public int qryIntValue(Object... inlineSQL) { + return ((Number) qryObject(inlineSQL)).intValue();// NOSONAR + } + + /** * In-line style execute query and force return a boolean, runtime exception may * throw if result can not be cast to boolean. */ public boolean qryBooleanValue(Object... inlineSQL) { return (Boolean) qryObject(inlineSQL);// NOSONAR } - - - /** - * In-line style execute query and force return a String object. - */ - public String qryString(Object... inlineSQL) { - Object result = qryObject(inlineSQL); - return result == null ? null : result.toString(); - } - - /** - * In-Line style execute query and force return a List> type - * result. - */ - public List> qryMapList(Object... items) { - PreparedSQL ps = prepare(items); - ps.addHandler(new MapListHandler()); - ps.ifNullSetType(SqlOption.QUERY); - return (List>) runPreparedSQL(ps); - } - - /** - * In-Line style execute query and force return a Map type - * result, if no record found, return empty HashMap instance; - */ - public Map qryMap(Object... items) { - List> list = qryMapList(items); - if (list.isEmpty()) - return new HashMap(); - return list.get(0); - } - - /** - * In-Line style execute query and force return a Map type - * result, if no record found, return empty HashMap instance; - */ - public List qryList(Object... items) { - return this.qry(new ColumnListHandler(1), items); - } - - - /** - * Executes the in-line style INSERT, UPDATE, or DELETE statement - * - * @param inlineSQL - * the in-line style SQL - * @return The number of rows updated. - */ - public int upd(Object... inlineSQL) { - PreparedSQL ps = prepare(inlineSQL); - ps.ifNullSetType(SqlOption.UPDATE); - return (Integer) runPreparedSQL(ps); - } - - /** - * Executes the in-line style insert statement - * - * @param inlineSQL - * the in-line style SQL - * @return An object generated by the handler. - */ - public T ins(Object... inlineSQL) { - PreparedSQL ps = prepare(inlineSQL); - ps.ifNullSetType(SqlOption.INSERT); - return (T) runPreparedSQL(ps); - } - - /** - * Executes the in-line style execute statement - * - * @param inlineSQL - * the in-line style SQL - * @return A list of objects generated by the handler, or number of rows updated - * if no handler - */ - public T exe(Object... inlineSQL) { - PreparedSQL ps = prepare(inlineSQL); - ps.ifNullSetType(SqlOption.EXECUTE); - return (T) runPreparedSQL(ps); - } - - /** - * nXxxx style series methods are design to replace QueryRunner's xxxx method, - * the difference is nXxxx methods do not throw SqlException - */ - public void ________jdbcMethods________() {// NOSONAR - - } - - /** - * Query for an Object, only return the first row and first column's value if - * more than one column or more than 1 rows returned, a null object may return - * if no result found , DbProRuntimeException may be threw if some SQL operation - * Exception happen. - * - * @param sql - * @param params - * @return An Object or null, Object type determined by SQL content - */ - @Override - public T jdbcQueryForObject(String sql, Object... params) { - PreparedSQL ps = new PreparedSQL(SqlOption.QUERY, null, SingleTonHandlers.scalarHandler, sql, params); - ps.addGlobalAndThreadedHandlers(this); - return (T) runPreparedSQL(ps); - } - - /** - * Executes the given INSERT, UPDATE, or DELETE SQL statement. - * - * @param sql - * the SQL - * @param params - * the parameters if have - * @return The number of rows updated. - */ - @Override - public int jdbcUpdate(String sql, Object... params) { - PreparedSQL ps = new PreparedSQL(SqlOption.UPDATE, null, null, sql, params); - ps.addGlobalAndThreadedHandlers(this); - return (Integer) runPreparedSQL(ps); - } - - /** - * Execute an statement, including a stored procedure call, which does not - * return any result sets. Any parameters which are instances of - * {@link OutParameter} will be registered as OUT parameters. - *

- * Use this method when invoking a stored procedure with OUT parameters that - * does not return any result sets. - * - * @param sql - * the SQL - * @return The number of rows updated. - */ - @Override - public int jdbcExecute(String sql, Object... params) { - PreparedSQL ps = new PreparedSQL(SqlOption.EXECUTE, null, null, sql, params); - ps.addGlobalAndThreadedHandlers(this); - return (Integer) runPreparedSQL(ps); - } - - // ============================================================================ + + + /** + * In-line style execute query and force return a String object. + */ + public String qryString(Object... inlineSQL) { + Object result = qryObject(inlineSQL); + return result == null ? null : result.toString(); + } + + /** + * In-Line style execute query and force return a List> type + * result. + */ + public List> qryMapList(Object... items) { + PreparedSQL ps = prepare(items); + ps.addHandler(new MapListHandler()); + ps.ifNullSetType(SqlOption.QUERY); + return (List>) runPreparedSQL(ps); + } + + /** + * In-Line style execute query and force return a Map type + * result, if no record found, return empty HashMap instance; + */ + public Map qryMap(Object... items) { + List> list = qryMapList(items); + if (list.isEmpty()) + return new HashMap(); + return list.get(0); + } + + /** + * In-Line style execute query and force return a Map type + * result, if no record found, return empty HashMap instance; + */ + public List qryList(Object... items) { + return this.qry(new ColumnListHandler(1), items); + } + + + /** + * Executes the in-line style INSERT, UPDATE, or DELETE statement + * + * @param inlineSQL the in-line style SQL + * @return The number of rows updated. + */ + public int upd(Object... inlineSQL) { + PreparedSQL ps = prepare(inlineSQL); + ps.ifNullSetType(SqlOption.UPDATE); + return (Integer) runPreparedSQL(ps); + } + + /** + * Executes the in-line style insert statement + * + * @param inlineSQL the in-line style SQL + * @return An object generated by the handler. + */ + public T ins(Object... inlineSQL) { + PreparedSQL ps = prepare(inlineSQL); + ps.ifNullSetType(SqlOption.INSERT); + return (T) runPreparedSQL(ps); + } + + /** + * Executes the in-line style execute statement + * + * @param inlineSQL the in-line style SQL + * @return A list of objects generated by the handler, or number of rows updated + * if no handler + */ + public T exe(Object... inlineSQL) { + PreparedSQL ps = prepare(inlineSQL); + ps.ifNullSetType(SqlOption.EXECUTE); + return (T) runPreparedSQL(ps); + } + + /** + * nXxxx style series methods are design to replace QueryRunner's xxxx method, + * the difference is nXxxx methods do not throw SqlException + */ + public void ________jdbcMethods________() {// NOSONAR + + } + + /** + * Query for an Object, only return the first row and first column's value if + * more than one column or more than 1 rows returned, a null object may return + * if no result found , DbProRuntimeException may be threw if some SQL operation + * Exception happen. + * + * @param sql + * @param params + * @return An Object or null, Object type determined by SQL content + */ + @Override + public T jdbcQueryForObject(String sql, Object... params) { + PreparedSQL ps = new PreparedSQL(SqlOption.QUERY, null, SingleTonHandlers.scalarHandler, sql, params); + ps.addGlobalAndThreadedHandlers(this); + return (T) runPreparedSQL(ps); + } + + /** + * Executes the given INSERT, UPDATE, or DELETE SQL statement. + * + * @param sql the SQL + * @param params the parameters if have + * @return The number of rows updated. + */ + @Override + public int jdbcUpdate(String sql, Object... params) { + PreparedSQL ps = new PreparedSQL(SqlOption.UPDATE, null, null, sql, params); + ps.addGlobalAndThreadedHandlers(this); + return (Integer) runPreparedSQL(ps); + } + + /** + * Execute an statement, including a stored procedure call, which does not + * return any result sets. Any parameters which are instances of + * {@link OutParameter} will be registered as OUT parameters. + *

+ * Use this method when invoking a stored procedure with OUT parameters that + * does not return any result sets. + * + * @param sql the SQL + * @return The number of rows updated. + */ + @Override + public int jdbcExecute(String sql, Object... params) { + PreparedSQL ps = new PreparedSQL(SqlOption.EXECUTE, null, null, sql, params); + ps.addGlobalAndThreadedHandlers(this); + return (Integer) runPreparedSQL(ps); + } + + // ============================================================================ } diff --git a/core/src/main/java/com/github/drinkjava2/jdbpro/ImprovedQueryRunner.java b/core/src/main/java/com/github/drinkjava2/jdbpro/ImprovedQueryRunner.java index e2b5ab03c1f960d4821c01aa773a79b7e0c434ae..de6fc6bfc58f0b32a18aedae5c2af60eb3f4c903 100644 --- a/core/src/main/java/com/github/drinkjava2/jdbpro/ImprovedQueryRunner.java +++ b/core/src/main/java/com/github/drinkjava2/jdbpro/ImprovedQueryRunner.java @@ -556,14 +556,14 @@ public class ImprovedQueryRunner extends QueryRunner implements DataSourceHolder try { if (ps.getConnection() != null) { if (ps.getParams() != null) - return (T) query(ps.getConnection(), ps.getSql(), ps.getResultSetHandler(), ps.getParams()); + return (T) query(ps.getConnection(), ps.getSql(),ps.getTimeoutSeconds(), ps.getResultSetHandler(), ps.getParams()); else - return (T) query(ps.getConnection(), ps.getSql(), ps.getResultSetHandler()); + return (T) query(ps.getConnection(), ps.getSql(),ps.getTimeoutSeconds(), ps.getResultSetHandler()); } else { if (ps.getParams() != null) - return (T) query(ps.getSql(), ps.getResultSetHandler(), ps.getParams()); + return (T) query(ps.getSql(),ps.getTimeoutSeconds(), ps.getResultSetHandler(), ps.getParams()); else - return (T) query(ps.getSql(), ps.getResultSetHandler()); + return (T) query(ps.getSql(),ps.getTimeoutSeconds(), ps.getResultSetHandler()); } } catch (SQLException e) { throw new DbProException(e); diff --git a/core/src/main/java/com/github/drinkjava2/jdbpro/PreparedSQL.java b/core/src/main/java/com/github/drinkjava2/jdbpro/PreparedSQL.java index dffac98a9d6e1250b2d924999bdd7b0498966fbd..35216235e6568de60bf1f68c3bf43fcce86854fb 100644 --- a/core/src/main/java/com/github/drinkjava2/jdbpro/PreparedSQL.java +++ b/core/src/main/java/com/github/drinkjava2/jdbpro/PreparedSQL.java @@ -31,7 +31,7 @@ import com.github.drinkjava2.jdbpro.template.SqlTemplateEngine; * PreparedSQL is a temporary object used for store SQL, parameter, * ResultSetHandlers, SqlHandlers, Connection and templateEngine..., it's not * thread-safe - * + * * @author Yong Zhu * @since 1.7.0 */ @@ -99,6 +99,8 @@ public class PreparedSQL { /** EntityNet, this is designed for ORM program's EntityNet */ private Object entityNet = null; + /** query timeout secons default 0 unlimited*/ + private int timeoutSeconds=0; public PreparedSQL() {// default constructor } @@ -471,4 +473,11 @@ public class PreparedSQL { this.ignoreEmpty = ignoreEmpty; } + public int getTimeoutSeconds() { + return timeoutSeconds; + } + + public void setTimeoutSeconds(int timeoutSeconds) { + this.timeoutSeconds = timeoutSeconds; + } } diff --git a/core/src/main/java/com/github/drinkjava2/jdbpro/SqlOption.java b/core/src/main/java/com/github/drinkjava2/jdbpro/SqlOption.java index 186b05f2e5f5816475654f580ef300c86beb0b7c..4638ccf52025b152890fa0fe8f099d5e8c1852ff 100644 --- a/core/src/main/java/com/github/drinkjava2/jdbpro/SqlOption.java +++ b/core/src/main/java/com/github/drinkjava2/jdbpro/SqlOption.java @@ -18,7 +18,7 @@ package com.github.drinkjava2.jdbpro; /** * SqlOption system how to explain a SqlItem, SqlItem like "Message" in windows, * SqlOption is the "Message" type. - * + * * @author Yong Zhu * @since 1.7.0.3 */ @@ -135,5 +135,7 @@ public enum SqlOption { AUTO_SQL, /** Mark a TAIL SqlItem, tell ORM to use this model do CRUD */ - TAIL + TAIL, + /** Mark a TAIL SqlItem, tell ORM to use query timeout throw exception */ + TIMEOUT } \ No newline at end of file diff --git a/core/src/main/java/com/github/drinkjava2/jsqlbox/DB.java b/core/src/main/java/com/github/drinkjava2/jsqlbox/DB.java index 4bfe1813f92d16f8882408a21ef4f1513149f25b..356499e677243f609c9313ac1ad2f05496d7c9b1 100644 --- a/core/src/main/java/com/github/drinkjava2/jsqlbox/DB.java +++ b/core/src/main/java/com/github/drinkjava2/jsqlbox/DB.java @@ -31,7 +31,7 @@ import com.github.drinkjava2.jtransactions.TxResult; /** * DB store some public static methods, usually used for static import to * simplify programming - * + * * @author Yong Zhu * @since 1.0.8 */ @@ -58,7 +58,7 @@ public abstract class DB {// NOSONAR public static SqlItem par(Object... parameters) { return new SqlItem(SqlOption.PARAM, parameters); } - + /** * Cache parameters and return a "?" String */ @@ -70,14 +70,14 @@ public abstract class DB {// NOSONAR public static SqlItem param(Object... parameters) { return new SqlItem(SqlOption.PARAM, parameters); } - + /** * Cache parameters and return a "?" String */ public static SqlItem ques(Object... parameters) {// NOSONAR return new SqlItem(SqlOption.QUESTION_PARAM, parameters); } - + /** * Cache parameters and return a "?" String */ @@ -85,6 +85,11 @@ public abstract class DB {// NOSONAR return new SqlItem(SqlOption.QUESTION_PARAM, parameters); } + /** + * Cache parameters and set querytimeout + */ + public static SqlItem timeout(int seconds){return new SqlItem(SqlOption.TIMEOUT,seconds);} + /** * If last param is not null, then add all items in SQL
* Example: query("select * from a where 1=1",notNull(" and name=?",name)); @@ -144,7 +149,7 @@ public abstract class DB {// NOSONAR sb.append(items[i]); return new Object[] {items[0], par(sb.toString())}; } - + /** if condition true, return items array, else return "" */ public static Object when(boolean condition, Object... items) { return condition ? items : ""; @@ -157,11 +162,11 @@ public abstract class DB {// NOSONAR public static SqlItem valuesQuestions() { return new SqlItem(SqlOption.VALUES_QUESTIONS); } - + public static SqlItem other(Object... otherInfos) { return new SqlItem(SqlOption.OTHER, otherInfos); } - + public static List getOthers() { return gctx().getOthers(); } @@ -176,7 +181,7 @@ public abstract class DB {// NOSONAR /** * For tXxxx style templateEngine use, return a SqlItemType.PUT type SqlItem * instance, - * + * * Usage: put("key1",value1,"key2",value2...); */ public static SqlItem bind(Object... parameters) { @@ -190,17 +195,17 @@ public abstract class DB {// NOSONAR public static SqlItem disableHandlers(Class... args) { return new SqlItem(SqlOption.DISABLE_HANDLERS, (Object[]) args); } - + //====================== - - - - - - - - - + + + + + + + + + /** Shortcut method equal to DbContext.getGlobalDbContext() */ public static DbContext gctx() { return DbContext.getGlobalDbContext(); @@ -278,18 +283,18 @@ public abstract class DB {// NOSONAR protected void ________Entity_Methods________() {// NOSONAR } - //@formatter:off + //@formatter:off //Entity series methods from DbContext - + public static List entityFind(Class entityClass, Object... items) {return gctx().entityFind(entityClass, items);} public static List entityFindBySample(Object sampleBean, Object... items) {return gctx().entityFindBySample(sampleBean, items);} public static List entityFindBySql(Object... items) {return gctx().entityFindBySql(items);} - public static T entityFindOneBySQL(Object... items) {return gctx().entityFindOneBySQL(items);} - public static T entityLoad(T entity, Object... items) {return gctx().entityLoad(entity, items);} + public static T entityFindOneBySQL(Object... items) {return gctx().entityFindOneBySQL(items);} + public static T entityLoad(T entity, Object... items) {return gctx().entityLoad(entity, items);} public static T entityLoadById(Class entityClass, Object entityId, Object... items) {return gctx().entityLoadById(entityClass, entityId, items);} public static T entityLoadByIdTry(Class entityClass, Object entityId, Object... items) {return gctx().entityLoadByIdTry(entityClass, entityId, items);} public static T entityLoadBySql(Object... items) {return gctx().entityLoadBySql(items);} - public static T entityInsert(T entity, Object... items) {return gctx().entityInsert(entity, items);} + public static T entityInsert(T entity, Object... items) {return gctx().entityInsert(entity, items);} public static T entityUpdate(Object entity, Object... items) {return gctx().entityUpdate(entity, items);} public static boolean entityExist(Object entity, Object... items) {return gctx().entityExist(entity, items);} public static boolean entityExistById(Class entityClass, Object id, Object... items) {return gctx().entityExistById(entityClass, id, items);} @@ -304,12 +309,12 @@ public abstract class DB {// NOSONAR public static List entityFindRelatedList(Object entityOrIterable, Object... sqlItems) {return gctx().entityFindRelatedList(entityOrIterable, sqlItems);} public static Set entityFindRelatedSet(Object entity, Object... sqlItems) {return gctx().entityFindRelatedSet(entity, sqlItems);} public static Map entityFindRelatedMap(Object entity, Object... sqlItems) {return gctx().entityFindRelatedMap(entity, sqlItems);} - public static EntityNet autoNet(Class... entityClass) {return gctx().autoNet(entityClass);} - - - // simplilfied SQL methods + public static EntityNet autoNet(Class... entityClass) {return gctx().autoNet(entityClass);} + + + // simplilfied SQL methods protected void ________SQL_Methods________() {}// NOSONAR - + public static T qry(Object... items) {return gctx().qry(items);} public static T qryObject(Object... items) {return gctx().qryObject(items);} public static long qryLongValue(Object... items) {return gctx().qryLongValue(items);} @@ -324,5 +329,5 @@ public abstract class DB {// NOSONAR public static List qryEntityList(Object... items) {return gctx().qryEntityList(items);} public static PreparedSQL prepare(Object... items) { return gctx().prepare(items); } - + } \ No newline at end of file diff --git a/core/src/main/java/org/apache/commons/dbutils/QueryRunner.java b/core/src/main/java/org/apache/commons/dbutils/QueryRunner.java index 7f131f9094aeb95c0b0dcb38ef38ac4209897ef7..6533a0926c323c244b6d8ac46e2f91f236690cef 100644 --- a/core/src/main/java/org/apache/commons/dbutils/QueryRunner.java +++ b/core/src/main/java/org/apache/commons/dbutils/QueryRunner.java @@ -45,8 +45,8 @@ public class QueryRunner extends AbstractQueryRunner { * Constructor for QueryRunner that controls the use of ParameterMetaData. * * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. + * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. */ public QueryRunner(boolean pmdKnownBroken) { super(pmdKnownBroken); @@ -54,7 +54,7 @@ public class QueryRunner extends AbstractQueryRunner { /** * Constructor for QueryRunner that takes a DataSource to use. - * + *

* Methods that do not take a Connection parameter will retrieve connections from this * DataSource. * @@ -79,10 +79,10 @@ public class QueryRunner extends AbstractQueryRunner { * Methods that do not take a Connection parameter will retrieve connections from this * DataSource. * - * @param ds The DataSource to retrieve connections from. + * @param ds The DataSource to retrieve connections from. * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. + * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. */ public QueryRunner(DataSource ds, boolean pmdKnownBroken) { super(ds, pmdKnownBroken); @@ -90,11 +90,11 @@ public class QueryRunner extends AbstractQueryRunner { /** * Constructor for QueryRunner that takes a DataSource to use and a StatementConfiguration. - * + *

* Methods that do not take a Connection parameter will retrieve connections from this * DataSource. * - * @param ds The DataSource to retrieve connections from. + * @param ds The DataSource to retrieve connections from. * @param stmtConfig The configuration to apply to statements when they are prepared. */ public QueryRunner(DataSource ds, StatementConfiguration stmtConfig) { @@ -106,11 +106,11 @@ public class QueryRunner extends AbstractQueryRunner { * controls the use of ParameterMetaData. Methods that do not take a Connection parameter * will retrieve connections from this DataSource. * - * @param ds The DataSource to retrieve connections from. + * @param ds The DataSource to retrieve connections from. * @param pmdKnownBroken Some drivers don't support {@link java.sql.ParameterMetaData#getParameterType(int) }; - * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, - * and if it breaks, we'll remember not to use it again. - * @param stmtConfig The configuration to apply to statements when they are prepared. + * if pmdKnownBroken is set to true, we won't even try it; if false, we'll try it, + * and if it breaks, we'll remember not to use it again. + * @param stmtConfig The configuration to apply to statements when they are prepared. */ public QueryRunner(DataSource ds, boolean pmdKnownBroken, StatementConfiguration stmtConfig) { super(ds, pmdKnownBroken, stmtConfig); @@ -119,11 +119,11 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute a batch of SQL INSERT, UPDATE, or DELETE queries. * - * @param conn The Connection to use to run the query. The caller is - * responsible for closing this Connection. - * @param sql The SQL to execute. + * @param conn The Connection to use to run the query. The caller is + * responsible for closing this Connection. + * @param sql The SQL to execute. * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. + * this array is one set of batch replacement values. * @return The number of rows updated per statement. * @throws SQLException if a database access error occurs * @since DbUtils 1.1 @@ -138,9 +138,9 @@ public class QueryRunner extends AbstractQueryRunner { * set in the constructor. This Connection must be in * auto-commit mode or the update will not be saved. * - * @param sql The SQL to execute. + * @param sql The SQL to execute. * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. + * this array is one set of batch replacement values. * @return The number of rows updated per statement. * @throws SQLException if a database access error occurs * @since DbUtils 1.1 @@ -153,11 +153,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Calls update after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the batch call. + * + * @param conn The connection to use for the batch call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. + * @param sql The SQL statement to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. * @return The number of rows updated in the batch. * @throws SQLException If there are database or parameter errors. */ @@ -192,7 +193,7 @@ public class QueryRunner extends AbstractQueryRunner { rows = stmt.executeBatch(); } catch (SQLException e) { - this.rethrow(e, sql, (Object[])params); + this.rethrow(e, sql, (Object[]) params); } finally { close(stmt); if (closeConn) { @@ -206,11 +207,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL SELECT query with a single replacement parameter. The * caller is responsible for closing the connection. - * @param The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. + * + * @param The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. * @param param The replacement parameter. - * @param rsh The handler that converts the results into an object. + * @param rsh The handler that converts the results into an object. * @return The object returned by the handler. * @throws SQLException if a database access error occurs * @deprecated Use {@link #query(Connection, String, ResultSetHandler, Object...)} @@ -223,14 +225,15 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL SELECT query with replacement parameters. The * caller is responsible for closing the connection. - * @param The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. + * + * @param The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. * @param params The replacement parameters. - * @param rsh The handler that converts the results into an object. + * @param rsh The handler that converts the results into an object. * @return The object returned by the handler. * @throws SQLException if a database access error occurs - * @deprecated Use {@link #query(Connection,String,ResultSetHandler,Object...)} instead + * @deprecated Use {@link #query(Connection, String, ResultSetHandler, Object...)} instead */ @Deprecated public T query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException { @@ -240,25 +243,44 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL SELECT query with replacement parameters. The * caller is responsible for closing the connection. - * @param The type of object that the handler returns - * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param rsh The handler that converts the results into an object. + * + * @param The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param rsh The handler that converts the results into an object. * @param params The replacement parameters. * @return The object returned by the handler. * @throws SQLException if a database access error occurs */ public T query(Connection conn, String sql, ResultSetHandler rsh, Object... params) throws SQLException { + return query(conn, sql, 0, rsh, params); + } + + /** + * Execute an SQL SELECT query with replacement parameters. The + * caller is responsible for closing the connection. + * + * @param The type of object that the handler returns + * @param conn The connection to execute the query in. + * @param sql The query to execute. + * @param timeout The query execute timeout. + * @param rsh The handler that converts the results into an object. + * @param params The replacement parameters. + * @return The object returned by the handler. + * @throws SQLException if a database access error occurs + */ + public T query(Connection conn, String sql, int timeout, ResultSetHandler rsh, Object... params) throws SQLException { return this.query(conn, false, sql, rsh, params); } /** * Execute an SQL SELECT query without any replacement parameters. The * caller is responsible for closing the connection. - * @param The type of object that the handler returns + * + * @param The type of object that the handler returns * @param conn The connection to execute the query in. - * @param sql The query to execute. - * @param rsh The handler that converts the results into an object. + * @param sql The query to execute. + * @param rsh The handler that converts the results into an object. * @return The object returned by the handler. * @throws SQLException if a database access error occurs */ @@ -270,12 +292,12 @@ public class QueryRunner extends AbstractQueryRunner { * Executes the given SELECT SQL with a single replacement parameter. * The Connection is retrieved from the * DataSource set in the constructor. - * @param The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param param The replacement parameter. - * @param rsh The handler used to create the result object from - * the ResultSet. * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param param The replacement parameter. + * @param rsh The handler used to create the result object from + * the ResultSet. * @return An object generated by the handler. * @throws SQLException if a database access error occurs * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} @@ -291,14 +313,13 @@ public class QueryRunner extends AbstractQueryRunner { * Executes the given SELECT SQL query and returns a result object. * The Connection is retrieved from the * DataSource set in the constructor. - * @param The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param params Initialize the PreparedStatement's IN parameters with - * this array. - * - * @param rsh The handler used to create the result object from - * the ResultSet. * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param params Initialize the PreparedStatement's IN parameters with + * this array. + * @param rsh The handler used to create the result object from + * the ResultSet. * @return An object generated by the handler. * @throws SQLException if a database access error occurs * @deprecated Use {@link #query(String, ResultSetHandler, Object...)} @@ -314,30 +335,48 @@ public class QueryRunner extends AbstractQueryRunner { * Executes the given SELECT SQL query and returns a result object. * The Connection is retrieved from the * DataSource set in the constructor. - * @param The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the ResultSet. + * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet. * @param params Initialize the PreparedStatement's IN parameters with - * this array. + * this array. * @return An object generated by the handler. * @throws SQLException if a database access error occurs */ public T query(String sql, ResultSetHandler rsh, Object... params) throws SQLException { - Connection conn = this.prepareConnection(); - return this.query(conn, true, sql, rsh, params); + return query(sql,0,rsh,params); } + /** + * Executes the given SELECT SQL query and returns a result object. + * The Connection is retrieved from the + * DataSource set in the constructor. + * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet. + * @param params Initialize the PreparedStatement's IN parameters with + * this array. + * @return An object generated by the handler. + * @throws SQLException if a database access error occurs + */ + public T query(String sql,int timeout, ResultSetHandler rsh, Object... params) throws SQLException { + Connection conn = this.prepareConnection(); + return this.query(conn, true, sql,timeout, rsh, params); + } /** * Executes the given SELECT SQL without any replacement parameters. * The Connection is retrieved from the * DataSource set in the constructor. + * * @param The type of object that the handler returns * @param sql The SQL statement to execute. * @param rsh The handler used to create the result object from - * the ResultSet. - * + * the ResultSet. * @return An object generated by the handler. * @throws SQLException if a database access error occurs */ @@ -349,16 +388,34 @@ public class QueryRunner extends AbstractQueryRunner { /** * Calls query after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the query call. + * + * @param conn The connection to use for the query call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of query replacement parameters. Each row in - * this array is one set of batch replacement values. + * @param sql The SQL statement to execute. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. * @return The results of the query. * @throws SQLException If there are database or parameter errors. */ private T query(Connection conn, boolean closeConn, String sql, ResultSetHandler rsh, Object... params) throws SQLException { + return query(conn, closeConn, sql, 0, rsh, params); + } + + /** + * Calls query after checking the parameters to ensure nothing is null. + * + * @param conn The connection to use for the query call. + * @param closeConn True if the connection should be closed, false otherwise. + * @param sql The SQL statement to execute. + * @param timeout The SQL statement to execute timeout. + * @param params An array of query replacement parameters. Each row in + * this array is one set of batch replacement values. + * @return The results of the query. + * @throws SQLException If there are database or parameter errors. + */ + private T query(Connection conn, boolean closeConn, String sql, int timeout, ResultSetHandler rsh, Object... params) + throws SQLException { if (conn == null) { throw new SQLException("Null connection"); } @@ -383,6 +440,9 @@ public class QueryRunner extends AbstractQueryRunner { try { stmt = this.prepareStatement(conn, sql); + if (timeout != 0) { + stmt.setQueryTimeout(timeout); + } this.fillStatement(stmt, params); rs = this.wrap(stmt.executeQuery()); result = rsh.handle(rs); @@ -409,7 +469,7 @@ public class QueryRunner extends AbstractQueryRunner { * parameters. * * @param conn The connection to use to run the query. - * @param sql The SQL to execute. + * @param sql The SQL to execute. * @return The number of rows updated. * @throws SQLException if a database access error occurs */ @@ -421,8 +481,8 @@ public class QueryRunner extends AbstractQueryRunner { * Execute an SQL INSERT, UPDATE, or DELETE query with a single replacement * parameter. * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. * @param param The replacement parameter. * @return The number of rows updated. * @throws SQLException if a database access error occurs @@ -434,8 +494,8 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL INSERT, UPDATE, or DELETE query. * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. * @param params The query replacement parameters. * @return The number of rows updated. * @throws SQLException if a database access error occurs @@ -452,8 +512,8 @@ public class QueryRunner extends AbstractQueryRunner { * not be saved. * * @param sql The SQL statement to execute. - * @throws SQLException if a database access error occurs * @return The number of rows updated. + * @throws SQLException if a database access error occurs */ public int update(String sql) throws SQLException { Connection conn = this.prepareConnection(); @@ -468,10 +528,10 @@ public class QueryRunner extends AbstractQueryRunner { * This Connection must be in auto-commit mode or the * update will not be saved. * - * @param sql The SQL statement to execute. + * @param sql The SQL statement to execute. * @param param The replacement parameter. - * @throws SQLException if a database access error occurs * @return The number of rows updated. + * @throws SQLException if a database access error occurs */ public int update(String sql, Object param) throws SQLException { Connection conn = this.prepareConnection(); @@ -485,11 +545,11 @@ public class QueryRunner extends AbstractQueryRunner { * set in the constructor. This Connection must be in * auto-commit mode or the update will not be saved. * - * @param sql The SQL statement to execute. + * @param sql The SQL statement to execute. * @param params Initializes the PreparedStatement's IN (i.e. '?') - * parameters. - * @throws SQLException if a database access error occurs + * parameters. * @return The number of rows updated. + * @throws SQLException if a database access error occurs */ public int update(String sql, Object... params) throws SQLException { Connection conn = this.prepareConnection(); @@ -499,11 +559,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Calls update after checking the parameters to ensure nothing is null. - * @param conn The connection to use for the update call. + * + * @param conn The connection to use for the update call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. + * @param sql The SQL statement to execute. + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. * @return The number of rows updated. * @throws SQLException If there are database or parameter errors. */ @@ -544,10 +605,11 @@ public class QueryRunner extends AbstractQueryRunner { * Executes the given INSERT SQL without any replacement parameters. * The Connection is retrieved from the * DataSource set in the constructor. + * * @param The type of object that the handler returns * @param sql The SQL statement to execute. * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * the ResultSet of auto-generated keys. * @return An object generated by the handler. * @throws SQLException if a database access error occurs * @since 1.6 @@ -561,10 +623,11 @@ public class QueryRunner extends AbstractQueryRunner { * Connection is retrieved from the DataSource * set in the constructor. This Connection must be in * auto-commit mode or the insert will not be saved. - * @param The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. * @param params Initializes the PreparedStatement's IN (i.e. '?') * @return An object generated by the handler. * @throws SQLException if a database access error occurs @@ -576,11 +639,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL INSERT query without replacement parameters. - * @param The type of object that the handler returns + * + * @param The type of object that the handler returns * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. * @return An object generated by the handler. * @throws SQLException if a database access error occurs * @since 1.6 @@ -591,11 +655,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Execute an SQL INSERT query. - * @param The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * + * @param The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. * @param params The query replacement parameters. * @return An object generated by the handler. * @throws SQLException if a database access error occurs @@ -607,12 +672,13 @@ public class QueryRunner extends AbstractQueryRunner { /** * Executes the given INSERT SQL statement. - * @param conn The connection to use for the query call. + * + * @param conn The connection to use for the query call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. - * @param params The query replacement parameters. + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. + * @param params The query replacement parameters. * @return An object generated by the handler. * @throws SQLException If there are database or parameter errors. * @since 1.6 @@ -663,10 +729,11 @@ public class QueryRunner extends AbstractQueryRunner { * Connection is retrieved from the DataSource * set in the constructor. This Connection must be in * auto-commit mode or the insert will not be saved. - * @param The type of object that the handler returns - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * + * @param The type of object that the handler returns + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. * @param params Initializes the PreparedStatement's IN (i.e. '?') * @return The result generated by the handler. * @throws SQLException if a database access error occurs @@ -678,11 +745,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Executes the given batch of INSERT SQL statements. - * @param The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. + * + * @param The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. * @param params The query replacement parameters. * @return The result generated by the handler. * @throws SQLException if a database access error occurs @@ -694,12 +762,13 @@ public class QueryRunner extends AbstractQueryRunner { /** * Executes the given batch of INSERT SQL statements. - * @param conn The connection to use for the query call. + * + * @param conn The connection to use for the query call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The handler used to create the result object from - * the ResultSet of auto-generated keys. - * @param params The query replacement parameters. + * @param sql The SQL statement to execute. + * @param rsh The handler used to create the result object from + * the ResultSet of auto-generated keys. + * @param params The query replacement parameters. * @return The result generated by the handler. * @throws SQLException If there are database or parameter errors. * @since 1.6 @@ -738,7 +807,7 @@ public class QueryRunner extends AbstractQueryRunner { generatedKeys = rsh.handle(rs); } catch (SQLException e) { - this.rethrow(e, sql, (Object[])params); + this.rethrow(e, sql, (Object[]) params); } finally { close(stmt); if (closeConn) { @@ -762,8 +831,8 @@ public class QueryRunner extends AbstractQueryRunner { * If the stored procedure returns result sets, use * {@link #execute(java.sql.Connection, java.lang.String, org.apache.commons.dbutils.ResultSetHandler, java.lang.Object...) }. * - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. * @param params The query replacement parameters. * @return The number of rows updated. * @throws SQLException if a database access error occurs @@ -789,10 +858,10 @@ public class QueryRunner extends AbstractQueryRunner { * set in the constructor. This Connection must be in * auto-commit mode or the update will not be saved. * - * @param sql The SQL statement to execute. + * @param sql The SQL statement to execute. * @param params Initializes the CallableStatement's parameters (i.e. '?'). - * @throws SQLException if a database access error occurs * @return The number of rows updated. + * @throws SQLException if a database access error occurs */ public int execute(String sql, Object... params) throws SQLException { Connection conn = this.prepareConnection(); @@ -814,10 +883,10 @@ public class QueryRunner extends AbstractQueryRunner { * {@link #execute(java.sql.Connection, java.lang.String, java.lang.Object...) } * (if there are no result sets). * - * @param The type of object that the handler returns - * @param conn The connection to use to run the query. - * @param sql The SQL to execute. - * @param rsh The result set handler + * @param The type of object that the handler returns + * @param conn The connection to use to run the query. + * @param sql The SQL to execute. + * @param rsh The result set handler * @param params The query replacement parameters. * @return A list of objects generated by the handler * @throws SQLException if a database access error occurs @@ -840,9 +909,9 @@ public class QueryRunner extends AbstractQueryRunner { * {@link #execute(java.lang.String, java.lang.Object...) } * (if there are no result sets). * - * @param The type of object that the handler returns - * @param sql The SQL to execute. - * @param rsh The result set handler + * @param The type of object that the handler returns + * @param sql The SQL to execute. + * @param rsh The result set handler * @param params The query replacement parameters. * @return A list of objects generated by the handler * @throws SQLException if a database access error occurs @@ -856,11 +925,12 @@ public class QueryRunner extends AbstractQueryRunner { /** * Invokes the stored procedure via update after checking the parameters to * ensure nothing is null. - * @param conn The connection to use for the update call. + * + * @param conn The connection to use for the update call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. + * @param sql The SQL statement to execute. + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. * @return The number of rows updated. * @throws SQLException If there are database or parameter errors. */ @@ -902,12 +972,13 @@ public class QueryRunner extends AbstractQueryRunner { /** * Invokes the stored procedure via update after checking the parameters to * ensure nothing is null. - * @param conn The connection to use for the update call. + * + * @param conn The connection to use for the update call. * @param closeConn True if the connection should be closed, false otherwise. - * @param sql The SQL statement to execute. - * @param rsh The result set handler - * @param params An array of update replacement parameters. Each row in - * this array is one set of update replacement values. + * @param sql The SQL statement to execute. + * @param rsh The result set handler + * @param params An array of update replacement parameters. Each row in + * this array is one set of update replacement values. * @return List of all objects generated by the ResultSetHandler for all result sets handled. * @throws SQLException If there are database or parameter errors. */ @@ -969,17 +1040,18 @@ public class QueryRunner extends AbstractQueryRunner { * Set the value on all the {@link OutParameter} instances in the * params array using the OUT parameter values from the * stmt. - * @param stmt the statement from which to retrieve OUT parameter values + * + * @param stmt the statement from which to retrieve OUT parameter values * @param params the parameter array for the statement invocation * @throws SQLException when the value could not be retrieved from the - * statement. + * statement. */ @SuppressWarnings("rawtypes") - private void retrieveOutParameters(CallableStatement stmt, Object[] params) throws SQLException { + private void retrieveOutParameters(CallableStatement stmt, Object[] params) throws SQLException { if (params != null) { for (int i = 0; i < params.length; i++) { if (params[i] instanceof OutParameter) { - ((OutParameter)params[i]).setValue(stmt, i + 1); + ((OutParameter) params[i]).setValue(stmt, i + 1); } } } diff --git a/core/src/test/java/com/github/drinkjava2/jsqlbox/helloworld/UsageAndSpeedTest.java b/core/src/test/java/com/github/drinkjava2/jsqlbox/helloworld/UsageAndSpeedTest.java index e5fc8cb3056a56e18427cfb14ebbd1c0bd99e27c..777187403c0fc3d8bd57325c0fa2433a40c8c2c0 100644 --- a/core/src/test/java/com/github/drinkjava2/jsqlbox/helloworld/UsageAndSpeedTest.java +++ b/core/src/test/java/com/github/drinkjava2/jsqlbox/helloworld/UsageAndSpeedTest.java @@ -1,13 +1,5 @@ package com.github.drinkjava2.jsqlbox.helloworld; -import static com.github.drinkjava2.jsqlbox.DB.TEMPLATE; -import static com.github.drinkjava2.jsqlbox.DB.bind; -import static com.github.drinkjava2.jsqlbox.DB.notNull; -import static com.github.drinkjava2.jsqlbox.DB.par; -import static com.github.drinkjava2.jsqlbox.DB.que; -import static com.github.drinkjava2.jsqlbox.DB.valuesQuestions; -import static com.github.drinkjava2.jsqlbox.DB.when; - import java.lang.reflect.Method; import java.sql.Connection; import java.sql.PreparedStatement; @@ -34,491 +26,522 @@ import com.github.drinkjava2.jsqlbox.DB; import com.github.drinkjava2.jsqlbox.DbContext; import com.zaxxer.hikari.HikariDataSource; +import static com.github.drinkjava2.jsqlbox.DB.*; + /** * Usage of different SQL style and speed test - * + * * @author Yong Zhu * @since 1.7.0 */ public class UsageAndSpeedTest { - static long REPEAT_TIMES = 1; - static boolean PRINT_TIMEUSED = false; - - protected HikariDataSource dataSource; - - @Before - public void init() { - dataSource = new HikariDataSource(); - dataSource.setJdbcUrl("jdbc:h2:mem:DBName;MODE=MYSQL;DB_CLOSE_DELAY=-1;TRACE_LEVEL_SYSTEM_OUT=0"); - dataSource.setDriverClassName("org.h2.Driver"); - dataSource.setUsername("sa");// change to your user & password - dataSource.setPassword(""); - DbContext ctx = new DbContext(dataSource); - DbContext.resetGlobalVariants(); - for (String ddl : ctx.getDialect().toDropAndCreateDDL(UserAR.class)) - try { - ctx.jdbcExecute(ddl); - } catch (Exception e) { - } - } - - @After - public void cleanUp() { - dataSource.close(); - } - - @Test - public void speedTest() throws Exception { - try { - PRINT_TIMEUSED = false; - REPEAT_TIMES = 1;// warm up - runTestMethods(); - PRINT_TIMEUSED = true; - REPEAT_TIMES = 10;// Change to 10000 to do speed test - System.out.println("Speed test, compare method execute time for repeat " + REPEAT_TIMES + " times:"); - runTestMethods(); - } finally { - PRINT_TIMEUSED = false; - REPEAT_TIMES = 1; - } - } - - private void runTestMethods() throws Exception { - runMethod("pureJdbc"); - runMethod("withConnection"); - runMethod("oldDbutilsMethods"); - runMethod("simpleMethods"); - runMethod("templateStyle"); - runMethod("dataMapperStyle"); - runMethod("activeRecordStyle"); - runMethod("activeRecordDefaultContext"); - } - - public void runMethod(String methodName) throws Exception { - long start = System.currentTimeMillis(); - Method m = ClassUtils.getMethod(this.getClass(), methodName); - m.invoke(this); - long end = System.currentTimeMillis(); - String timeused = "" + (end - start) / 1000 + "." + (end - start) % 1000; - if (PRINT_TIMEUSED) - System.out.println(String.format("%35s: %6s s", methodName, timeused)); - } - - @Table(name = "users") - public static class UserPOJO { - @Id - String name; - String address; - - public UserPOJO() { - } - - public UserPOJO(String name, String address) { - this.name = name; - this.address = address; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - } - - @Table(name = UserAR.TABLE) - public static class UserAR extends ActiveRecord { - public static final String TABLE = "users"; - public static final String NAME = "name"; - public static final String ADDRESS = "address"; - - @Id - @Column(name = "name") - String name; - String address; - Integer age; - - public UserAR() { - } - - public UserAR(String name, String address) { - this.name = name; - this.address = address; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - - } - - @Test - public void pureJdbc() { - for (int i = 0; i < REPEAT_TIMES; i++) { - Connection conn = null; - PreparedStatement pst = null; - ResultSet rs = null; - try { - conn = dataSource.getConnection(); - pst = conn.prepareStatement("insert into users (name,address) values(?,?)"); - pst.setString(1, "Sam"); - pst.setString(2, "Canada"); - pst.execute(); - pst.close(); - - pst = conn.prepareStatement("update users set name=?, address=?"); - pst.setString(1, "Tom"); - pst.setString(2, "China"); - pst.execute(); - pst.close(); - - pst = conn.prepareStatement("select count(*) from users where name=? and address=?"); - pst.setString(1, "Tom"); - pst.setString(2, "China"); - rs = pst.executeQuery(); - rs.next(); - Assert.assertEquals(1L, rs.getLong(1)); - - pst = conn.prepareStatement("delete from users where name=? or address=?"); - pst.setString(1, "Tom"); - pst.setString(2, "China"); - pst.execute(); - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - if (rs != null) - try { - rs.close(); - } catch (SQLException e) { - } - if (pst != null) - try { - pst.close(); - } catch (SQLException e) { - } - if (conn != null) - try { - conn.close(); - } catch (SQLException e) { - } - } - } - } - - @Test - public void withConnection() { - DbContext ctx = new DbContext(dataSource); - for (int i = 0; i < REPEAT_TIMES; i++) { - Connection conn = null; - try { - conn = ctx.prepareConnection(); - ctx.execute(conn, "insert into users (name,address) values(?,?)", "Sam", "Canada"); - ctx.execute(conn, "update users set name=?, address=?", "Tom", "China"); - Assert.assertEquals(1L, ctx.queryForLongValue(conn, - "select count(*) from users where name=? and address=?", "Tom", "China")); - ctx.execute(conn, "delete from users where name=? or address=?", "Tom", "China"); - } catch (SQLException e) { - Systemout.println("Exception found: " + e.getMessage()); - } finally { - try { - ctx.close(conn); - } catch (SQLException e) { - Systemout.println("Exception found: " + e.getMessage()); - } - } - } - } - - @Test - public void oldDbutilsMethods() { - DbContext ctx = new DbContext(dataSource); - for (int i = 0; i < REPEAT_TIMES; i++) { - try { - ctx.execute("insert into users (name,address) values(?,?)", "Sam", "Canada"); - ctx.execute("update users set name=?, address=?", "Tom", "China"); - Assert.assertEquals(1L, - ctx.queryForLongValue("select count(*) from users where name=? and address=?", "Tom", "China")); - ctx.execute("delete from users where name=? or address=?", "Tom", "China"); - } catch (SQLException e) { - Systemout.println("Exception found: " + e.getMessage()); - } - } - } - - @Test - public void simpleMethods() { - DbContext ctx = new DbContext(dataSource); - for (int i = 0; i < REPEAT_TIMES; i++) { - ctx.exe("insert into users (", // - notNull(" name ,", "Sam"), // - notNull(" someother ,", null), // - " address ", par("Canada"), // - ") ", valuesQuestions()); - ctx.exe("update users set name=?,address=?", par("Tom", "China")); - Assert.assertEquals(1L, ctx.qryLongValue("select count(*) from users where name=? and address=?", - par("Tom", "China"))); - ctx.exe("delete from users where name=", que("Tom"), " or address=", que("China")); - } - } - - @Test - public void templateStyle() { - DbContext ctx2 = new DbContext(dataSource); - Map paramMap = new HashMap(); - for (int i = 0; i < REPEAT_TIMES; i++) { - UserAR sam = new UserAR("Sam", "Canada"); - UserAR tom = new UserAR("Tom", "China"); - paramMap.put("user", sam); - ctx2.exe(TEMPLATE, "insert into users (name, address) values(#{user.name},:user.address)", paramMap); - ctx2.exe(TEMPLATE,"update users set name=#{user.name}, address=:user.address", bind("user", tom)); - Assert.assertEquals(1L, - ctx2.qryLongValue(TEMPLATE,"select count(*) from users where name=#{name} and address=:addr", - bind("name", "Tom", "addr", "China"))); - ctx2.exe(TEMPLATE,"delete from users where "// - , " name=:name ", bind("name", "Tom")// - , " or address=#{address}", bind("address", "China")// - ); - } - } - - @Test - public void dataMapperStyle() { - DbContext ctx = new DbContext(dataSource); - for (int i = 0; i < REPEAT_TIMES; i++) { - UserPOJO user = new UserPOJO(); - user.setName("Sam"); - user.setAddress("Canada"); - ctx.entityInsert(user); - user.setAddress("China"); - ctx.entityUpdateTry(user); - UserPOJO sam2 = ctx.entityLoadById(UserPOJO.class, "Sam"); - ctx.entityDeleteTry(sam2); - } - } - - @Test - public void activeRecordStyle() { - DbContext ctx = new DbContext(dataSource); - UserAR user = new UserAR(); - for (int i = 0; i < REPEAT_TIMES; i++) { - user.setName("Sam"); - user.setAddress("Canada"); - user.insert(ctx); - user.setAddress("China"); - user.update(ctx); - UserAR user2 = new UserAR().loadById("Sam",ctx); - user2.delete(ctx); - } - } - - @Test - public void activeRecordDefaultContext() { - DbContext ctx = new DbContext(dataSource); - DbContext.setGlobalDbContext(ctx);// use global default context - UserAR user = new UserAR(); - for (int i = 0; i < REPEAT_TIMES; i++) { - user.setName("Sam"); - user.setAddress("Canada"); - user.insert(); - user.setAddress("China"); - user.update(); - UserAR user2 = ctx.entityLoadById(UserAR.class, "Sam"); - user2.delete(); - } - } - - protected void BelowNotForSpeedTest_JustDoSomeUnitTest__________________() { - // below methods are for unit test only, not for speed test - } - - @Test - public void useAnotherSqlTemplateEngine() { - DbContext ctx = new DbContext(dataSource); - SqlTemplateEngine engine=new BasicSqlTemplate("[", "]", true, true);//default engine, change to use [] for param - UserAR user = new UserAR("Sam", "Canada"); - UserAR tom = new UserAR("Tom", "China"); - ctx.exe(engine,"insert into users (name, address) values([user.name], [user.address])", bind("user", user)); - ctx.exe(engine,"update users set name=[user.name], address=[user.address]", bind("user", tom)); - Assert.assertEquals(1L, - ctx.qryLongValue(engine,"select count(*) from users where ${col}= [name] and address=[addr]", - bind("name", "Tom"), bind("addr", "China"), bind("$col", "name"))); - ctx.exe(engine,"delete from users where ${nm}='${t.name}' or address=:u.address", bind("u", tom), bind("$t", tom), - bind("$nm", "name")); - } - - @Test - public void changeTemplateEngine() { - DbContext ctx = new DbContext(dataSource); - SqlTemplateEngine customizedEngine = new BasicSqlTemplate("[", "]", true, true);//customized sql engine - UserAR user = new UserAR("Sam", "Canada"); - UserAR tom = new UserAR("Tom", "China"); - //default template - ctx.exe(DB.TEMPLATE,"insert into users (name, address) values(#{user.name}, #{user.address})", bind("user", user)); - List lst=ctx.qryEntityList(TEMPLATE, UserPOJO.class, "select t.* from users t where t.name=:name", bind("name", "Sam")); - Assert.assertEquals(1, lst.size()); - - //below are customized engine - ctx.exe(customizedEngine, "update users set name=[user.name], address=[user.address]", bind("user", tom)); - Assert.assertEquals(1L, - ctx.qryLongValue(customizedEngine, "select count(*) from users where ${col}= [name] and address=[addr]", - bind("name", "Tom"), bind("addr", "China"), bind("$col", "name"))); - ctx.exe("delete from users where ${nm}='${t.name}' or address=:u.address", bind("u", tom), bind("$t", tom), - bind("$nm", "name"),customizedEngine); - } - - /** Use const String can make SQL support Java Bean field refactoring */ - @Test - public void supportRefactor() { - DbContext ctx = new DbContext(dataSource); - ctx.exe("insert into ", UserAR.TABLE, " ( ", // - UserAR.NAME, ",", par("Sam"), // - UserAR.ADDRESS, " ", par("Canada"), // - ") ", valuesQuestions()); - ctx.exe("delete from users where ", // - UserAR.NAME, "=", que("Sam"), // - " or ", UserAR.ADDRESS, "=", que("Canada")// - ); - } - - @Test - public void activeRecordLoadByIdMap() { - DbContext ctx = new DbContext(dataSource); - UserAR user = new UserAR(); - user.useContext(ctx); // Use ctx as DbContext - user.setName("Sam"); - user.setAddress("Canada"); - user.insert(); - user.setAddress("China"); - user.update(); - Map map = new HashMap(); - map.put("name", "Sam"); - UserAR user2 = new UserAR().useContext(ctx).loadById(map); - user2.delete(ctx); - } - - @Test - public void activeRecordLoadByQuery() { - DbContext ctx = new DbContext(dataSource); - UserAR user = new UserAR(); - user.useContext(ctx); // Use ctx as DbContext - user.setName("Sam"); - user.setAddress("Canada"); - user.insert(); - UserAR user2 = new UserAR().useContext(ctx).loadById(user.getName()); - Assert.assertEquals("Canada", user2.getAddress()); - } - - @Test - public void dataMapperCrudTest() { - DbContext ctx = new DbContext(dataSource); - // ctx.setAllowShowSQL(true); - UserAR user = new UserAR(); - for (int i = 1; i <= 10; i++) { - user.setName("Tom" + i); - user.setAddress("China" + i); - ctx.entityInsert(user); - } - user = new UserAR(); - user.setName("Tom8"); - ctx.entityLoad(user); - Assert.assertEquals("China8", user.getAddress()); - - user = ctx.entityLoadById(UserAR.class, "Tom7"); - Assert.assertEquals("China7", user.getAddress()); - - user.setAddress("Canada"); - ctx.entityUpdateTry(user); - Assert.assertEquals("Canada", ctx.entityLoadById(UserAR.class, "Tom7").getAddress()); - - ctx.entityDeleteTry(user); - ctx.entityDeleteTry(user, " or name=?", par("Tom2")); - - Assert.assertEquals(7, ctx.entityFind(UserAR.class, " where name>?", par("Tom1")).size()); - } - - @Test - public void conditionsQuery() { - DbContext ctx = new DbContext(dataSource); - ctx.setAllowShowSQL(true); - final String name = "Tom"; - final String age = null; - final String address = "China"; - ctx.exe("insert into users (", // - notNull(" name", name), // - notNull(" ,age ", age), // - " ,address ", par(address), // - ") ", valuesQuestions()); - ctx.exe("update users set ", // - notNull(" name", "=", "?, ", name), // - notNull(" age=?,", age), // - " address=? ", par(address), // - " where name is not null"// - ); - Assert.assertEquals(1L, ctx.qryLongValue(// - "select count(*) from users where 1=1 ", // - notNull(" and name=? ", name), // - "Tom".equals(name) ? ctx.prepare(" and name=? ", par(name)) : "", // - "China".equals(address) ? new Object[] {" and address= ", que(address)} : "",// - " order by name" - )); - ctx.jdbcExecute("delete from users"); - } - - @Test - public void conditionsQuery2() { //use "when" method to test - DbContext ctx = new DbContext(dataSource); - ctx.setAllowShowSQL(true); - final String name = "Tom"; - final String age = null; - final String address = "China"; - ctx.exe("insert into users (", // - " name", par(name), // - when(age!=null," ,age ", par(age)), // - " ,address ", par(address), // - ") ", valuesQuestions()); - ctx.exe("update users set ", // - " name=", que(name), // - when(age!=null, ", age=", que(age)), // - when(address!=null, ", address=", que(address)), // - " where name is not null" - ); - Assert.assertEquals(1L, ctx.qryLongValue(// - "select count(*) from users where 1=1 ", // - when(name!=null," and name=", que(name)),// - when("Tom".equals(name)," and name=", que(name)),// - when("China".equals(address)," and address=", que(address)),// - " order by name" - )); - ctx.jdbcExecute("delete from users"); - } - + static long REPEAT_TIMES = 1; + static boolean PRINT_TIMEUSED = false; + + protected HikariDataSource dataSource; + + @Before + public void init() { + dataSource = new HikariDataSource(); + dataSource.setJdbcUrl("jdbc:h2:mem:DBName;MODE=MYSQL;DB_CLOSE_DELAY=-1;TRACE_LEVEL_SYSTEM_OUT=0"); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUsername("sa");// change to your user & password + dataSource.setPassword(""); + DbContext ctx = new DbContext(dataSource); + DbContext.resetGlobalVariants(); + for (String ddl : ctx.getDialect().toDropAndCreateDDL(UserAR.class)) + try { + ctx.jdbcExecute(ddl); + } catch (Exception e) { + } + } + + @After + public void cleanUp() { + dataSource.close(); + } + + @Test + public void speedTest() throws Exception { + try { + PRINT_TIMEUSED = false; + REPEAT_TIMES = 1;// warm up + runTestMethods(); + PRINT_TIMEUSED = true; + REPEAT_TIMES = 10;// Change to 10000 to do speed test + System.out.println("Speed test, compare method execute time for repeat " + REPEAT_TIMES + " times:"); + runTestMethods(); + } finally { + PRINT_TIMEUSED = false; + REPEAT_TIMES = 1; + } + } + + private void runTestMethods() throws Exception { + runMethod("pureJdbc"); + runMethod("withConnection"); + runMethod("oldDbutilsMethods"); + runMethod("simpleMethods"); + runMethod("templateStyle"); + runMethod("dataMapperStyle"); + runMethod("activeRecordStyle"); + runMethod("activeRecordDefaultContext"); + } + + public void runMethod(String methodName) throws Exception { + long start = System.currentTimeMillis(); + Method m = ClassUtils.getMethod(this.getClass(), methodName); + m.invoke(this); + long end = System.currentTimeMillis(); + String timeused = "" + (end - start) / 1000 + "." + (end - start) % 1000; + if (PRINT_TIMEUSED) + System.out.println(String.format("%35s: %6s s", methodName, timeused)); + } + + @Table(name = "users") + public static class UserPOJO { + @Id + String name; + String address; + + public UserPOJO() { + } + + public UserPOJO(String name, String address) { + this.name = name; + this.address = address; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + } + + @Table(name = UserAR.TABLE) + public static class UserAR extends ActiveRecord { + public static final String TABLE = "users"; + public static final String NAME = "name"; + public static final String ADDRESS = "address"; + + @Id + @Column(name = "name") + String name; + String address; + Integer age; + + public UserAR() { + } + + public UserAR(String name, String address) { + this.name = name; + this.address = address; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + } + + @Test + public void pureJdbc() { + for (int i = 0; i < REPEAT_TIMES; i++) { + Connection conn = null; + PreparedStatement pst = null; + ResultSet rs = null; + try { + conn = dataSource.getConnection(); + pst = conn.prepareStatement("insert into users (name,address) values(?,?)"); + pst.setString(1, "Sam"); + pst.setString(2, "Canada"); + pst.execute(); + pst.close(); + + pst = conn.prepareStatement("update users set name=?, address=?"); + pst.setString(1, "Tom"); + pst.setString(2, "China"); + pst.execute(); + pst.close(); + + pst = conn.prepareStatement("select count(*) from users where name=? and address=?"); + pst.setString(1, "Tom"); + pst.setString(2, "China"); + rs = pst.executeQuery(); + rs.next(); + Assert.assertEquals(1L, rs.getLong(1)); + + pst = conn.prepareStatement("delete from users where name=? or address=?"); + pst.setString(1, "Tom"); + pst.setString(2, "China"); + pst.execute(); + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (rs != null) + try { + rs.close(); + } catch (SQLException e) { + } + if (pst != null) + try { + pst.close(); + } catch (SQLException e) { + } + if (conn != null) + try { + conn.close(); + } catch (SQLException e) { + } + } + } + } + + @Test + public void withConnection() { + DbContext ctx = new DbContext(dataSource); + for (int i = 0; i < REPEAT_TIMES; i++) { + Connection conn = null; + try { + conn = ctx.prepareConnection(); + ctx.execute(conn, "insert into users (name,address) values(?,?)", "Sam", "Canada"); + ctx.execute(conn, "update users set name=?, address=?", "Tom", "China"); + Assert.assertEquals(1L, ctx.queryForLongValue(conn, + "select count(*) from users where name=? and address=?", "Tom", "China")); + ctx.execute(conn, "delete from users where name=? or address=?", "Tom", "China"); + } catch (SQLException e) { + Systemout.println("Exception found: " + e.getMessage()); + } finally { + try { + ctx.close(conn); + } catch (SQLException e) { + Systemout.println("Exception found: " + e.getMessage()); + } + } + } + } + + @Test + public void oldDbutilsMethods() { + DbContext ctx = new DbContext(dataSource); + for (int i = 0; i < REPEAT_TIMES; i++) { + try { + ctx.execute("insert into users (name,address) values(?,?)", "Sam", "Canada"); + ctx.execute("update users set name=?, address=?", "Tom", "China"); + Assert.assertEquals(1L, + ctx.queryForLongValue("select count(*) from users where name=? and address=?", "Tom", "China")); + ctx.execute("delete from users where name=? or address=?", "Tom", "China"); + } catch (SQLException e) { + Systemout.println("Exception found: " + e.getMessage()); + } + } + } + + @Test + public void simpleMethods() { + DbContext ctx = new DbContext(dataSource); + for (int i = 0; i < REPEAT_TIMES; i++) { + ctx.exe("insert into users (", // + notNull(" name ,", "Sam"), // + notNull(" someother ,", null), // + " address ", par("Canada"), // + ") ", valuesQuestions()); + ctx.exe("update users set name=?,address=?", par("Tom", "China")); + Assert.assertEquals(1L, ctx.qryLongValue("select count(*) from users where name=? and address=?", + par("Tom", "China"))); + ctx.exe("delete from users where name=", que("Tom"), " or address=", que("China")); + } + } + + @Test + public void templateStyle() { + DbContext ctx2 = new DbContext(dataSource); + Map paramMap = new HashMap(); + for (int i = 0; i < REPEAT_TIMES; i++) { + UserAR sam = new UserAR("Sam", "Canada"); + UserAR tom = new UserAR("Tom", "China"); + paramMap.put("user", sam); + ctx2.exe(TEMPLATE, "insert into users (name, address) values(#{user.name},:user.address)", paramMap); + ctx2.exe(TEMPLATE, "update users set name=#{user.name}, address=:user.address", bind("user", tom)); + Assert.assertEquals(1L, + ctx2.qryLongValue(TEMPLATE, "select count(*) from users where name=#{name} and address=:addr", + bind("name", "Tom", "addr", "China"))); + ctx2.exe(TEMPLATE, "delete from users where "// + , " name=:name ", bind("name", "Tom")// + , " or address=#{address}", bind("address", "China")// + ); + } + } + + @Test + public void dataMapperStyle() { + DbContext ctx = new DbContext(dataSource); + for (int i = 0; i < REPEAT_TIMES; i++) { + UserPOJO user = new UserPOJO(); + user.setName("Sam"); + user.setAddress("Canada"); + ctx.entityInsert(user); + user.setAddress("China"); + ctx.entityUpdateTry(user); + UserPOJO sam2 = ctx.entityLoadById(UserPOJO.class, "Sam"); + ctx.entityDeleteTry(sam2); + } + } + + @Test + public void activeRecordStyle() { + DbContext ctx = new DbContext(dataSource); + UserAR user = new UserAR(); + for (int i = 0; i < REPEAT_TIMES; i++) { + user.setName("Sam"); + user.setAddress("Canada"); + user.insert(ctx); + user.setAddress("China"); + user.update(ctx); + UserAR user2 = new UserAR().loadById("Sam", ctx); + user2.delete(ctx); + } + } + + @Test + public void activeRecordDefaultContext() { + DbContext ctx = new DbContext(dataSource); + DbContext.setGlobalDbContext(ctx);// use global default context + UserAR user = new UserAR(); + for (int i = 0; i < REPEAT_TIMES; i++) { + user.setName("Sam"); + user.setAddress("Canada"); + user.insert(); + user.setAddress("China"); + user.update(); + UserAR user2 = ctx.entityLoadById(UserAR.class, "Sam"); + user2.delete(); + } + } + + protected void BelowNotForSpeedTest_JustDoSomeUnitTest__________________() { + // below methods are for unit test only, not for speed test + } + + @Test + public void useAnotherSqlTemplateEngine() { + DbContext ctx = new DbContext(dataSource); + SqlTemplateEngine engine = new BasicSqlTemplate("[", "]", true, true);//default engine, change to use [] for param + UserAR user = new UserAR("Sam", "Canada"); + UserAR tom = new UserAR("Tom", "China"); + ctx.exe(engine, "insert into users (name, address) values([user.name], [user.address])", bind("user", user)); + ctx.exe(engine, "update users set name=[user.name], address=[user.address]", bind("user", tom)); + Assert.assertEquals(1L, + ctx.qryLongValue(engine, "select count(*) from users where ${col}= [name] and address=[addr]", + bind("name", "Tom"), bind("addr", "China"), bind("$col", "name"))); + ctx.exe(engine, "delete from users where ${nm}='${t.name}' or address=:u.address", bind("u", tom), bind("$t", tom), + bind("$nm", "name")); + } + + @Test + public void changeTemplateEngine() { + DbContext ctx = new DbContext(dataSource); + SqlTemplateEngine customizedEngine = new BasicSqlTemplate("[", "]", true, true);//customized sql engine + UserAR user = new UserAR("Sam", "Canada"); + UserAR tom = new UserAR("Tom", "China"); + //default template + ctx.exe(DB.TEMPLATE, "insert into users (name, address) values(#{user.name}, #{user.address})", bind("user", user)); + List lst = ctx.qryEntityList(TEMPLATE, UserPOJO.class, "select t.* from users t where t.name=:name", bind("name", "Sam")); + Assert.assertEquals(1, lst.size()); + + //below are customized engine + ctx.exe(customizedEngine, "update users set name=[user.name], address=[user.address]", bind("user", tom)); + Assert.assertEquals(1L, + ctx.qryLongValue(customizedEngine, "select count(*) from users where ${col}= [name] and address=[addr]", + bind("name", "Tom"), bind("addr", "China"), bind("$col", "name"))); + ctx.exe("delete from users where ${nm}='${t.name}' or address=:u.address", bind("u", tom), bind("$t", tom), + bind("$nm", "name"), customizedEngine); + } + + /** + * Use const String can make SQL support Java Bean field refactoring + */ + @Test + public void supportRefactor() { + DbContext ctx = new DbContext(dataSource); + ctx.exe("insert into ", UserAR.TABLE, " ( ", // + UserAR.NAME, ",", par("Sam"), // + UserAR.ADDRESS, " ", par("Canada"), // + ") ", valuesQuestions()); + ctx.exe("delete from users where ", // + UserAR.NAME, "=", que("Sam"), // + " or ", UserAR.ADDRESS, "=", que("Canada")// + ); + } + + @Test + public void activeRecordLoadByIdMap() { + DbContext ctx = new DbContext(dataSource); + UserAR user = new UserAR(); + user.useContext(ctx); // Use ctx as DbContext + user.setName("Sam"); + user.setAddress("Canada"); + user.insert(); + user.setAddress("China"); + user.update(); + Map map = new HashMap(); + map.put("name", "Sam"); + UserAR user2 = new UserAR().useContext(ctx).loadById(map); + user2.delete(ctx); + } + + @Test + public void activeRecordLoadByQuery() { + DbContext ctx = new DbContext(dataSource); + UserAR user = new UserAR(); + user.useContext(ctx); // Use ctx as DbContext + user.setName("Sam"); + user.setAddress("Canada"); + user.insert(); + UserAR user2 = new UserAR().useContext(ctx).loadById(user.getName()); + Assert.assertEquals("Canada", user2.getAddress()); + } + + @Test + public void dataMapperCrudTest() { + DbContext ctx = new DbContext(dataSource); + // ctx.setAllowShowSQL(true); + UserAR user = new UserAR(); + for (int i = 1; i <= 10; i++) { + user.setName("Tom" + i); + user.setAddress("China" + i); + ctx.entityInsert(user); + } + user = new UserAR(); + user.setName("Tom8"); + ctx.entityLoad(user); + Assert.assertEquals("China8", user.getAddress()); + + user = ctx.entityLoadById(UserAR.class, "Tom7"); + Assert.assertEquals("China7", user.getAddress()); + + user.setAddress("Canada"); + ctx.entityUpdateTry(user); + Assert.assertEquals("Canada", ctx.entityLoadById(UserAR.class, "Tom7").getAddress()); + + ctx.entityDeleteTry(user); + ctx.entityDeleteTry(user, " or name=?", par("Tom2")); + + Assert.assertEquals(7, ctx.entityFind(UserAR.class, " where name>?", par("Tom1")).size()); + } + + @Test + public void conditionsQuery() { + DbContext ctx = new DbContext(dataSource); + ctx.setAllowShowSQL(true); + final String name = "Tom"; + final String age = null; + final String address = "China"; + ctx.exe("insert into users (", // + notNull(" name", name), // + notNull(" ,age ", age), // + " ,address ", par(address), // + ") ", valuesQuestions()); + ctx.exe("update users set ", // + notNull(" name", "=", "?, ", name), // + notNull(" age=?,", age), // + " address=? ", par(address), // + " where name is not null"// + ); + Assert.assertEquals(1L, ctx.qryLongValue(// + "select count(*) from users where 1=1 ", // + notNull(" and name=? ", name), // + "Tom".equals(name) ? ctx.prepare(" and name=? ", par(name)) : "", // + "China".equals(address) ? new Object[]{" and address= ", que(address)} : "",// + " order by name" + )); + ctx.jdbcExecute("delete from users"); + } + + @Test + public void conditionsQuery2() { //use "when" method to test + DbContext ctx = new DbContext(dataSource); + ctx.setAllowShowSQL(true); + final String name = "Tom"; + final String age = null; + final String address = "China"; + ctx.exe("insert into users (", // + " name", par(name), // + when(age != null, " ,age ", par(age)), // + " ,address ", par(address), // + ") ", valuesQuestions()); + ctx.exe("update users set ", // + " name=", que(name), // + when(age != null, ", age=", que(age)), // + when(address != null, ", address=", que(address)), // + " where name is not null" + ); + Assert.assertEquals(1L, ctx.qryLongValue(// + "select count(*) from users where 1=1 ", // + when(name != null, " and name=", que(name)),// + when("Tom".equals(name), " and name=", que(name)),// + when("China".equals(address), " and address=", que(address)),// + " order by name" + )); + ctx.jdbcExecute("delete from users"); + } + + @Test + public void timeoutQuery() { + DbContext ctx = new DbContext(dataSource); + ctx.setAllowShowSQL(true); + final String name = "Tom"; + final String age = null; + final String address = "China"; + ctx.exe("insert into users (", // + " name", par(name), // + when(age != null, " ,age ", par(age)), // + " ,address ", par(address), // + ") ", valuesQuestions()); + try { + List> r1 = ctx.qryMapList("select * from users", timeout(1)); + Map r2 = ctx.qryMap("select * from users", timeout(1)); + String r3 = ctx.qryString("select name from users where name=?", par(name), timeout(1)); + System.out.println(); + } catch (Exception e) { + if (e instanceof SQLException) { + //test on PGSQL + if (e.getMessage().indexOf("cancelled") != -1 || e.getMessage().indexOf("timeout") != -1) { + System.out.println("execute sql timeout..."); + } + } + + } + } }