温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JDBC DAO的设计理念是什么

发布时间:2021-12-22 13:40:27 来源:亿速云 阅读:92 作者:iii 栏目:编程语言

这篇文章主要讲解了“JDBC DAO的设计理念是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JDBC DAO的设计理念是什么”吧!

JDBC DAO中Connection的含义

Connection表示了一个和数据库的链接,底层需要有操作系统的Socket支持,所以Connection是一种资源,既然是一种资源,就需要按照建立,打开,使用,关闭的顺序合理的使用。

Connection是Java数据库操作的基础,是进行一系列操作的基础,所有的派生的操作,例如Statement,PreparedStatement,ResultSet等都由Connection直接或者间接的衍生。

如何获得Connection呢?

方法一,使用DriverManager类来获取,前提条件是数据库驱动程序需要在classpath下(即使用数据库链接的程序按照Java的方式可以访问到)。

Connectionconn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.1:1521:ORCL",user,pwd);

方法二,使用数据库连接池来获取

什么是数据库连接池呢,数据库连接池是标准JavaEE容器的一种服务,例如Webspher,Weblogic,Tomcat等,容器预先建立一些数据库链接,以便应用程序使用的时候从中借取,注意有借有还,当应用程序使用完了之后会将数据库链接还回连接池。(数据源配置请参考其他文档)

使用连接池的好处是,可以预先建立链接,减小在数据库获取上的相对时间。

使用连接池获取数据库链接的方式为:

InitialContextctx=newInitialContext();  DataSourceds=(DataSource)ctx.lookup("java:comp/env/jdbc/DataSource");  Connectionconn=ds.getConnection();

由于在配置数据库连接池的时候已经定义了URL,用户名,密码等信息,所以在程序中使用的时候不需要传入这些信息。

JDBC DAO中ConnectionManager定义

Connection用来专门管理数据库链接,通常情况下ConnectionManager只有一个方法,调用这个方法将返回一个Connection的实例。通过ConnectionManager可以封装Connection的获取方式(例如开发的时候使用DriverManager,运用的时候使用DataSource的方式,但是不需要修改ConnectionManager之外的其他代码)和追加Connection获取之前之后的操作(例如针对Connection的属性的设置)。

下面的代码是一个ConnectionManager的代码示例:

packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;  importjava.sql.DriverManager;  importjava.sql.SQLException;   publicclassConnectionManager{   publicstaticConnectiongetConnection()throwsDaoException{  Connectionconn=null;  try{  conn=DriverManager.getConnection("","","");  }catch(SQLExceptione){  thrownewDaoException("cannotgetdatabaseconnection",e);  }  returnconn;  }  }

如果需要从开发模式变为运用模式,只需要将上述代码修改为:

packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;  importjava.sql.DriverManager;  importjava.sql.SQLException;   publicclassConnectionManager{   publicstaticConnectiongetConnection()throwsDaoException{  Connectionconn=null;  try{  Contextctx=newInitialContext();  DataSourceds=(DataSource)ctx.lookup("jdbc/dsname");  conn=ds.getConnection();  }catch(NamingExceptione){  thrownewDaoException("cannotfinddatasource",e);  }catch(SQLExceptione){  thrownewDaoException("cannotgetdatabaseconnection",e);  }  returnconn;  }  }   如果需要预先设定Connection的一些属性,也可以在上述代码中设定,例如:  packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;  importjava.sql.DriverManager;  importjava.sql.SQLException;   publicclassConnectionManager{   publicstaticConnectiongetConnection()throwsDaoException{  Connectionconn=null;  try{  Contextctx=newInitialContext();  DataSourceds=(DataSource)ctx.lookup("jdbc/dsname");  conn=ds.getConnection();  conn.setAutoCommit(false);  }catch(NamingExceptione){  thrownewDaoException("cannotfinddatasource",e);  }catch(SQLExceptione){  thrownewDaoException("cannotgetdatabaseconnection",e);  }  returnconn;  }  }   CommonDao定义  属性和构造方法  通常情况下,CommonDao要有一个Connection的引用。所有一个CommonDao的实例的所有方法的调用都需要依赖于这个Connection。需要一个Connection的另外一个原因是如果各个方法需要保证在一个事务环境中(上下文中),必须保证所有的操作都在一个Connection上。  构造方法通常需要将类型为Connection的属性实例化,例如:   packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;   publicclassCommonDao{   privateConnectionconn;   publicCommonDao()throwsDaoException{  this.conn=ConnectionManager.getConnection();  }  }

事务方法

begin()

开始一个事务,调用CommonDao的begin方法之后,所以的后续操作将会在一个事务环境内,要么全部提交,要么全部回滚。

commit()

提交一个事务,必须在begin调用之后调用。且和rollback方法互斥。

rollback()

回滚一个事务,必须在begin方法调用之后调用。且和commit方法互斥。

