您的位置:程序门 -> java -> j2se / 基础类



【学习&讨论】一个类设计的问题,不看的一定后悔,大家一起学习!


[收藏此页] [打印本页]选择字色:背景色:字体:[][][]


【学习&讨论】一个类设计的问题,不看的一定后悔,大家一起学习!
发表于:2007-01-14 21:49:05 楼主
请问下面两种方式有何区别,各自的优点和缺点是什么?

//第一种,为每个方法创建一个connection
public   class   testa
{
private   connection   getconnection()
{
class.forname( "... ");
connection   conn   =   drivermanager.getconnection( "... ");
return   conn;
}

public   void   methoda()
{
connection   conn   =   getconnection();
...
conn.close();
}

                  public   void   methodb()
{
connection   conn   =   getconnection();
...
conn.close();
}
}

//第二种,创建一个connection实例变量,供所有的方法调用
public   class   testb
{
private   connection   conn;

public   test()
{
class.forname( "... ");
this.conn   =   drivermanager.getconnection( "... ");
}

public   void   methoda()
{
...
statement   st   =   this.conn.createstatement();
...
this.conn.close();
}

                  public   void   methodb()
{
...
statement   st   =   this.conn.createstatement();
...
this.conn.close();
}
}
发表于:2007-01-14 22:05:181楼 得分:0
第一种,方法之间使用独立的数据库连接,
第二种,设计上存在问题,methoda和methodb应该是共享一个连接,但是又在调用各自方法之后把连接给关闭了,下一个方法调用的时候连接已经关闭,数据库操作明显会出错,数据库连接的关闭操作应该独立出来,也不是由methoda和methodb来调用(既然他们也没有创建连接),有点数据库连接池的味道,只不过只有一个连接
发表于:2007-01-15 12:19:442楼 得分:0
第一种你说的等于没说。。。

第二种调用methoda()和methodb()的时候是这样的,
test   t1   =   new   test();
t1.methoda();

test   t2   =   new   test();
t2.methodb();

