问题的提出
在一个应用程序中,处理JDBC的操作是一个重复率较高的工作。当你在一个JDBC数据源上执行SQL查询时,你通常需要执行下面几个步骤:
1.生成SQL语句
2.获得连接
3.获得一个PreparedStatement对象
4.在PreparedStatement对象中设定需要送入到数据库的值
5.执行SQL语句
6.处理查询结果
除此之外,你还需要处理SQLException异常。如果上面列出的这些步骤分散在程序的各个部分的话,程序中需要多个try/catch块来处理异常。
如果我们仔细看看上面列出的步骤,就会发现在执行不同的SQL语句时,上面这些步骤中涉及到的程序代码变化不会很大:我们使用同样的方法获得数据库连接和PreperedStatement对象;使用setXXX方法来设定PreperedStatement对象中的值;处理SQL查询结果的过程也是基本不变的。在这篇文章中,我们通过定义三个JDBC模型,去除了上述六个步骤中的三个步骤,这样使得整个过程更加简单,而且具有更好的通用性。
查询模型
我们定义了一个名叫SQLProcessor的类,在该类中定义了一个executeQuery()方法来执行SQL语句,我们在实现这个方法的时候尽量保持代码的简洁性,并且传递尽可能少的参数给该方法。下面是该方法的定义:
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public Object[] executeQuery(String sql, Object[] pStmntValues,
ResultProcessor processor);</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
我们知道在执行SQL语句的JDBC过程中,变化的因素有三个:SQL语句,PreparedStatement对象和如何解释和处理查询结果。在上面的方法定义中,sql中保存的就是SQL语句;pStmntValues对象数组保存的是需要放入preparedStatement对象中的值;processor参数是一个能够处理查询结果的对象,于是我们把JDBC程序涉及到的对象分成了三个部分。下面让我们来看一下executeQuery()和与它相关的一些方法的实现:
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public class SQLProcessor {
public Object[] executeQuery(String sql, Object[] pStmntValues,
ResultProcessor processor) {
//获得连接
Connection conn = ConnectionManager.getConnection();
//将SQL语句的执行重定向到handlQuery()方法
Object[] results = handleQuery(sql, pStmntValues, processor, conn);
//关闭连接
closeConn(conn);
//返回结果
return results;
}
protected Object[] handleQuery(String sql, Object[] pStmntValues,
ResultProcessor processor, Connection conn)
{
//获得一个preparedStatement对象
PreparedStatement stmnt = null;
try {
//获得preparedStatement
stmnt = conn.prepareStatement(sql);
//向preparedStatement中送入值
if(pStmntValues != null) {
PreparedStatementFactory.buildStatement(stmnt, pStmntValues);
}
//执行SQL语句
ResultSet rs = stmnt.executeQuery();
//获得查询结果
Object[] results = processor.process(rs);
//关闭preparedStatement对象
closeStmnt(stmnt);
//返回结果
return results;
//处理异常
} catch(SQLException e) {
String message = &quot;无法执行查询语句 &quot; + sql;
//关闭所有资源
closeConn(conn);
closeStmnt(stmnt);
//抛出DatabaseQueryException
throw new DatabaseQueryException(message);
}
}
}
...
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
程序中有两个方法需要说明:PreparedStatementFactory.buildStatement()和processor.process()。buildStatement()方法把在pStmntValues对象数组中的所有对象送到prepareStatement对象中的相应位置。例如:
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">...
//取出对象数组中的每个对象的值,
//在preparedStatement对象中的相应位置设定对应的值
for(int i = 0; i &lt; values.length; i++) {
//如果对象的值为空, 设定SQL空值
if(value instanceof NullSQLType) {
stmnt.setNull(i + 1, ((NullSQLType) value).getFieldType());
} else {
stmnt.setObject(i + 1, value);
}
}</font></font></ccid_code></pre></td></tr></tbody></table>
<p><font color="#a52a2a" size="4">因为stmnt.setOject(int index, Object value)方法不能接受一个空对象作为参数。为了使程序能够处理空值,我们使用了自己设计的NullSQLType类。当一个NullSQLType对象被初始化的时候,将会保存数据库表中相应列的SQL类型。在上面的例子中我们可以看到,NULLSQLType对象的属性中保存了一个SQL NULL实际对应的SQL类型。我们用NULLSQLType对象的getFieldType()方法来向preparedStatement对象填入空值。 </font></p>
<p><font size="4"><font color="#a52a2a">下面让我们来看一看processor.process()方法。Processor类实现了ResultProcessor接口,该接口是用来处理SQL查询结果的,它只有一个方法process(),该方法返回了处理SQL查询结果后生成的对象数组。 <br><br><ccid_nobr></ccid_nobr></font></font>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public interface ResultProcessor {
public Object[] process(ResultSet rs) throws SQLException;
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
process()的典型实现方法是遍历查询后返回的ResultSet对象,将保存在ResultSet对象中的值转化为相应的对象放入对象数组。下面我们通过一个例子来说明如何使用这些类和接口。例如当我们需要从数据库的一张用户信息表中取出用户信息,表名称为User:
<ccid_nobr><table class="content" width="502" border="1"><tbody>
<tr>
<td><font color="#a52a2a" size="4">列名</font></td>
<td><font color="#a52a2a" size="4">数据类型</font></td>
</tr>
<tr>
<td><font color="#a52a2a" size="4">ID</font></td>
<td><font color="#a52a2a" size="4">NUMBER</font></td>
</tr>
<tr>
<td><font color="#a52a2a" size="4">UserName</font></td>
<td><font color="#a52a2a" size="4">VARCHAR2</font></td>
</tr>
<tr>
<td><font color="#a52a2a" size="4">Email</font></td>
<td><font color="#a52a2a" size="4">VARCHAR2</font></td>
</tr>
</tbody></table></ccid_nobr>
我们需要在程序中定义一个类User来映射上面的表:
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">public User(int id, String userName, String email)</font></font></ccid_code> |
如果我们使用常规方法来读取User表中的数据,我们需要一个方法来从数据库表中读取数据,然后将数据送入User对象中。而且一旦查询语句发生变化,我们需要修改大量的代码。让我们看一看采用本文描述的解决方案情况会如何。
首先构造一个SQL语句。
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">private static final String SQL_GET_USER = &quot;SELECT * FROM USERS WHERE ID = ?&quot;;</font></font></ccid_code> |
然后创建一个ResultProcessor接口的实例类,通过它我们可以从查询结果中获得一个User对象。
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">public class UserResultProcessor implements ResultProcessor {
// 列名称定义(省略)
...
public Object[] process(ResultSet rs) throws SQLException {
// 使用List对象来保存所有返回的User对象
List users = new ArrayList();
User user = null;
// 如果查询结果有效,处理查询结果
while(rs.next()) {
user = new User(rs.getInt(COLUMN_ID), rs.getString(COLUMN_USERNAME),
rs.getString(COLUMN_EMAIL));
users.add(user);
}
return users.toArray(new User[users.size()]);</font></font></ccid_code> |
最后,将执行SQL查询和返回User对象的指令放入getUser()方法中。
<ccid_nobr></ccid_nobr>
<ccid_code><font size="4"><font color="#a52a2a">public User getUser(int userId) {
// 生成一个SQLProcessor对象并执行查询
SQLProcessor processor = new SQLProcessor();
Object[] users = processor.executeQuery(SQL_GET_USER_BY_ID,
new Object[] {new Integer(userId)},
new UserResultProcessor());
// 返回查询到的第一个User对象
return (User) users[0];
}</font></font></ccid_code> |
这就是我们需要做的全部工作:只需要实现一个processor类和一个getUser()方法。与传统的JDBC程序相比,在本文描述的模型中,我们不需要处理数据库连接操作,生成prepareStatement对象和异常处理部分的代码。如果需要在同一张表中根据用户名查用户ID,我们只需要在代码中申明新的查询语句,然后重用UserResultProcessor类中的大部分代码。
更新模型
如果SQL语句中涉及到更新,情况又会怎样呢?我们可以用类似于设计查询模型的方法来设计更新模型,我们需要向SQLProcessor类中增加一些新的方法。这些方法同executeQuery()和handleQuery()方法有相似之处,只是我们需要改变一下处理ResultSet对象的代码,并且把更新的行数作为方法的返回值。
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public void executeUpdate(String sql, Object[] pStmntValues,
UpdateProcessor processor) {
// 获得数据库连接
Connection conn = ConnectionManager.getConnection();
// 执行SQL语句
handleUpdate(sql, pStmntValues, processor, conn);
// 关闭连接
closeConn(conn);
}
protected void handleUpdate(String sql, Object[] pStmntValues,
UpdateProcessor processor, Connection conn) {
PreparedStatement stmnt = null;
try {
stmnt = conn.prepareStatement(sql);
// 向prepareStatement对象中送入值
if(pStmntValues != null) {
PreparedStatementFactory.buildStatement(stmnt, pStmntValues);
}
// 执行更新语句
int rows = stmnt.executeUpdate();
// 统计有多少行数据被更新
processor.process(rows);
closeStmnt(stmnt);
// 异常处理
} catch(SQLException e) {
String message = &quot;无法执行查询语句 &quot; + sql;
closeConn(conn);
closeStmnt(stmnt);
throw new DatabaseUpdateException(message);
}
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
上面的两个方法和处理查询的方法不同之处在于他们如何处理返回值。由于更新语句只需要返回被更新了的行数,所以我们不需要处理SQL操作返回的结果。实际上有些情况下连被更新了的行数都不需要返回,我们这样做的原因是在某些情况下需要确认更新操作已经完成。
我们设计了UpdateProcessor接口来处理Update操作返回的更新行数。
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public interface UpdateProcessor {
public void process(int rows);
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
例如在程序中需要保证更新操作,更新表中的至少一条记录。在UpdateProcessor接口的实现类中就可以加入对修改行数的检测,当没有记录被更新时,processor()方法可以抛出自定义的异常;也可以将更新的行数记录到日志文件中;或者激发一个自定义的更新事件。总而言之,你可以在其中做任何事。
下面是一个使用更新模型的例子:
首先生成SQL语句
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">private static final String SQL_UPDATE_USER =
&quot;UPDATE USERS SET USERNAME = ?, EMAIL = ? WHERE ID = ?&quot;;</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
实现UpdateProcessor接口。在Processor()方法中,检查Update操作是否更新了数据。如果没有,抛出IllegalStateException异常。
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public class MandatoryUpdateProcessor implements UpdateProcessor {
public void process(int rows) {
if(rows &lt; 1) {
String message = &quot;更新操作没有更新数据库表中的数据。&quot;;
throw new IllegalStateException(message);
}
}
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr>
最后在updateUser()方法中执行Update操作并处理结果。
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public static void updateUser(User user) {
SQLProcessor sqlProcessor = new SQLProcessor();
sqlProcessor.executeUpdate(SQL_UPDATE_USER,
new Object[] {user.getUserName(),
user.getEmail(),
new Integer(user.getId())},
new MandatoryUpdateProcessor());
}</font></font></ccid_code></pre></td></tr></tbody></table>
<p><strong><font color="#a52a2a" size="4"></font></strong></p>
<p><strong><font color="#a52a2a" size="4">事务模型</font></strong></p>
<p><font color="#a52a2a" size="4">在数据库中,事务和独立的SQL语句的区别在于事务在生命期内使用一个数据库连接,并且AutoCommit属性必须被设为False。因此我们需要指定事务何时开始,何时结束,并且在事务结束时提交事务。我们可以重用SQLProcessor中的大部分代码来处理事务。也许在最开始读者会问为什么要把执行更新和处理更新的工作放在 executeUpdate()和handleUpdate()两个函数中完成--实际上它们是可以被合并到同一个函数中的。这样做的原因是把处理数据库连接的代码和处理SQL操作的代码分离开来。对于需要在多个SQL操作间共用数据库连接的事务模型来说,这种方案便于编码。 <br><br>在事务中,我们需要保存事务的状态,特别是数据库连接的状态。前面的SQLProcessor中没有保存状态的属性,为了保证对SQLProcessor类的重用,我们设计了一个包装类,该类包装了SQLProcessor类,并且可以维护事务在生命周期内的状态。 <br><br></font></p>
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public class SQLTransaction {
private SQLProcessor sqlProcessor;
private Connection conn;
// 缺省构造方法,该方法初始化数据库连接,并将AutoCommit设定为False
...
public void executeUpdate(String sql, Object[] pStmntValues,
UpdateProcessor processor) {
// 获得结果。如果更新操作失败,回滚到事务起点并抛出异常
try {
sqlProcessor.handleUpdate(sql, pStmntValues, processor, conn);
} catch(DatabaseUpdateException e) {
rollbackTransaction();
throw e;
}
}
public void commitTransaction() {
// 事务结束,提交更新并回收资源
try {
conn.commit();
sqlProcessor.closeConn(conn);
// 如果发生异常,回滚到事务起点并回收资源
} catch(Exception e) {
rollbackTransaction();
throw new DatabaseUpdateException(&quot;无法提交当前事务&quot;);
}
}
private void rollbackTransaction() {
// 回滚到事务起点并回收资源
try {
conn.rollback();
conn.setAutoCommit(true);
sqlProcessor.closeConn(conn);
// 如果在回滚过程中发生异常,忽略该异常
} catch(SQLException e) {
sqlProcessor.closeConn(conn);
}
}
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr><p><br><br><font color="#a52a2a" size="4">SQLTransaction中出现了一些新方法,这些方法主要是用来处理数据库连接和进行事务管理的。当一个事务开始时,SQLTransaction对象获得一个新的数据库连接,并将连接的AutoCommit设定为False,随后的所有SQL语句都是用同一个连接。 <br><br>只有当commitTransaction()被调用时,事务才会被提交。如果执行SQL语句的过程中发生了异常,程序会自动发出一个回滚申请,以恢复程序对数据库所作的改变。对于开发人员来说,不需要担心在出现异常后处理回滚或关闭连接的工作。下面是一个使用事务模型的例子。 <br><br></font></p>
<ccid_nobr><p>
</p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="550" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code><font size="4"><font color="#a52a2a">public static void updateUsers(User[] users) {
// 开始事务
SQLTransaction trans = sqlProcessor.startTransaction();
// 更新数据
User user = null;
for(int i = 0; i &lt; users.length; i++) {
user = users[i];
trans.executeUpdate(SQL_UPDATE_USER,
new Object[] {user.getUserName(),
user.getFirstName(),
user.getLastName(),
user.getEmail(),
new Integer(user.getId())},
new MandatoryUpdateProcessor());
}
// 提交事务
trans.commitTransaction();
}</font></font></ccid_code></pre></td></tr></tbody></table></ccid_nobr><p><br><br><font color="#a52a2a" size="4">在例子中我们只使用了更新语句(在大多数情况下事务都是由更新操作构成的),查询语句的实现方法和更新语句类似。 </font></p>
<p><strong><font color="#a52a2a" size="4">问题</font></strong></p>
<p><font color="#a52a2a" size="4">在实际使用上面提到的这些模型时,我遇到了一些问题,下面是这些问题的小结,希望对大家有所帮助。 <br><br><b>自定义数据库连接</b> <br><br>在事务处理的时候,有可能发生在多个事务并存的情况下,它们使用的数据库连接不同的情况。ConnectionManager需要知道它应该从数据库连接池中取出哪一个连接。你可以简单修改一下模型来满足上面的要求。例如在executeQuery()和executeUpdate()方法中,你可以把数据库连接作为参数,然后将它们传送给ConnectionManager对象。请记住所有的连接管理都应该放在executeXXX()方法中。另外一种解决方案,也是一种更面向对象化的解决方案,是将一个连接工厂作为参数传递给SQLProcessor的构造函数。对于不同的连接工厂类型,我们需要不同的SQLProcessor对象。 <br><br><b>ResultProcessor类的返回值:对象数组还是List?</b> <br><br>为什么ResultProcessor接口中的process()方法返回的是对象数组呢?怎么不使用List类呢?这是由于在很多实际的应用中,SQL查询在大多数情况下值返回一行数据,在这种情况下,使用List对象会有些多余了。但是如果你确信SQL查询将返回多行结果,你可以使用List对象。 <br><br><b>数据库操作异常</b> <br><br>我们可以用多个自定义的数据库操作异常类来替代运行时发生的SQLException异常。最好在这些自定义的异常类时继承RuntimeException类,这样可以将这些异常进行集中处理。也许你会认为因该将异常处理放在发生异常的地方。但是我们设计这个的模型的目的之一是在JDBC应用程序开发中去掉或弱化异常处理的部分,只有使用RuntimeException我们才可能达到这个目的。 <br><br><br></font></p>
<p><font color="#a52a2a" size="4"></font></p>
<p><font color="#a52a2a" size="4"></font></p>
<p><font color="#a52a2a" size="4"></font></p>
<p><font color="#a52a2a" size="4"></font></p>
<p><font color="#a52a2a" size="4"></font></p></ccid_nobr>
分享到:
相关推荐
项目名称:轻量级Java持久层框架MiniDAO...MiniDAO致力于简化数据访问层代码,通过FreeMarker模板提供灵活的SQL管理方式,同时继承了Spring JDBC的易用性和高效性,为Java开发者提供了一个简洁、高效的持久层解决方案。
JSP+SQL房屋租赁管理信息系统JDBC是一个针对计算机专业的学生或开发者的完整项目资料包,它集成了Java服务器页面(JSP)技术、结构化查询语言(SQL)以及Java数据库连接(JDBC)接口,旨在为用户提供一个全面的解决方案来...
SQL Mapper与Spring JDBC Framework相似,但是它简化了某些功能,并对其进行了一些更改。 它可以在JDK 7或更高版本上运行。 zip归档文件包含库jar,源代码和javadocs,以及一个演示如何使用映射器的演示。 PS:这个...
简化数据库操作:MyBatis 简化了 JDBC 代码的编写,减少了手动设置参数和获取结果集的工作量。 支持事务管理:MyBatis 可以与 Spring 框架集成,利用 Spring 的事务管理功能,确保数据的完整性和一致性。 缓存机制:...
MyBatis或Hibernate可以简化数据库操作,提供了方便的ORM(对象关系映射)功能,使得数据的持久化变得简单和高效。 通过以上技术选择和框架搭建,该项目可以实现一个高性能、可扩展性强的Web应用程序。开发人员可以...
房屋租赁管理信息系统是一个基于Java JSP和JDBC技术的在线租赁服务平台,旨在简化房屋租赁流程并为房东和租客提供便利。该系统支持房源发布、搜索、预订、合同签订以及租金支付等核心功能,通过高效的数据库操作实现...
一个基于AspectJ拦截器的JDBC包装器。 基于注释的解决方案。 还为实体提供了一个简单的ORM。 有关信息,请访问主页或从源代码和发行版中阅读readme.md文件。
MyBatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决了JDBC将结果集封装为Java对象的麻烦。对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。 此外,MyBatis还支持自定义SQL...
jOOQ 是一个内部 DSL 和源代码生成器,将 SQL 语言建模为类型安全的 Java API,以帮助您编写更好的 SQL。 其主要特点包括: 源代码生成器 用于类型安全查询构造和动态 SQL的 DSL API 次要特征包括: DAO 数据导出...
SBORM只是针对spring jdbc的一些不方便的地方,做了一些封装,更加简化日常的开发工作,基于spring jdbc的RowMapper自动实现对象映射,也勉强算的上叫ORM,只是大部分功能已经由spring jdbc实现了。 平时不太...
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot...
此文件为JDBC的工具类,JDBC操作数据库时,每执行一次操作都要重新执行JDBC的获取连接对象、获取处理命令的对象、执行sql操作、处理结果、关闭资源的几个步骤的话,大大加重的程序员的代码压力,由于这些步骤基本...
为了简化开发并实现程序解耦,选用了Spring Boot框架去搭建后台,在此基础上使用Mybatis连接数据库,避免了繁琐的JDBC代码,利用Freemarker框架减少了业务逻辑代码在表现层的耦合并实现数据展示,从0到1设计并开发了...
它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。 二、为什么需要Dbutils ? 在使用Dbutils 之前,我们Dao层使用的技术是JDBC,那么分析一下JDBC的弊端: ①数据库链接对象、sql语句操作对象,封装结果集...
MyBatis是一个优秀的基于Java的持久层框架,它内部封装了JDBC,使得开发者只需要关注SQL语句本身,而无需处理加载驱动、创建连接、创建Statement等繁琐的过程。MyBatis的主要特点和功能如下: 简单易用:通过XML...
最新发布版,集成了所有工具集。Jodd是一个普通开源Java包。...3. 简化JDBC的接连与代码, 4. 剖析SQL查询, 5. 处理时间与日期, 6. 操作与格式化String, 7. 搜索本地硬盘上的文件, 8. 帮助处理Servlet请求等。
3. MyBatis内部封装了JDBC,简化了加载驱动、创建连接、创建statement等烦琐的过程。 MyBatis具有以下特点。 (1)MyBatis是免费开源的,它是最简单的持久层框架,小巧且简单易学。 (2)MyBatis与JDBC相比,...
3. 简化JDBC的接连与代码, 4. 剖析SQL查询, 5. 处理时间与日期, 6. 操作与格式化String, 7. 搜索本地硬盘上的文件, 8. 帮助处理Servlet请求等。 除此之外还包含一个很小,但实用的基于JSP的MVC框架。
3. 简化JDBC的接连与代码, 4. 剖析SQL查询, 5. 处理时间与日期, 6. 操作与格式化String, 7. 搜索本地硬盘上的文件, 8. 帮助处理Servlet请求等。 除此之外还包含一个很小,但实用的基于JSP的MVC框架。
它封装了注册和载入JDBC驱动程序、建立数据库连接、运行Structured Query Language(SQL)语句及处理查询结果集、查询结果集的分页显示操作,简化了Java DataBase Connectivity(JDBC)代码的编写,通过编写SQL语句,...