事务的实现有两种方法,一种是使用基于单一Connection的事务,另外一种方法是使用容器的JTA(JavaTransactionAPI)。需要注意的是***种方法可以在任何环境下使用,但是只能是针对单一的数据库链接。第二种方法智能在支持JTA的JavaEE容器中使用(例如Websphere,Weblogic等,Tomcat默认不支持),但是支持多个Connection实例。

***种方法代码为:

packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;  importjava.sql.SQLException;   publicclassCommonDao{   privateConnectionconn;   publicCommonDao()throwsDaoException{  this.conn=ConnectionManager.getConnection();  }   publicvoidbegin()throwsDaoException{  if(conn!=null){  try{  conn.setAutoCommit(false);  }catch(SQLExceptione){  thrownewDaoException("cannotbegintransaction",e);  }  }else{  thrownewDaoException("connectionnotopened!");  }  }   publicvoidcommit()throwsDaoException{  try{  if(conn!=null&&!conn.getAutoCommit()){  conn.commit();  conn.setAutoCommit(true);  }else{  if(conn==null){  thrownewDaoException("connectionnotopened!");  }else{  thrownewDaoException("firstbeginthencommitplease!");  }  }  }catch(SQLExceptione){  thrownewDaoException("cannotcommittransaction!",e);  }  }   publicvoidrollback()throwsDaoException{  try{  if(conn!=null&&!conn.getAutoCommit()){  conn.rollback();  conn.setAutoCommit(true);  }else{  if(conn==null){  thrownewDaoException("connectionnotopened!");  }else{  thrownewDaoException("firstbeginthenrollbackplease!");  }  }  }catch(SQLExceptione){  thrownewDaoException("cannotrollbacktransaction!",e);  }  }  }

第二种我们在使用DAO的实例中介绍如何使用(@TODO)

新建两个DAO,做不同的操作,使用JTA保证事务完整。

查询方法

查询方法也许是CommonDao最常用的方法,查询方法需要将数据库的结果返回给画面。返回值我们一般不使用ResultSet,因为ResultSet依赖于Connection,如果Connection关闭,ResultSet将不再有效,所以我们通常将ResultSet转变为一个List之后返回。

在说明查询方法之前,我们先说说如何将数据库中的内容放在List中,我们使用一个List表示一个查询结果集合,使用一个Map表示集合中的一行,Map的key表示数据库表的字段名字,Value表示数据库字段的内容。代码为:

