- 浏览: 58284 次
- 性别:
- 来自: 厦门
最新评论
-
gongmingwind:
但是JTA是怎样控制多个DAO事务的没有写的清楚,但已经非常不 ...
JDBC DAO设计 -
gongmingwind:
整理的非常好,受益匪浅!谢谢...
JDBC DAO设计 -
萝卜控:
linksys的产品简单好用设置中自带说明(虽然不全)入手后5 ...
linksys 密匙设置 -
zhiblin:
http://www.myprice.com.cn/manu/ ...
linksys 密匙设置 -
zhiblin:
维度表
维度表可以看作是用户来分析数据的 ...
Fact Table and Dimension Table
Connection的含义
Connection表示了一个和数据库的链接,底层需要有操作系统的Socket支持,所以Connection是一种资源,既然是一种资源,就需要按照建立,打开,使用,关闭的顺序合理的使用。
Connection是Java数据库操作的基础,是进行一系列操作的基础,所有的派生的操作,例如Statement,PreparedStatement,ResultSet等都由Connection直接或者间接的衍生。
如何获得Connection呢?
方法一,使用DriverManager类来获取,前提条件是数据库驱动程序需要在classpath下(即使用数据库链接的程序按照Java的方式可以访问到)。
Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@192.168.0.1:1521:ORCL", user, pwd );
方法二,使用数据库连接池来获取
什么是数据库连接池呢,数据库连接池是标准JavaEE容器的一种服务,例如Webspher,Weblogic,Tomcat等,容器预先建立一些数据
库链接,以便应用程序使用的时候从中借取,注意有借有还,当应用程序使用完了之后会将数据库链接还回连接池。(数据源配置请参考其他文档)
使用连接池的好处是,可以预先建立链接,减小在数据库获取上的相对时间。
使用连接池获取数据库链接的方式为:
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/DataSource");
Connection conn = ds.getConnection();
由于在配置数据库连接池的时候已经定义了URL,用户名,密码等信息,所以在程序中使用的时候不需要传入这些信息。
ConnectionManager定义
Connection用来专门管理数据库链接,通常情况下ConnectionManager只有一个方法,调用这个方法将返回一个Connection
的实例。通过ConnectionManager可以封装Connection的获取方式(例如开发的时候使用DriverManager,运用的时候使
用DataSource的方式,但是不需要修改ConnectionManager之外的其他代码)和追加Connection获取之前之后的操作(例如
针对Connection的属性的设置)。
下面的代码是一个ConnectionManager的代码示例:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionManager {
public static Connection getConnection() throws DaoException {
Connection conn = null;
try {
conn = DriverManager.getConnection("", "", "");
} catch (SQLException e) {
throw new DaoException("can not get database connection", e);
}
return conn;
}
}
如果需要从开发模式变为运用模式,只需要将上述代码修改为:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionManager {
public static Connection getConnection() throws DaoException {
Connection conn = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/dsname");
conn = ds.getConnection();
} catch(NamingException e) {
throw new DaoException("can not find datasource", e);
}
catch (SQLException e) {
throw new DaoException("can not get database connection", e);
}
return conn;
}
}
如果需要预先设定Connection的一些属性,也可以在上述代码中设定,例如:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionManager {
public static Connection getConnection() throws DaoException {
Connection conn = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/dsname");
conn = ds.getConnection();
conn.setAutoCommit(false);
} catch(NamingException e) {
throw new DaoException("can not find datasource", e);
}catch (SQLException e) {
throw new DaoException("can not get database connection", e);
}
return conn;
}
}
CommonDao定义
属性和构造方法
通常情况下,CommonDao要有一个Connection的引用。所有一个CommonDao的实例的所有方法的调用都需要依赖于这个
Connection。需要一个Connection的另外一个原因是如果各个方法需要保证在一个事务环境中(上下文中),必须保证所有的操作都在一个
Connection上。
构造方法通常需要将类型为Connection的属性实例化,例如:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
public class CommonDao {
private Connection conn;
public CommonDao() throws DaoException {
this.conn = ConnectionManager.getConnection();
}
}
事务方法
begin()
开始一个事务,调用CommonDao的begin方法之后,所以的后续操作将会在一个事务环境内,要么全部提交,要么全部回滚。
commit()
提交一个事务,必须在begin调用之后调用。且和rollback方法互斥。
rollback()
回滚一个事务,必须在begin方法调用之后调用。且和commit方法互斥。
事务的实现有两种方法,一种是使用基于单一Connection的事务,另外一种方法是使用容器的JTA(Java
Transaction
API)。需要注意的是第一种方法可以在任何环境下使用,但是只能是针对单一的数据库链接。第二种方法智能在支持JTA的Java
EE容器中使用(例如Websphere,Weblogic等,Tomcat默认不支持),但是支持多个Connection实例。
第一种方法代码为:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
import java.sql.SQLException;
public class CommonDao {
private Connection conn;
public CommonDao() throws DaoException {
this.conn = ConnectionManager.getConnection();
}
public void begin() throws DaoException{
if(conn != null) {
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
throw new DaoException("can not begin transaction", e);
}
} else {
throw new DaoException("connection not opened!");
}
}
public void commit() throws DaoException {
try {
if (conn != null && !conn.getAutoCommit()) {
conn.commit();
conn.setAutoCommit(true);
} else {
if (conn == null) {
throw new DaoException("connection not opened!");
} else {
throw new DaoException("first begin then commit please!");
}
}
} catch (SQLException e) {
throw new DaoException("can not commit transaction!", e);
}
}
public void rollback() throws DaoException {
try {
if (conn != null && !conn.getAutoCommit()) {
conn.rollback();
conn.setAutoCommit(true);
} else {
if (conn == null) {
throw new DaoException("connection not opened!");
} else {
throw new DaoException("first begin then rollback please!");
}
}
} catch (SQLException e) {
throw new DaoException("can not rollback transaction!", e);
}
}
}
第二种我们在使用DAO的实例中介绍如何使用(@TODO)
新建两个DAO,做不同的操作,使用JTA保证事务完整。
查询方法
查询方法也许是CommonDao最常用的方法,查询方法需要将数据库的结果返回给画面。返回值我们一般不使用ResultSet,因为
ResultSet依赖于Connection,如果Connection关闭,ResultSet将不再有效,所以我们通常将ResultSet转变为
一个List之后返回。
在说明查询方法之前,我们先说说如何将数据库中的内容放在List中,我们使用一个List表示一个查询结果集合,使用一个Map表示集合中的一行,Map的key表示数据库表的字段名字,Value表示数据库字段的内容。代码为:
private List convert(ResultSet rs) throws DaoException {
// record list
List retList = new ArrayList();
try {
ResultSetMetaData meta = rs.getMetaData();
// column count
int colCount = meta.getColumnCount();
// each record
while (rs.next()) {
Map recordMap = new HashMap();
// each column
for (int i = 1; i <= colCount; i++) {
// column name
String name = meta.getColumnName(i);
// column value
Object value = rs.getObject(i);
// add column to record
recordMap.put(name, value);
}
// ad record to list
retList.add(recordMap);
}
} catch (SQLException ex) {
throw new DaoException("can not convert result set to list of map", ex);
}
return retList;
}
为了避免Sql注入的安全问题,我们通常使用PreparedStatement,在使用PreparedStatement的时候涉及到如何将传入参数设置到PreparedStatement上面,参看以下的共通方法:
private void apply(PreparedStatement pstmt, List params) throws DaoException {
try {
// if params exist
if (params != null && params.size() > 0) {
// parameters iterator
Iterator it = params.iterator();
// parameter index
int index = 1;
while(it.hasNext()) {
Object obj = it.next();
// if null set ""
if (obj == null) {
pstmt.setObject(index, "");
} else {
// else set object
pstmt.setObject(index, obj);
}
//next index
index++;
}
}
} catch (SQLException ex) {
throw new DaoException("can not apply parameter", ex);
}
}
接着我们继续说我们的查询方法,有了上述两个方法,我们的查询方法就非常简单了:
public List query(String sql, List params) throws DaoException {
List result = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(sql);
this.apply(pstmt, params);
rs = pstmt.executeQuery();
result = this.convert(rs);
} catch (SQLException ex) {
throw new DaoException("can not execute query", ex);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// nothing
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
// nothing
}
}
}
return result;
}
特殊的查询方法(返回单值)
有时候为了方便使用,我们需要返回单值的产寻方法,例如 select max(id) from table_a, select count(id) from table_b等。以下的代码使用了上述通用的查询方法,代码为:
public Object queryOne(String sql, List params) throws DaoException {
List list = this.query(sql, params);
if(list == null || list.size() == 0) {
throw new DaoException("data not exist");
} else {
Map record = (Map)list.get(0);
if(record == null || record.size() == 0 ) {
throw new DaoException("data not exist");
} else {
return record.values().toArray()[0];
}
}
}
更新,删除,插入方法
由于在JDBC中这三个方法都是用了一个execute完成,所以这里我们也使用一个方法来完成这些功能。代码为:
public int execute(String sql, List params) throws DaoException {
int ret = 0;
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(sql);
this.apply(pstmt, params);
ret = pstmt.executeUpdate();
}catch(SQLException ex) {
throw new DaoException("", ex);
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
// nothing.
}
}
}
return ret;
}
批处理方法(查询)
有些时候为了便于操作,需要一次查询多条SQL语句,我们称之为批处理,实现参看以下方法,其中为了和query方法做区分,将参数和返回值都改为了数组形式。
public List[] queryBatch(String[] sqlArray, List[] paramArray) throws DaoException {
List rets = new ArrayList();
if(sqlArray.length != paramArray.length) {
throw new DaoException("sql size not equal parameter size");
} else {
for(int i = 0; i < sqlArray.length; i++) {
String sql = sqlArray[i];
List param = paramArray[i];
List ret = this.query(sql, param);
rets.add(ret);
}
return (List[])rets.toArray();
}
}
批处理方法(更新)
有些时候需要一次更新多条Sql语句,为了便于操作,添加了批处理更新操作,参看以下代码,为了和更新方法区分,将参数和返回值都改为了数组形式。
public int[] executeBatch(String[] sqlArray, List[] paramArray) throws DaoException {
List rets = new ArrayList();
if(sqlArray.length != paramArray.length) {
throw new DaoException("sql size not equal parameter size");
} else {
for(int i = 0; i < sqlArray.length; i++) {
int ret = this.execute(sqlArray[i], paramArray[i]);
rets.add(new Integer(ret));
}
int[] retArray = new int[rets.size()];
for(int i = 0; i < retArray.length; i++) {
retArray[i] = ((Integer)rets.get(i)).intValue();
}
return retArray;
}
}
资源释放
由于CommonDao有一个Connection的属性,且Connection属于稀缺资源,所以在CommonDao不需要在使用的时候需要显示的关闭Connection。代码如下:
public void close() throws DaoException{
try {
if (conn != null && conn.getAutoCommit()) {
conn.close();
} else {
if(conn == null) {
throw new DaoException("can not close null connection, first new then close");
} else {
throw new DaoException("transaction is running, rollbakc or commit befor close please.");
}
}
} catch (SQLException ex) {
throw new DaoException("Can not close common dao");
}
}
JDBC工具类(JDBCUtil Class)
在上述的代码中我们看到有很多的无用的处理,例如:
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
// nothing.
}
}
为什么要有这些处理呢?说先这些处理发生的位置都是在正常处理完成之后,这些处理(例如pstmt.close())即使失败也没有影响,这个时候我们需
要做上述的无用处理,这正是JDBC API的一个小小的瑕疵。我们通常使用一个特殊的静态工具来来做补充,例如:
package com.jpleasure.jdbc.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCUtil {
public void safelyClose(Connection conn) {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
//
}
}
}
public void safelyClose(PreparedStatement pstmt) {
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
//
}
}
}
public void safelyClose(ResultSet rs) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
//
}
}
}
}
异常处理
也许细心的你已经发现了一个问题,为什么所有抛出异常的地方我们都是将SQLException包装在了DaoException之内抛出呢,为什么不直
接抛出SQLException呢?有两个原因,第一,可以细化,分类Exception抛出合适的异常,添加合适的消息,第二,隔离和Dao和业务逻辑
的耦合,可以方便的修改Dao层而不会影响到业务逻辑层。另外需要注意,DaoExcetion中可以包含SQLException,这个时候可以为客户
提供更详细的错误信息,例如ORA-12524等内容,但是很少见到。
package com.jpleasure.jdbc.dao;
public class DaoException extends Exception {
public DaoException() {
super();
}
public DaoException(String message, Throwable cause) {
super(message, cause);
}
public DaoException(String message) {
super(message);
}
public DaoException(Throwable cause) {
super(cause);
}
}
原文地址:http://www.blogjava.net/super2/archive/2008/11/01/237987.html
评论
发表评论
-
dba_source \dba_views oracle
2012-02-01 14:58 986oracle要点记录 Select Distinct ... -
oracle 表名最长30个字符
2012-01-31 15:40 1352如题 -
遭遇EXC_BAD_ACCESS
2011-12-06 15:46 941如何在XCode4中设置NSZombieEnabled ... -
Oracle 循环语句
2009-12-03 17:03 1298loop循环: create or replace proc ... -
linksys 密匙设置
2009-09-15 16:21 1138linksys的产品真的很难搞,郁闷 http://www. ... -
两台路由器上网设置
2009-09-14 10:14 1307http://www.ejdz.cn/diannaojishu ... -
百度过来的笛卡尔积
2009-08-04 17:12 1002给定一组域D1,D2,…,Dn,这些域中可以有相同的。D1,D ... -
super man blog
2009-08-04 16:57 968about oracle informatica sql s ... -
Fact Table and Dimension Table
2009-08-04 16:30 1948Fact Table: A fact ... -
我的数据仓库之路
2009-07-28 14:10 983这段时间一直在做BI 其实在看到下面这篇文章之前,我还不能很 ... -
string 转换成 date
2009-03-30 15:19 1064SimpleDateFormat myFmt=new Simp ... -
获取系统时间
2009-03-30 15:06 875public String getSysTime(){ ... -
java annotation
2009-03-04 15:40 733http://hi.baidu.com/sincere_yq/ ... -
break和 continue在java中的使用
2009-03-04 10:46 1010http://hi.baidu.com/jgs80/blog/ ... -
instanceof 的理解例子
2009-03-04 10:45 728http://hi.baidu.com/londalonda/ ... -
java基础复习
2009-03-04 10:40 607path,java_home,classpath 在实际开发 ... -
oracle转义字符
2009-01-12 16:42 1017http://hi.baidu.com/fuguoliang/ ... -
sql进行分组查询
2009-01-12 16:30 920http://wenwen.soso.com/z/q22515 ... -
oracle的 desc语句
2009-01-09 15:29 1537http://hi.baidu.com/yangwenlong ... -
java异常throw 与 throws关键字有什么区别?
2008-09-21 14:55 46181.throws 用于抛出方法层次的异常, 并且直接由些方法调 ...
相关推荐
在"JDBC与Java数据库程序设计"中,我们将深入探讨如何利用JDBC技术实现高效的数据库操作。 1. **JDBC基础** - JDBC API由一系列接口和类组成,如`Connection`、`Statement`、`PreparedStatement`和`ResultSet`等。...
【标题】"flume-jdbc-channel-1.5.0.1.zip" 指的是Apache Flume的一个特定版本——1.5.0.1,其中包含了一个用于数据存储的JDBC(Java Database Connectivity)通道。Flume是Apache Hadoop生态中的一个分布式、可靠且...
在Android开发中,有时我们需要实现从移动设备上访问位于外网的数据库,这通常涉及到使用Java Database Connectivity(JDBC)...这个过程虽然复杂,但通过合理的设计和良好的编程实践,可以实现高效、安全的数据交换。
本项目以"使用jdbc数据库实现登录注册,能玩华容道小游戏"为主题,涵盖了数据库交互、用户认证以及游戏开发等多个方面。 首先,我们需要理解JDBC的概念。JDBC是Java标准API,它允许Java程序与各种不同类型的数据库...
总的来说,这个项目提供了关于Java GUI编程、数据库设计和JDBC应用的实践示例,对于学习和理解这些技术的开发者来说是一个宝贵的资源。通过实际操作这个系统,开发者不仅可以掌握相关技能,还能了解如何将这些技术...
4. **ojdbc8**: ojdbc8是专为Java SE 8设计的,符合JDBC 4.3规范。它不仅包含ojdbc7的所有功能,还引入了对Java新特性的支持,比如Lambda表达式和Stream API。ojdbc8同样适用于Oracle数据库12c及以上版本。 5. **...
"200道Java程序设计练习题 PDF" 是一个宝贵的资源,旨在帮助学习者从初级到高级逐步提升Java编程技能。这份资料不仅适合初学者,也对有经验的Java开发者具有很高的参考价值,尤其是对于准备Java面试的人来说,它能够...
本项目基于Java JDBC和Socket编程实现,为用户提供类似于QQ的即时通讯功能,包括发送消息、接收消息以及可能的头像显示等功能。下面将详细讲解其中涉及的关键技术点。 1. **Java基础**: - **类与对象**:QQ聊天...
通讯录数据可能存储在关系型数据库如MySQL中,通过JDBC(Java Database Connectivity)接口进行操作。开发者需要编写SQL语句进行数据的CRUD(Create, Read, Update, Delete)操作,并封装到JavaBean中,以便于JSP...
在业务应用支撑平台设计原则中,我们需要遵循相关规或标准,例如 J2EE、XML、JDBC、E、SNMP、HTTP、TCP/IP、SSL 等业界主流标准,并采用先进和成熟的技术系统,使用 XML 规作为信息交互的标准,充分吸收国际厂商的...
之道 》,其中很多观点我看了很受启发,以前我也将"设计模式" 看成一个简单的解决方案,没有从一种高度来看待"设计模式"在软 件中地位,下面是我自己的一些想法: 建筑和软件某些地方是可以来比喻的 特别是中国传统建筑...
Spring作为现在最优秀的框架之一已被广泛的使用51CTO也曾经针对Spring框架中的JDBC应用做过 报道。本文将从另外一个视角试图剖析出Spring框架的作者设计Spring框架的骨骼架构的设计理念。 Rod Johson在2002年...
首先,登录界面是系统的第一道门,通常由HTML和CSS构建,配合JavaScript进行表单验证,确保用户输入的合法性。在后台,Servlet接收用户的登录请求,验证用户名和密码的正确性。一旦验证通过,系统会创建一个Session...
【JAVA 课程设计资料】 Java,作为一种广泛使用的高级编程语言,以其“一次编写,到处运行”的特性赢得了全球程序员的喜爱。本资料集旨在提供一个全面的Java学习资源,帮助初学者和有经验的开发者深入理解Java语言...
系统登录是系统的第一道防线,需要验证用户身份。通常包含管理员和销售员两类用户,每种用户有不同的权限。登录界面需要用户输入账号和密码,系统会验证这些信息,只有正确无误后才会允许用户进入系统。 2. **商品...
Java的JDBC API提供了连接和操作数据库的能力,理解SQL语言和事务管理也是必不可少的。 10. **用户界面设计**:系统可能包含客户端应用程序,UI设计和实现是用户体验的关键。Java Swing或JavaFX库可用于构建图形...