在JavaEE应用中,使用ORM操作数据库虽然简单快捷(参考“高效使用JavaEE ORM”),但是毕竟是对JDBC的封装,很多时候,ORM还是不能满足我们的需求,主要是两个问题:
1. 速度不如JDBC,毕竟是封装JDBC,有额外的开销;
2. ORM提供的xQL很多时候无法满足需求,还需要数据库相关的SQL,这时,必须使用JDBC。
使用JDBC虽然麻烦点,但是,按照软件设计的思想,一步一步封装必要的代码,还是可以做到性能与开发效率并存。
首先,要坚决避免的就是不断重复编写try... catch... finally...。对于查询、更新、插入和删除操作,每一种操作只允许编写一次try... catch... finally...。如何实现?有两个方法。
第一个办法是找一个现成的封装了这些JDBC操作的框架,最好的方案当然就是Spring的JDBC框架了,顺便可以参考JdbcTemplate的源码,以便提升自己的JavaEE功力。
如果不使用Spring,那就采用第二个办法,自己造轮子,封装一个JDBC框架。
很多人反对自己造轮子,原因不外乎费事。不过很多时候,造轮子并不麻烦,而且可以满足特定的需求。今天要造的轮子就是一个封装JDBC的框架:Express-Persist。
Express-Persist是ExpressMe的持久化子项目,目标是封装JDBC并提供简单的数据库操作接口。
为什么不使用Spring JDBC呢?主要原因只有一个:Spring的JDBC目前还是1.4兼容的,不支持1.5的泛型。Express-Persist要提供的接口除了基本的数据库操作外,还要实现:
1. 简单的ORM映射,注意是简单的,没有Hibernate那样完整而强悍,本质上就是把ResultSet的每一条记录变成一个JavaBean,可以参考Spring JDBC的RowMapper,实现非常容易;
2. 充分利用Java 5泛型支持,都是类型安全的参数和返回值,不用做强制转化;
3. 利用Java 5的注解(Annotation)把SQL标记在接口方法上,比如:
1.
@Query
(
"select * from User where u.id=:id"
)
2.
public
User get(String id);
4. 最后,最重要的,只编写接口,没有实现类!
没有实现类,那JDBC代码写在哪?当然由Express-Persist框架自动生成了。如何自动生成?运行一个命令自动生成Java类?在“高效使用JavaEE ORM”一文中我们已经对JDO的这种静态增强方式表示了强烈的鄙视和唾弃,因此绝不可重蹈覆辙。Express-Persist会在启动时根据接口动态创建出类,不过我们不采用Hibernate使用的CGLIB库,而是直接通过JDK的动态代理功能实现动态类。
如何绑定SQL参数
DAO接口的方法参数要自动绑定到SQL参数中,由于方法参数的顺序与SQL参数的顺序可能不一致,因此,只能使用命名参数来绑定,即:SQL参数定义为:xxx,对应的方法参数用@Param("xxx")标记。
当SQL参数很多的时候(尤其是INSERT语句),方法参数也非常多,调用起来非常不方便,比如:
1.
@Update
(
"insert into User values(:id, :email, :password, :name)"
)
2.
public
int
create(
@Param
(
"id"
) String id,
@Param
(
"email"
) String email,
@Param
(
"password"
) String password,
@Param
(
"name"
) String name);
而且都是String类型,调用起来容易出错。
因此,Express-Persist允许使用JavaBean绑定,把上述代码变为:
1.
@Update
(
"insert into User values(:u.id, :u.email, :u.password, :u.name)"
)
2.
public
int
create(
@Param
(
"u"
) User u);
这样,调用起来只需要传入一个User对象即可,简单且不易出错。
如何分页查询
绝大多数数据库支持分页查询,但语法各不相同。如果让开发者自己写分页SQL语句,难度较大,而且不易复用。因此,Express-Persist仿照Hibernate的做法,为每一种数据库定义一个Dialect,处理分页,这样,无需考虑数据库的特定分页语法,只需额外添加@FirstResult和@MaxResults这两个注解,以便传入分页参数:
1.
@Query
(
"select * from User u order by id"
)
2.
List<User> queryAll(
@FirstResult
int
first,
@MaxResults
int
max);
Express-Persist已经内置HSQLDB、MySQL和Oracle的Dialect支持,也可以编写其他数据库的Dialect,只需实现Dialect接口即可。
如何把ResultSet映射为Java对象
要把ResultSet映射为Java对象,我们采用Spring JDBC使用的RowMapper方案,改进之处在于采用了泛型,并且,提供一个BeanRowMapper,实现ResultSet到JavaBean的转换,因为大部分的转换都是到JavaBean。
利用Java 5的泛型支持,可以非常容易地生成一个BeanRowMapper,而无需编写任何方法:
1.
public
class
UserRowMapper
extends
BeanRowMapper<User> {}
@MappedBy用于告诉Express-Persist如何映射ResultSet:
1.
@MappedBy
(UserRowMapper.
class
)
2.
@Query
(
"select * from User u order by id"
)
3.
List<User> queryAll(
@FirstResult
int
first,
@MaxResults
int
max);
如果返回结果仅有一个,例如根据主键查询,则必须加上一个@Unique注解,这样,Express-Persist将自动检查返回的记录数,如果不为1,则抛出异常:
1.
@Unique
2.
@MappedBy
(UserRowMapper.
class
)
3.
@Query
(
"select * from User u where id=:id"
)
4.
User queryById(
@Param
(
"id"
) String id);
如果返回结果允许多个,则返回值应该定义为泛型List,如List<User>。
Batch支持
批量插入或修改时,使用和不使用JDBC Batch,其性能将有数量级的差距。Express-Persist提供Batch支持,通过继承BatchSupport接口:
1.
public
class
UserDao
extends
BatchSupport {
2.
@Update
(
"update User set name=:name where id=:id"
)
3.
void
updateUserName(
@Param
(
"id"
) String id,
@Param
(
"name"
) String name);
4.
}
Batch操作的代码稍微复杂一点,必须用try... finally执行,以便正确释放资源:
01.
try
{
02.
dao.prepareBatch();
03.
04.
dao.updateUserName(
"id-1"
,
"change A's name"
);
05.
dao.updateUserName(
"id-2"
,
"change B's name"
);
06.
dao.updateUserName(
"id-3"
,
"change C's name"
);
07.
08.
int
[] results = dao.executeBatch();
09.
}
10.
finally
{
11.
dao.closeBatch();
12.
}
事务控制
Express-Persist仅支持JDBC事务,因此无法远程传播事务。事务代码通常写在Web应用程序的Filter或Interceptor中,只需编写一次:
01.
TransactionManager txManager = ...;
02.
Transaction tx = txManager.beginTransaction();
03.
try
{
04.
05.
tx.commit();
06.
}
07.
catch
(Exception e) {
08.
tx.rollback();
09.
}
如果你想体验一下Express-Persist带来的全新Java持久化方案,可以从http://express-me.googlecode.com/files/express-persist.jar下载Jar包(含源代码)。完整的文档请参考http://code.google.com/p/express-me/wiki/ExpressPersist。
相关推荐
JDBC数据库访问工具类 强大 精巧 高效
高性能jdbc分页处理,使用PreparedStatement方式
然后可以使用此对象高效地多次执行该语句。 java.sql.CallableStatement 用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入/输出参数。 java.sql.ResultSet 指的是查询返回的数据库结果集。 ...
Tomcat 7 的 新数据源配置方式,context.xml 配置了一个性能优秀的数据源,数据库的账号,密码和url需要根据自己的项目实际情况来修改
jdbc连接数据库方法大全,提供了各种jdbc连接数据库的方法,让你明了哪种方法更高效
自己封装好的,基于commons的DBBase,DBCP的数据库工具。支持线程池,支持直接...属于超轻量级JDBC高效开发工具。 附DOC文档和源代码。如有改进意见,请邮件我。supperman_009@163.com 邮件请注明:CSDN 资源下载改进
小而高效的 JDBC 包装器。 小:没有外部依赖。 Jar 大小小于 50kb。 简单:无需特殊配置。 在 1 行初始化代码后开始使用它。 可靠:所有 SQL 语句都在应用程序启动时进行解析和验证。 灵活:在需要时直接切换和使用...
使用JDBC技术连接oracle数据库,并且实现简单的数据分页,能够更加高效的提取数据
基于JDBC的数据库连接池高效管理策略,很老的资料了
JDBC加载数据库驱动的三种方法 简单高效
用代码进行数据库链接
系统采用MySQL数据库进行数据存储,使用JDBC技术实现数据的访问。 MySQL数据库采用关系型数据存储,具有良好的扩展性和稳定性,能够满足系统对数据存储的各种需求。JDBC技术是一种标准的Java API,能够实现多种数据库的...
Druid是一个JDBC组件,它包括三部分: DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。 DruidDataSource 高效可管理的数据库连接池。 SQLParser Druid可以做什么? 1) 可以监控数据库...
本文介绍了基于JDBC的数据库连接池的工作原理,阐述了连接池技术的事务处理、多数据库服务器等各项关键技术,提出了一个高效的连接池管理策略,最后详细说明了数据库连接池应用的具体实现过程。 我觉得很有启发,...
SQLite Security JDBC 驱动实现了Android平台下可以使用JDBC访问SQLite数据库的能力, 提供的加密引擎是采用透明加密方式,应用程序访问SQLite不需要做任何修改,就能高效地对SQLite数据库进行数据加密。
Java版本 人大金仓ESV8最新版驱动程序,学习使用国产化数据库操作。 金仓通用数据库,可视化操作,毫秒级数据处理,高效准确完成数据处理全过程。面向事务处理类、兼顾分析类应用领域场景,兼容Oracle、国产数据库等多...
Druid是一个JDBC组件,它包括三部分: DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。 DruidDataSource 高效可管理的数据库连接池。 SQLParser Druid可以做什么? 1) 可以监控数据库访问...
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问解决部分mybatis或者hibernate不支持的数据库,例informix。通过pool连接池提高性能,并将...
JDBC:作为Java程序访问数据库的标准接口,使用JDBC可以方便地连接和操作MySQL数据库。 MySQL数据库:作为一种开源的关系型数据库管理系统,MySQL提供了稳定、高效的数据存储和管理能力。 Java Control:实现用户...
学员将通过实战示例掌握如何使用JDBC API进行数据库连接、执行SQL命令、处理结果集,以及进行事务管理。这一技能对于Java后端开发者来说是必不可少的,能够极大地提升其在企业级应用开发中的竞争力。 通过本课程的...