不过我现在发现第二种的设计是有问题的,每次调用方法时都要创建一个对象!
发表于:2007-01-15 13:02:193楼 得分:0
第一种方法每次调用都要建立连接,比较消耗时间,所以一般都是建立一个连接后重复使用,就是你的第二种方法.   不过this.conn.close();应该去掉,放到finally块中关闭连接
发表于:2007-01-15 16:12:264楼 得分:0
第二种方法完全错误,同一个连接建立一次关闭多次,
第一种是对的,但是有性能问题,建议使用连接池
发表于:2007-01-17 11:55:155楼 得分:0
001   import   java.io.*;
002   import   java.sql.*;
003   import   java.util.*;
004   import   java.util.date;
005
006   /**
007   *   管理类dbconnectionmanager支持对一个或多个由属性文件定义的数据库连接
008   *   池的访问.客户程序可以调用getinstance()方法访问本类的唯一实例.
009   */
010   public   class   dbconnectionmanager   {
011   static   private   dbconnectionmanager   instance;   //   唯一实例
012   static   private   int   clients;
013
014   private   vector   drivers   =   new   vector();
015   private   printwriter   log;
016   private   hashtable   pools   =   new   hashtable();
017
018   /**
019   *   返回唯一实例.如果是第一次调用此方法,则创建实例
020   *
021   *   @return   dbconnectionmanager   唯一实例
022   */
023   static   synchronized   public   dbconnectionmanager   getinstance()   {
024   if   (instance   ==   null)   {
025   instance   =   new   dbconnectionmanager();
026   }
027   clients++;
028   return   instance;
029   }
030
031   /**
032   *   建构函数私有以防止其它对象创建本类实例
033   */
034   private   dbconnectionmanager()   {
035   init();
036   }
037
038   /**
039   *   将连接对象返回给由名字指定的连接池
040   *
041   *   @param   name   在属性文件中定义的连接池名字
042   *   @param   con   连接对象
043   */
044   public   void   freeconnection(string   name,   connection   con)   {
045   dbconnectionpool   pool   =   (dbconnectionpool)   pools.get(name);
046   if   (pool   !=   null)   {
047   pool.freeconnection(con);
048   }
049   }
050
051   /**
052   *   获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
053   *   限制,则创建并返回新连接
054   *
055   *   @param   name   在属性文件中定义的连接池名字
056   *   @return   connection   可用连接或null
057   */
058   public   connection   getconnection(string   name)   {
059   dbconnectionpool   pool   =   (dbconnectionpool)   pools.get(name);
060   if   (pool   !=   null)   {
061   return   pool.getconnection();
062   }
063   return   null;
064   }
065
066   /**
067   *   获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
068   *   则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
069   *
070   *   @param   name   连接池名字
071   *   @param   time   以毫秒计的等待时间
072   *   @return   connection   可用连接或null
073   */
074   public   connection   getconnection(string   name,   long   time)   {
075   dbconnectionpool   pool   =   (dbconnectionpool)   pools.get(name);
076   if   (pool   !=   null)   {
077   return   pool.getconnection(time);
078   }
079   return   null;
080   }
081
082   /**
083   *   关闭所有连接,撤销驱动程序的注册
084   */
085   public   synchronized   void   release()   {
086   //   等待直到最后一个客户程序调用
087   if   (--clients   !=   0)   {
088   return;
089   }
090
091   enumeration   allpools   =   pools.elements();
092   while   (allpools.hasmoreelements())   {
093   dbconnectionpool   pool   =   (dbconnectionpool)   allpools.nextelement();
094   pool.release();
095   }
096   enumeration   alldrivers   =   drivers.elements();
097   while   (alldrivers.hasmoreelements())   {
098   driver   driver   =   (driver)   alldrivers.nextelement();
099   try   {
100   drivermanager.deregisterdriver(driver);
101   log( "撤销jdbc驱动程序   "   +   driver.getclass().getname()+ "的注册 ");
102   }
103   catch   (sqlexception   e)   {
104   log(e,   "无法撤销下列jdbc驱动程序的注册:   "   +   driver.getclass().getname());
105   }
106   }
107   }
108
109   /**
110   *   根据指定属性创建连接池实例.
111   *
112   *   @param   props   连接池属性
113   */
114   private   void   createpools(properties   props)   {
115   enumeration   propnames   =   props.propertynames();
116   while   (propnames.hasmoreelements())   {
117   string   name   =   (string)   propnames.nextelement();
118   if   (name.endswith( ".url "))   {
119   string   poolname   =   name.substring(0,   name.lastindexof( ". "));
120   string   url   =   props.getproperty(poolname   +   ".url ");
121   if   (url   ==   null)   {
122   log( "没有为连接池 "   +   poolname   +   "指定url ");
123   continue;
124   }
125   string   user   =   props.getproperty(poolname   +   ".user ");
126   string   password   =   props.getproperty(poolname   +   ".password ");
127   string   maxconn   =   props.getproperty(poolname   +   ".maxconn ",   "0 ");
128   int   max;
129   try   {
130   max   =   integer.valueof(maxconn).intvalue();
131   }
132   catch   (numberformatexception   e)   {
133   log( "错误的最大连接数限制:   "   +   maxconn   +   "   .连接池:   "   +   poolname);
134   max   =   0;
135   }
136   dbconnectionpool   pool   =
137   new   dbconnectionpool(poolname,   url,   user,   password,   max);
138   pools.put(poolname,   pool);
139   log( "成功创建连接池 "   +   poolname);
140   }
141   }
142   }
143
144   /**
145   *   读取属性完成初始化
146   */
147   private   void   init()   {
148   inputstream   is   =   getclass().getresourceasstream( "/db.properties ");
149   properties   dbprops   =   new   properties();
150   try   {
151   dbprops.load(is);
152   }
153   catch   (exception   e)   {
154   system.err.println( "不能读取属性文件.   "   +
155   "请确保db.properties在classpath指定的路径中 ");
156   return;
157   }
158   string   logfile   =   dbprops.getproperty( "logfile ",   "dbconnectionmanager.log ");
159   try   {
160   log   =   new   printwriter(new   filewriter(logfile,   true),   true);
161   }
162   catch   (ioexception   e)   {
163   system.err.println( "无法打开日志文件:   "   +   logfile);
164   log   =   new   printwriter(system.err);
165   }
166   loaddrivers(dbprops);
167   createpools(dbprops);
168   }
169
170   /**
171   *   装载和注册所有jdbc驱动程序
172   *
173   *   @param   props   属性
174   */
175   private   void   loaddrivers(properties   props)   {
176   string   driverclasses   =   props.getproperty( "drivers ");
177   stringtokenizer   st   =   new   stringtokenizer(driverclasses);
178   while   (st.hasmoreelements())   {
179   string   driverclassname   =   st.nexttoken().trim();
180   try   {
181   driver   driver   =   (driver)
182   class.forname(driverclassname).newinstance();
183   drivermanager.registerdriver(driver);
184   drivers.addelement(driver);
185   log( "成功注册jdbc驱动程序 "   +   driverclassname);
186   }
187   catch   (exception   e)   {
188   log( "无法注册jdbc驱动程序:   "   +
189   driverclassname   +   ",   错误:   "   +   e);
190   }
191   }
192   }
193
194   /**
195   *   将文本信息写入日志文件
196   */
发表于:2007-01-17 11:55:256楼 得分:0
197   private   void   log(string   msg)   {
198   log.println(new   date()   +   ":   "   +   msg);
199   }
200
201   /**
202   *   将文本信息与异常写入日志文件
203   */
204   private   void   log(throwable   e,   string   msg)   {
205   log.println(new   date()   +   ":   "   +   msg);
206   e.printstacktrace(log);
207   }
208
209   /**
210   *   此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最
211   *   大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.
212   */
213   class   dbconnectionpool   {
214   private   int   checkedout;
215   private   vector   freeconnections   =   new   vector();
216   private   int   maxconn;
217   private   string   name;
218   private   string   password;
219   private   string   url;
220   private   string   user;
221
222   /**
223   *   创建新的连接池
224   *
225   *   @param   name   连接池名字
226   *   @param   url   数据库的jdbc   url
227   *   @param   user   数据库帐号,或   null
228   *   @param   password   密码,或   null
229   *   @param   maxconn   此连接池允许建立的最大连接数
230   */
231   public   dbconnectionpool(string   name,   string   url,   string   user,   string   password,
232   int   maxconn)   {
233   this.name   =   name;
234   this.url   =   url;
235   this.user   =   user;
236   this.password   =   password;
237   this.maxconn   =   maxconn;
238   }
239
240   /**
241   *   将不再使用的连接返回给连接池
242   *
243   *   @param   con   客户程序释放的连接
244   */
245   public   synchronized   void   freeconnection(connection   con)   {
246   //   将指定连接加入到向量末尾
247   freeconnections.addelement(con);
248   checkedout--;
249   notifyall();
250   }
251
252   /**
253   *   从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
254   *   数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
255   *   然后递归调用自己以尝试新的可用连接.
256   */
257   public   synchronized   connection   getconnection()   {
258   connection   con   =   null;
259   if   (freeconnections.size()   >   0)   {
260   //   获取向量中第一个可用连接
261   con   =   (connection)   freeconnections.firstelement();
262   freeconnections.removeelementat(0);
263   try   {
264   if   (con.isclosed())   {
265   log( "从连接池 "   +   name+ "删除一个无效连接 ");
266   //   递归调用自己,尝试再次获取可用连接
267   con   =   getconnection();
268   }
269   }
270   catch   (sqlexception   e)   {
271   log( "从连接池 "   +   name+ "删除一个无效连接 ");
272   //   递归调用自己,尝试再次获取可用连接
273   con   =   getconnection();
274   }
275   }
276   else   if   (maxconn   ==   0   ¦ ¦   checkedout   <   maxconn)   {
277   con   =   newconnection();
278   }
279   if   (con   !=   null)   {
280   checkedout++;
281   }
282   return   con;
283   }
284
285   /**
286   *   从连接池获取可用连接.可以指定客户程序能够等待的最长时间
287   *   参见前一个getconnection()方法.
288   *
289   *   @param   timeout   以毫秒计的等待时间限制
290   */
291   public   synchronized   connection   getconnection(long   timeout)   {
292   long   starttime   =   new   date().gettime();
293   connection   con;
294   while   ((con   =   getconnection())   ==   null)   {
295   try   {
296   wait(timeout);
297   }
298   catch   (interruptedexception   e)   {}
299   if   ((new   date().gettime()   -   starttime)   > =   timeout)   {
300   //   wait()返回的原因是超时
301   return   null;
302   }
303   }
304   return   con;
305   }
306
307   /**
308   *   关闭所有连接
309   */
310   public   synchronized   void   release()   {
311   enumeration   allconnections   =   freeconnections.elements();
312   while   (allconnections.hasmoreelements())   {
313   connection   con   =   (connection)   allconnections.nextelement();
314   try   {
315   con.close();
316   log( "关闭连接池 "   +   name+ "中的一个连接 ");
317   }
318   catch   (sqlexception   e)   {
319   log(e,   "无法关闭连接池 "   +   name+ "中的连接 ");
320   }
321   }
322   freeconnections.removeallelements();
323   }
324
325   /**
326   *   创建新的连接
327   */
328   private   connection   newconnection()   {
329   connection   con   =   null;
330   try   {
331   if   (user   ==   null)   {
332   con   =   drivermanager.getconnection(url);
333   }
334   else   {
335   con   =   drivermanager.getconnection(url,   user,   password);
336   }
337   log( "连接池 "   +   name+ "创建一个新的连接 ");
338   }
339   catch   (sqlexception   e)   {
340   log(e,   "无法创建下列url的连接:   "   +   url);
341   return   null;
342   }
343   return   con;
344   }
345   }
346   }
发表于:2007-01-17 13:09:047楼 得分:0
第1种方法勉强可以采用
第2中设计根本是不正确的~,不知道设计者出于哪种目的这样设计
发表于:2007-01-17 13:57:358楼 得分:0
恩第2种设计不正确.
发表于:2007-05-15 20:16:329楼 得分:0
成年老帖顶起   大家一起学习
发表于:2007-05-16 01:45:0810楼 得分:0
该回复于2007-12-28 11:30:29被管理员或版主删除
发表于:2007-05-16 08:15:3411楼 得分:0
学习学习
发表于:2007-05-16 10:58:2212楼 得分:0
第2种根本看不明白!!太菜了!!5555
发表于:2007-05-16 12:32:5513楼 得分:0
up
发表于:2007-05-16 12:43:1614楼 得分:0
按照楼住的调用方式,两种方式完全相同
发表于:2007-05-16 12:46:3215楼 得分:0
fanxiangqin(mary)的连接池是从网上下载的吧,我感觉用起来挺顺手
只是freeconnection设计有点问题
每个人肯定都只想采用freeconnection(conn)的方式,可是如果释放到其他池了
系统可能会崩溃
发表于:2007-05-16 12:50:0416楼 得分:0
up
发表于:2007-05-16 14:38:5917楼 得分:0
都不好~
发表于:2007-05-16 14:43:2318楼 得分:0
数据库的连接数也是有限的资源,最好采用连接池
发表于:2007-05-16 18:49:3419楼 得分:0
连接池


快速检索

最新资讯
热门点击