- 浏览: 157353 次
- 性别:
- 来自: 无锡
文章分类
最新评论
-
lgh1992314:
1.7public <T> List<T&g ...
Commons DbUtils 源码阅读四 -
lgh1992314:
it was too slow to call the met ...
Commons DbUtils 源码阅读四 -
lgh1992314:
toBeanList的存在位置有点变态
Commons DbUtils 源码阅读二 -
lgh1992314:
toBeanList的存在位置有点变态
Commons DbUtils 源码阅读二 -
hwwjason:
<target name="jar" ...
Apache Ant 实例介绍
关于DbUtils,我们深入剖析了对ResultSet解析处理的两个核心类:BeanProcessor和BasicRowProcessor,可以说,这两个类,是对ResultSet的解析有了一个完整的支持。虽然真正做解析工作的是这两个类,但用户对ResultSet的解析是通过接口ResultSetHandler<T>的这个实现类来封装解决的。但要解析的是,我们也得通过SQL语句获取ResultSet对象呀,所以,看看DbUtils是怎么做的。
一、QueryRunner类,利用可插拨的策略执行SQL查询来处理ResultSets,大致看了一下,该类的重载方法确实有够多。来一类一类的解决:
1)构造器有多个重载方法,有必要说明解析一下,现列出部分代码:
/** *QueryRunner 默认构造器 */ public QueryRunner() { super(); ds = null; } /** * 允许Oracle驱动程序的解决方案 * @param pmdKnownBroken 如果是Oracle drivers,则不支持 ParameterMetaData.getParameterType(int)这个方法; * if pmdKnownBroken参数设置为true,则我们不做 * ParameterMetaData.getParameterType(int)方法; * 如果为false,那将会尝试获取,如果不支持有异常抛出,则不再使用 */ public QueryRunner(boolean pmdKnownBroken) { super(); this.pmdKnownBroken = pmdKnownBroken; ds = null; } /** * QueryRunner构造器,Oracle drivers的解决方案. 通过DataSource * 获取数据源连接 * @param ds 数据源,用于获取数据连接Connection */ public QueryRunner(DataSource ds) { super(); this.ds = ds; } /** * QueryRunner构造器,Oracle drivers的解决方案. 通过DataSource * 获取数据源连接 * @param ds 数据源,用于获取数据连接Connection. * @param pmdKnownBroken 如果是Oracle drivers,则不支持 ParameterMetaData.getParameterType(int)这个方法; * if pmdKnownBroken参数设置为true,则我们不做 * ParameterMetaData.getParameterType(int)方法; * 如果为false,那将会尝试获取,如果不支持有异常抛出,则不再使用 */ public QueryRunner(DataSource ds, boolean pmdKnownBroken) { super(); this.pmdKnownBroken = pmdKnownBroken; this.ds = ds; }
本身这个构造器并没有什么,关键是boolean类型的pmdKnownBroken和DataSource类型的ds。DataSource呢,很明显,是通过它来获取数据库连接,如何程式获取DataSource对象,这得需要借助于commons里的dbcp和pool这两个组件。具体的如何获取,可以参考DBCP组件的官方示例程序,具体网址如下:
http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/doc/BasicDataSourceExample.java?view=markup
这个类中的静态方法setupDataSource就是用来获取数据源的,说个题外话,DBCP和pool这两个组件对于数据源的管理,可谓是鼎鼎大名啊,Spring的数据源管理也是基于该组件,当然了还有另外一个数据源C3P0。关于数据源这一知识点,各位有兴趣的朋友可以参考在下写的“Spring 数据源不同配置 ”,扯远了啊,呵~咱接着说pmdKnownBroken这个变量,虽然现在说起来可能感觉有些抽象。源码的解释是这样的:Oracle的驱动程序不支持ParameterMetaData.getParameterType方法,如果pmdKnownBroken设置为true,则我们甚至不进行尝试处理,而false,我们则会尝试着使用ParameterMetaData.getParameterType方法,如果有异常抛出,则不再使用。
2)一般来说数据库操作的时候,总是会顺口溜似的:增删改查,所以我们先从QueryRunner类的SQL增加操作说起,看了一下这个类的大概实现,实际上呢,update方法它不仅充当了SQL增加操作,同时也充当了更新和删除的操作,所以,一并了解了吧:
/** * 执行一个没有参数的SQL插入、更新或者删除操作 * Execute an SQL INSERT, UPDATE, or DELETE query without replacement * parameters. * * @param conn 数据连接The connection to use to run the query. * @param sql 要执行的SQL语句The SQL to execute. * @return 更新的行数The number of rows updated. * @throws SQLException 数据库访问异常if a database access error occurs */ public int update(Connection conn, String sql) throws SQLException { return this.update(conn, sql, (Object[]) null); } /** * 执行只有一个参数的SQL插入、修改或者删除操作 * @param conn 执行查询的数据库连接 * @param sql 要执行的SQL语句 * @return 更新的行数 * @throws SQLException 数据库访问异常 */ public int update(Connection conn, String sql, Object param) throws SQLException { return this.update(conn, sql, new Object[] { param }); } /** * 执行指定没有参数的插入、修改或者删除的SQL语句。 * 数据连接通过DataSource(在构造器中指定)获取。 * 此连接必须在自动提交模式,否则会导致更新操作不会保存。 * @param sql 要执行的SQL语句 * @throws SQLException 数据库访问异常 * @return 更新的行数 */ public int update(String sql) throws SQLException { return this.update(sql, (Object[]) null); } /** * 执行指定只有一个参数的插入、修改或者删除的SQL语句。 * 数据连接通过DataSource(在构造器中指定)获取。 * 此连接必须在自动提交模式,否则会导致更新操作不会保存。 * * @param sql 要执行的SQL语句 * @param param 参数 * @throws SQLException 数据库访问异常 * @return 更新的行数 */ public int update(String sql, Object param) throws SQLException { return this.update(sql, new Object[] { param }); } /** * 执行指定的插入、修改或者删除的SQL语句。 * 数据连接通过DataSource(在构造器中指定)获取。 * 此连接必须在自动提交模式,否则会导致更新操作不会保存。 * * @param sql 要执行的SQL语句 * @param params 初始化PreparedStatement参数 * @throws SQLException 数据库访问异常 * @return 更新的行数 */ public int update(String sql, Object... params) throws SQLException { Connection conn = this.prepareConnection(); try { return this.update(conn, sql, params); } finally { close(conn); } }
真是巨多啊!我在每个方法上,都将源码上面的一些说明解释成了中文,各位有兴趣的可以看看。
挑两个具有代表性的方法来读一下:
2-1)获取数据库连接,这个呢,源码上面的说明也说了,是通过DataSource来获取的,具体看看prepareConnection()这个方法:
protected Connection prepareConnection() throws SQLException { if(this.getDataSource() == null) { throw new SQLException("QueryRunner requires a DataSource to be " + "invoked in this way, or a Connection should be passed in"); } return this.getDataSource().getConnection(); }
这个方法比较的简单,首先是获取数据源实例,如果数据源为空,则抛出异常:必须要有一个DataSource,然后呢,就会获取一个Connection实例返回。这个DataSource实例呢,是在实例化的时候指定的,当然了,我们也可以子类重写这个prepareConnection方法,来实现一个指定的获取数据库连接的方法。
2-2)
/** * 执行一个SQL插入、更新或者删除操作 * @param conn 执行查询的数据库连接 * @param sql 要执行的SQL语句 * @return 更新的行数 * @throws SQLException 数据库访问异常 */ public int update(Connection conn, String sql, Object... params) throws SQLException { PreparedStatement stmt = null; int rows = 0; try { stmt = this.prepareStatement(conn, sql);//通过Connection和sql获取PreparedStatement实例 this.fillStatement(stmt, params); rows = stmt.executeUpdate(); } catch (SQLException e) { this.rethrow(e, sql, params); } finally { close(stmt); } return rows; }
来,一步一步的执行这个核心方法,首先,通过prepareStatement这个方法,传入数据库连接和SQL这两个参数
得到一个PreparedStatement对象实例;然后通过fillStatement方法填充参数值,看看具体实现:
/** * 通过指定对象填充PreparedStatement的代替参数。 * @param stmt PreparedStatement to fill * @param params 查询替代参数; null也是有效的参数。 * @throws SQLException 数据库访问异常 */ public void fillStatement(PreparedStatement stmt, Object... params) throws SQLException { if (params == null) {//参数为空,则返回 return; } ParameterMetaData pmd = null; if (!pmdKnownBroken){//false,we try it pmd = stmt.getParameterMetaData();//获取关于PreparedStatement 对象中参数的类型和属性信息的对象 if (pmd.getParameterCount() < params.length) {//如果PreparedStatement需要的参数数量少于指定参数数量,则抛出数量不匹配异常 throw new SQLException("Too many parameters: expected " + pmd.getParameterCount() + ", was given " + params.length); } } //循环参数 for (int i = 0; i < params.length; i++) { if (params[i] != null) {//如果指定的参数不为空,则指定参数值 stmt.setObject(i + 1, params[i]); } else { // VARCHAR类型可以与许多的驱动工作,而不管真实的列类型. // 奇怪的是,NULL和OTHER与Oracle的驱动不能工作. // VARCHAR works with many drivers regardless // of the actual column type. Oddly, NULL and // OTHER don't work with Oracle's drivers. int sqlType = Types.VARCHAR; if (!pmdKnownBroken) {//false try { sqlType = pmd.getParameterType(i + 1);//获取特定的参数类型 } catch (SQLException e) { pmdKnownBroken = true;//如果不支持getParameterType方法,则不再尝试使用 } } stmt.setNull(i + 1, sqlType);//为特定类型赋空值 } } }
我已经对这个方法做了一些必要的说明,实际上呢,最需要强调的,就是pmdKnownBroken参数以及Oracle驱动的关系,pmdKnownBroken这个参数呢,我们已经在构造器那一块说过了,它实际上用于区别Oracle驱动, 说是Oracle驱动不支持getParameterType方法,我是不清楚了,没有使用过,所以没有发言权,但我想这个问题应该会有所解决.另一个批量查询方法batch,主要方法是与update方法类似的,故不再解析。现在呢,主要的方法体功能已经了解完了。
3)接下来呢,理论上应该是SQL的查询方法解析了,但我看了一下query方法,需要说明的,我们都已经在之前的update方法里拜读过了,唯一不同的是就是多了一个ResultSetHandler<T>参数,之前呢,我有说过ResultSetHandler这个接口,它通过调用handler方法处理ResultSet结果集完成指定类型的转换,本身dbUtils组件呢,提供了众多的ResultSetHandler实现类,它们都位于org.apache.commons.dbutils.handlers的包下,我会在以后的章节中具体解析。
4)具体来说明一下QueryRunner这个类中的fillStatementWithBean这个方法,在整个组件中暂未用到,但,我想在面向对象的Java开发中,通过指定的bean实例,为SQL语句参数指定bean变量值肯定是会广泛应用的,也就是JavaBean与特定数据表的映射了。Hibernate、JPA等框架能够自动完成对象与关系型数据库的映射,底层的实现也诸如此类吧!
/** * 根据bean的属性值填充PerparedStatement的参数 * @param stmt * 待填充值的PreparedStatement * @param bean * JavaBean对象 * @param propertyNames * 有序的属性名称数组(这些名字应该有 * getters/setters方法匹配);这个属性数组顺序与statement的插入参数顺序匹配 * @throws SQLException * 数据访问异常 */ public void fillStatementWithBean(PreparedStatement stmt, Object bean, String... propertyNames) throws SQLException { PropertyDescriptor[] descriptors; try { descriptors = Introspector.getBeanInfo(bean.getClass()) .getPropertyDescriptors(); //4-1 }catch(IntrospectionException e){ throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e); } PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];//4-2 //参数名与Bean的属性进行比较,确保属性的完整性 //确保为每个属性名找到在bean中对应的PropertyDescriptor实例 for (int i = 0; i < propertyNames.length; i++) { String propertyName = propertyNames[i]; if (propertyName == null) {//属性列表里的属性不能为空 throw new NullPointerException("propertyName can't be null: " + i); } boolean found = false; for (int j = 0; j < descriptors.length; j++) {//4-3 PropertyDescriptor descriptor = descriptors[j]; if (propertyName.equals(descriptor.getName())) { sorted[i] = descriptor;//此属性在bean中存在,赋于PropertyDescriptor实例 found = true; break; } } if (!found) { throw new RuntimeException("Couldn't find bean property: " + bean.getClass() + " " + propertyName); } } fillStatementWithBean(stmt, bean, sorted);//4-4 }
这个方法做的事情是这样的,就是通过指定一个Javabean实例和一个PreparedStatement的参数名数组为PreparedStatement填充对应的参数值。当然了,这些参数名都是JavaBean实例里的属性了。来看看具体的实现过程:
4-1)通过内省机制获取指定bean实例的PropertyDescriptor[]数组,这样呢,就有了对bean属性的直接操作能力了;
4-2)根据指定的参数名数组propertyNames,实例化一个PropertyDescriptor[]数组,这个数组,主要的呢,就是存储PreparedStatement指定的参数名对应bean实例中的属性的PropertyDescriptor对象;
4-3)循环4-1)中Bean实例的PropertyDescriptor数组,如果通过PropertyDescriptor实例获取的属性名与指定的propertyNames相同,则将对应的PeropertyDescriptor实例赋给4-2)中声明的数组;
4-4)4-1~4-3,这个应该算是真正实现PreparedStatement赋值的前期初始化工作吧,这个fillStatementWithBean的重载方法通过指定stmt中参数的bean实例对应的属性描述数组,下面来看看具体的实现代码吧:
/** * * 根据bean的属性值填充PerparedStatement的参数 * @param stmt * 待填充值的PreparedStatement * @param bean * JavaBean对象 * @param properties * 指定顺序数组;与PreparedStatement的参数顺序一致 * @throws SQLException * 数据访问异常 */ public void fillStatementWithBean(PreparedStatement stmt, Object bean, PropertyDescriptor[] properties) throws SQLException { Object[] params = new Object[properties.length];//属性值的数组 for (int i = 0; i < properties.length; i++) { PropertyDescriptor property = properties[i]; Object value = null; Method method = property.getReadMethod();//获取属性对应的getter方法 if (method == null) { throw new RuntimeException("No read method for bean property " + bean.getClass() + " " + property.getName()); } try { value = method.invoke(bean, new Object[0]);//通过反射调用获取属性值 } catch (InvocationTargetException e) { throw new RuntimeException("Couldn't invoke method: " + method, e); } catch (IllegalArgumentException e) { throw new RuntimeException("Couldn't invoke method with 0 arguments: " + method, e); } catch (IllegalAccessException e) { throw new RuntimeException("Couldn't invoke method: " + method, e); } params[i] = value;//设置属性值 } fillStatement(stmt, params); }
这个方法我还真的有点懒得再说明下去了,浪费太多面板罗,OK,这个类的解析到此为此吧。
二、QueryLoader类,是一个从一个文件加载查询到一个Map的简单的类。然后,当需要的时候,你从Map中选择一些查询。当然了,这个方法的实现是比较简单的。现看看文件载入的源代码:
/** * 载入一个查询命名和SQL值映射的Map集合. * 此Map被缓存以便以后相同路径的请求可以返回被缓存的Map * Loads a Map of query names to SQL values. The Maps are cached so a * subsequent request to load queries from the same path will return * the cached Map. * * @param path The path that the ClassLoader will use to find the file. * ClassLoader通过path查找文件 * * This is <strong>not</strong> a file system path. If you had a jarred * Queries.properties file in the com.yourcorp.app.jdbc package you would * pass "/com/yourcorp/app/jdbc/Queries.properties" to this method. * 这不是一个文件系统路径。如果你有一个Queries.properties文件在com.yourcorp.app.jdbc这个包下, * 那么你应该传递"/com/yourcorp/app/jdbc/Queries.properties"参数到这个方法. * * @throws IOException if a file access error occurs * @throws IllegalArgumentException if the ClassLoader can't find a file at * the given path. * @return Map of query names to SQL values */ public synchronized Map<String,String> load(String path) throws IOException { Map<String,String> queryMap = (Map<String,String>) this.queries.get(path); if (queryMap == null) { queryMap = this.loadQueries(path); this.queries.put(path, queryMap); } return queryMap; }
这个方法加入了同步锁机制,所以是线程安全的,这个方法需要注意的一点就是传入的路径,因为是通过ClassLoader载入,所以,传入的路径是绝对路径名。首先呢,先从本地的Map集合queries拿到路径名里对应的集合,如果为空,则说明没有缓存对不对,OK,没有就加呗,来loadQueries方法:
/** * Loads a set of named queries into a Map object. This implementation * reads a properties file at the given path. * * 加载命名查询集到一个Map对象中. * 这个实现用于读取给定路径的Properties文件 * * @param path The path that the ClassLoader will use to find the file. * ClassLoader使用指定的path去查找file * @throws IOException file访问异常 * @throws IllegalArgumentException ClassLoader查找不到指定路径的文件 * @since DbUtils 1.1 * @return Map of query names to SQL values 查询名称到SQL值的映射集合 */ @SuppressWarnings("unchecked") protected Map<String,String> loadQueries(String path) throws IOException { // Findbugs flags getClass().getResource as a bad practice; maybe we should change the API? InputStream in = getClass().getResourceAsStream(path);//获取指定文件的流对象 if (in == null) { throw new IllegalArgumentException(path + " not found."); } Properties props = new Properties(); props.load(in); // Copy to HashMap for better performance return new HashMap(props); }
哝,有没有?!通过ClassLoader载入指定文件流对象,如果为空,则会抛出找不到文件的异常。否则呢,载入Properties文件并以HashMap返回。
载入了未缓存的properties文件,那么,存一个:
this.queries.put(path, queryMap);
完成了载入、缓存,缓存这个东西呢是要占内存的,所以呢,不要缓存太多或者大的对象,除非有必要,建议各位用完就remove掉:
/** * Removes the queries for the given path from the cache. * 从缓存中删除指定的路径 * @param path The path that the queries were loaded from. * queries载入的路径 */ public synchronized void unload(String path){ this.queries.remove(path); }
好了,DbUtils这两个类的解析就到此为此吧,回头看看,发现DbUtils组件的一些主要的类都已经解析完成了,继续努力!
发表评论
-
Spring SpringMVC MyBatis MVN
2011-11-23 22:29 0突然想起用maven了,虽然早在今年上半年就有买了本书在看 ... -
Apache Lucene3.0 入门实例介绍
2011-05-24 23:02 1876咱这搞技术活儿的吧 ... -
Commons Logging 源码解析二
2011-05-18 22:52 0我们说过,Commons Loggi ... -
Commons Logging 源码解析一
2011-05-15 22:43 2079最近一段日子可真是够忙的,项目上线终于开始有回报了!一直要 ... -
Commons FileUpload 源码解析二
2011-04-14 23:03 0FileItemFactory: /** * ... -
Commons FileUpload 源码解析一
2011-04-14 20:39 0Commons FileUpload?! 哇噢~可以这样说 ... -
JExcelAPI(jxl)读写Excel应用
2011-04-04 23:51 10242这篇博文在我的草 ... -
Apache Axis 服务创建
2011-03-11 23:38 2300在Apache Axis了解一文中,已经对Apache A ... -
Apache Axis了解
2011-03-04 22:16 1501最近项目到了最最关键的时刻了,客户的试用期也快结束了,客户 ... -
Commons DbUtils源码阅读之实例及测试应用
2011-02-23 22:39 1933去年整了一Commons DbUtils的源码阅读,现如今 ... -
Apache Ant常用标签介绍
2011-02-20 22:24 4807在上一篇博文中简单介绍了一下Ant是如何编译和发布Java ... -
Apache Ant 实例介绍
2011-02-17 22:55 4466开开心心的过了个年,快快乐乐的过了个情人节!So,继续我技 ... -
Commons DbUtils 源码阅读八
2011-01-19 21:39 1843距离DbUtils组件源码七 ... -
Commons DbUtils 源码阅读七
2011-01-03 13:36 2077实际上,我们也知道官网上对ResultSet的解析示例: ... -
Commons DbUtils 源码阅读六
2010-12-24 23:27 1706DbUtils组件的核心部分已经解析完了,实际上呢,DbUt ... -
Commons DbUtils 源码阅读四
2010-12-03 19:51 2485在读BasicRowProcessor ... -
Commons DbUtils 源码阅读三
2010-11-29 22:26 3083前两天着实被javaeye关闭着急了一下,还好,总算开放了 ... -
Commons DbUtils 源码阅读二
2010-11-19 21:17 1906DbUtils组件的整个代码结构做了一个简单的疏导,现在来 ... -
Commons DbUtils 源码阅读一
2010-11-17 22:51 2964想起读源码了! 主要是出于这几个方面的考虑: ...
相关推荐
DbUtils源码的阅读可以从以下几个方面入手: 1. **QueryRunner**:查看QueryRunner类的源码,理解其如何处理SQL查询和更新操作,以及如何处理异常。 2. **ResultSetHandler**:研究不同的结果集处理器实现,了解...
赠送源代码:commons-dbutils-1.7-sources.jar; 赠送Maven依赖信息文件:commons-dbutils-1.7.pom; 包含翻译后的API文档:commons-dbutils-1.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:commons-dbutils:...
commons-dbutils包是Apache开源组织提供的用于操作数据库的工具包。简单来讲,这个工具包就是用来更加方便我们操作数据库的,最近工作中使用了一下,感觉确实方便很多,基本告别自己封装JDBC代码对数据库进行增删改...
使用 Commons dbutils 可以极大地简化 JDBC 编程,避免了许多手动处理连接、声明和结果集的工作,同时也提高了代码的可读性和可维护性。例如,使用 `QueryRunner` 执行查询和更新操作时,只需要提供 SQL 语句、参数...
`commons-dbutils-1.6-sources.jar`包含了源代码,这对于开发者来说是极其宝贵的资源,因为可以方便地查看和理解DBUtils内部的工作机制,进行调试或自定义扩展。 DBUtils的设计原则是简单、高效和健壮。它不是ORM...
EnhancedJDBC是一个基于Apache Commons DbUtils构建并扩展其功能的纯JDBC持久层工具,项目包含410个文件,主要由401个Java源文件组成,辅以少量批处理脚本、Markdown文档、版本控制忽略文件、许可协议文件、XML配置...
赠送源代码:commons-dbutils-1.7-sources.jar; 赠送Maven依赖信息文件:commons-dbutils-1.7.pom; 包含翻译后的API文档:commons-dbutils-1.7-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:commons-...
这是DBUtils的源码版本,开发者可以查看并学习源代码,理解其内部实现逻辑,进行调试或定制功能。源码中包含了详细的注释,有助于理解每个方法的作用和用法。 3. 关于DBUtils的知识点: - **数据库连接管理**:...
而"commons-dbutils-1.3-src.zip"则包含了源代码,对于开发者来说,查看源码有助于理解其工作原理,进行定制或扩展。 在实际使用中,开发者可以通过以下步骤集成DBUtils: 1. 添加DBUtils的jar文件到项目的类路径...
通过阅读和分析"commons-dbutils-1.7-src.zip"中的源代码,开发者可以深入理解DBUtils如何实现这些功能,如何优化JDBC操作,以及如何在自己的项目中更好地利用这个框架。同时,源代码也可以作为学习Java编程和数据库...
5. **异常处理**:DBUtils已经封装了常见的JDBC异常,使得开发者不必每次都进行try-catch,降低了代码的复杂性。 6. **关闭资源**:DBUtils在内部会自动处理连接、Statement和ResultSet的关闭,避免了资源泄漏的...
通过 Apache Commons DBUtils,我们可以方便地执行 SQL 语句并处理结果,避免了手动处理数据库连接和结果集带来的繁琐工作,提高了代码的可读性和可维护性。同时,由于 DBUtils 内部对异常进行了处理和包装,使得...
commons-dbutils-1.6的jar包、源码、文档说明.zip
通过 `commons-dbutils-master` 压缩包,你可以获取到 DbUtils 的源代码,深入理解其实现原理,并根据项目需求进行自定义扩展。总的来说,Apache Commons DbUtils 是一个值得信赖的工具,它让 JDBC 编程变得更加简洁...
总的来说,Apache Commons DBUtils是Java开发中一个不可或缺的工具,它极大地简化了数据库操作,提升了代码的可读性和可维护性,同时降低了出错的可能性。对于初学者和经验丰富的开发者来说,理解和掌握DBUtils都是...
这个"commons-dbutils-1.0-src.zip"文件包含了DBUtils 1.0版本的源代码,使得开发者能够深入理解其内部机制,进行定制化开发或者调试。DBUtils库主要为JDBC(Java Database Connectivity)提供了一层方便、高效的...
源码分析方面,你可以通过阅读DBUtils的源代码来了解其内部机制,比如: - 如何封装JDBC异常,创建自定义的异常类。 - `QueryRunner`如何处理SQL查询和更新,以及如何处理结果集。 - 批处理的实现原理,包括如何...
DbUtils与JDBC结合使用,可以避免大量重复的数据库连接关闭、异常处理等代码,使数据库操作更加简洁、安全。DbUtils的核心类有QueryRunner、ResultSetHandler等,它们简化了常见的CRUD操作,比如执行SQL查询、更新、...
在解压并使用“commons-dbutils-1.4(用于连接池)C3P0.rar”中的文件时,首先需要将C3P0的配置文件(如c3p0-config.xml)配置到项目中,并在代码中导入DBUtils和C3P0的相关依赖。然后,可以通过DBUtils的Query...
apache-commons下全部官方源码和官方API文档,其中有: commons-beanutils-1.8.0 commons-codec commons-collections commons-dbcp commons-dbutils commons-fileupload commons-io commons-lang commons-lang3 ...