privateListconvert(ResultSetrs)throwsDaoException{   //recordlist  ListretList=newArrayList();   try{  ResultSetMetaDatameta=rs.getMetaData();   //columncount  intcolCount=meta.getColumnCount();   //eachrecord  while(rs.next()){   MaprecordMap=newHashMap();   //eachcolumn  for(inti=1;i<=colCount;i++){  //columnname  Stringname=meta.getColumnName(i);  //columnvalue  Objectvalue=rs.getObject(i);  //addcolumntorecord  recordMap.put(name,value);  }  //adrecordtolist  retList.add(recordMap);  }  }catch(SQLExceptionex){  thrownewDaoException("cannotconvertresultsettolistofmap",ex);  }  returnretList;  }

为了避免Sql注入的安全问题,我们通常使用PreparedStatement,在使用PreparedStatement的时候涉及到如何将传入参数设置到PreparedStatement上面,参看以下的共通方法:

privatevoidapply(PreparedStatementpstmt,Listparams)throwsDaoException{  try{  //ifparamsexist  if(params!=null&&para;ms.size()>0){  //parametersiterator  Iteratorit=params.iterator();   //parameterindex  intindex=1;  while(it.hasNext()){   Objectobj=it.next();  //ifnullset""  if(obj==null){  pstmt.setObject(index,"");  }else{  //elsesetobject  pstmt.setObject(index,obj);  }   //nextindex  index++;  }  }  }catch(SQLExceptionex){  thrownewDaoException("cannotapplyparameter",ex);  }  }   接着我们继续说我们的查询方法,有了上述两个方法,我们的查询方法就非常简单了:  publicListquery(Stringsql,Listparams)throwsDaoException{  Listresult=null;  PreparedStatementpstmt=null;  ResultSetrs=null;  try{  pstmt=conn.prepareStatement(sql);  this.apply(pstmt,params);  rs=pstmt.executeQuery();  result=this.convert(rs);  }catch(SQLExceptionex){  thrownewDaoException("cannotexecutequery",ex);  }finally{  if(rs!=null){  try{  rs.close();  }catch(SQLExceptione){  //nothing  }  }  if(pstmt!=null){  try{  pstmt.close();  }catch(SQLExceptione){  //nothing  }  }  }  returnresult;  }

特殊的查询方法(返回单值)

有时候为了方便使用,我们需要返回单值的产寻方法,例如selectmax(id)fromtable_a,selectcount(id)fromtable_b等。以下的代码使用了上述通用的查询方法,代码为:

publicObjectqueryOne(Stringsql,Listparams)throwsDaoException{  Listlist=this.query(sql,params);   if(list==null||list.size()==0){  thrownewDaoException("datanotexist");  }else{  Maprecord=(Map)list.get(0);  if(record==null||record.size()==0){  thrownewDaoException("datanotexist");  }else{  returnrecord.values().toArray()[0];  }  }  }

更新,删除,插入方法

由于在JDBC中这三个方法都是用了一个execute完成,所以这里我们也使用一个方法来完成这些功能。代码为:

publicintexecute(Stringsql,Listparams)throwsDaoException{  intret=0;  PreparedStatementpstmt=null;  try{  pstmt=conn.prepareStatement(sql);  this.apply(pstmt,params);  ret=pstmt.executeUpdate();  }catch(SQLExceptionex){  thrownewDaoException("",ex);  }finally{  if(pstmt!=null){  try{  pstmt.close();  }catch(SQLExceptione){  //nothing.  }  }  }   returnret;  }

批处理方法(查询)

有些时候为了便于操作,需要一次查询多条SQL语句,我们称之为批处理,实现参看以下方法,其中为了和query方法做区分,将参数和返回值都改为了数组形式。

publicList[]queryBatch(String[]sqlArray,List[]paramArray)throwsDaoException{  Listrets=newArrayList();  if(sqlArray.length!=paramArray.length){  thrownewDaoException("sqlsizenotequalparametersize");  }else{  for(inti=0;iStringsql=sqlArray[i];  Listparam=paramArray[i];  Listret=this.query(sql,param);  rets.add(ret);  }  return(List[])rets.toArray();  }  }

批处理方法(更新)

有些时候需要一次更新多条Sql语句,为了便于操作,添加了批处理更新操作,参看以下代码,为了和更新方法区分,将参数和返回值都改为了数组形式。

publicint[]executeBatch(String[]sqlArray,List[]paramArray)throwsDaoException{  Listrets=newArrayList();  if(sqlArray.length!=paramArray.length){  thrownewDaoException("sqlsizenotequalparametersize");  }else{  for(inti=0;iintret=this.execute(sqlArray[i],paramArray[i]);  rets.add(newInteger(ret));  }   int[]retArray=newint[rets.size()];  for(inti=0;iretArray[i]=((Integer)rets.get(i)).intValue();  }   returnretArray;  }  }

资源释放

由于CommonDao有一个Connection的属性,且Connection属于稀缺资源,所以在CommonDao不需要在使用的时候需要显示的关闭Connection。代码如下:

publicvoidclose()throwsDaoException{  try{  if(conn!=null&&conn.getAutoCommit()){  conn.close();  }else{  if(conn==null){  thrownewDaoException("cannotclosenullconnection,firstnewthenclose");  }else{  thrownewDaoException("transactionisrunning,rollbakcorcommitbeforcloseplease.");  }  }  }catch(SQLExceptionex){  thrownewDaoException("Cannotclosecommondao");  }  }

JDBC工具类(JDBCUtilClass)

在上述的代码中我们看到有很多的无用的处理,例如:

if(pstmt!=null){  try{  pstmt.close();  }catch(SQLExceptione){  //nothing.  }  }

为什么要有这些处理呢?说先这些处理发生的位置都是在正常处理完成之后,这些处理(例如pstmt.close())即使失败也没有影响,这个时候我们需要做上述的无用处理,这正是JDBCAPI的一个小小的瑕疵。我们通常使用一个特殊的静态工具来来做补充,例如:

packagecom.jpleasure.jdbc.dao;   importjava.sql.Connection;  importjava.sql.PreparedStatement;  importjava.sql.ResultSet;  importjava.sql.SQLException;   publicclassJDBCUtil{  publicvoidsafelyClose(Connectionconn){  if(conn!=null){  try{  conn.close();  }catch(SQLExceptione){  //  }  }  }  publicvoidsafelyClose(PreparedStatementpstmt){  if(pstmt!=null){  try{  pstmt.close();  }catch(SQLExceptione){  //  }  }  }  publicvoidsafelyClose(ResultSetrs){  if(rs!=null){  try{  rs.close();  }catch(SQLExceptione){  //  }  }  }  }

JDBC DAO中异常处理

也许细心的你已经发现了一个问题,为什么所有抛出异常的地方我们都是将SQLException包装在了DaoException之内抛出呢,为什么不直接抛出SQLException呢?有两个原因,***,可以细化,分类Exception抛出合适的异常,添加合适的消息,第二,隔离和Dao和业务逻辑的耦合,可以方便的修改Dao层而不会影响到业务逻辑层。另外需要注意,DaoExcetion中可以包含SQLException,这个时候可以为客户提供更详细的错误信息,例如ORA-12524等内容,但是很少见到。

packagecom.jpleasure.jdbc.dao;  publicclassDaoExceptionextendsException{  publicDaoException(){  super();  }  publicDaoException(Stringmessage,Throwablecause){  super(message,cause);  }  publicDaoException(Stringmessage){  super(message);  }  publicDaoException(Throwablecause){  super(cause);  }  }

感谢各位的阅读,以上就是“JDBC DAO的设计理念是什么”的内容了,经过本文的学习后,相信大家对JDBC DAO的设计理念是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI