1. //$Id: DriverManagerConnectionProvider.java 7888 2005-08-12 21:22:38Z oneovthafew $
2.     
3. package
4.     
5.     
6.     
7. import
8.     
9. import
10.     
11. import
12.     
13. import
14.     
15. import
16.     
17. import
18.     
19.     
20.     
21. import
22.     
23. import
24.     
25. import
26.     
27. import
28.     
29. import
30.     
31. import
32.     
33.     
34.     
35. /**
36.    
37.  * A connection provider that uses <tt>java.sql.DriverManager</tt>. This provider
38.    
39.  * also implements a very rudimentary connection pool.
40.    
41.  * @see ConnectionProvider
42.    
43.  * @author Gavin King
44.    
45.  */
46.     
47. public   class  DriverManagerConnectionProvider  implements
48.     
49.     
50.     
51. private
52.     
53. private
54.     
55. private
56.     
57. private   final  ArrayList pool =  new
58.     
59. private   int
60.     
61. private   int  checkedOut =  0
62.     
63. private   boolean
64.     
65.     
66.     
67. private   static   final  Logger log = LoggerFactory.getLogger(DriverManagerConnectionProvider. class
68.     
69.     
70.     
71. public   void  configure(Properties props)  throws
72.     
73.     
74.     
75.          String driverClass = props.getProperty(Environment.DRIVER);   
76.     
77.     
78.     
79. 20 );  //default pool size 20
80.     
81. "Using Hibernate built-in connection pool (not for production use!)"
82.     
83. "Hibernate connection pool size: "
84.     
85.             
86.     
87.          autocommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);   
88.     
89. "autocommit mode: "
90.     
91.     
92.     
93.          isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);   
94.     
95. if  (isolation!= null
96.     
97. "JDBC isolation level: "
98.     
99.     
100.     
101. if  (driverClass== null
102.     
103. "no JDBC Driver class was specified by property "
104.     
105.          }   
106.     
107. else
108.     
109. try
110.     
111. // trying via forName() first to be as close to DriverManager's semantics
112.     
113.                  Class.forName(driverClass);   
114.     
115.              }   
116.     
117. catch
118.     
119. try
120.     
121.                      ReflectHelper.classForName(driverClass);   
122.     
123.                  }   
124.     
125. catch
126.     
127. "JDBC Driver class not found: "
128.     
129.                      log.error( msg, e );   
130.     
131. throw   new
132.     
133.                  }   
134.     
135.              }   
136.     
137.          }   
138.     
139.     
140.     
141.          url = props.getProperty( Environment.URL );   
142.     
143. if  ( url ==  null
144.     
145. "JDBC URL was not specified by property "
146.     
147.              log.error( msg );   
148.     
149. throw   new
150.     
151.          }   
152.     
153.     
154.     
155.          connectionProps = ConnectionProviderFactory.getConnectionProperties( props );   
156.     
157.     
158.     
159. "using driver: "  + driverClass +  " at URL: "
160.     
161. // if debug level is enabled, then log the password, otherwise mask it
162.     
163. if
164.     
165. "connection properties: "
166.     
167.          }    
168.     
169. else   if
170.     
171. "connection properties: "  + PropertiesHelper.maskOut(connectionProps,  "password"
172.     
173.          }   
174.     
175.     
176.     
177.      }   
178.     
179.     
180.     
181. public  Connection getConnection()  throws
182.     
183.     
184.     
185. if  ( log.isTraceEnabled() ) log.trace(  "total checked-out connections: "
186.     
187.     
188.     
189. synchronized
190.     
191. if
192.     
193. int  last = pool.size() -  1
194.     
195. if
196.     
197. "using pooled JDBC connection, pool size: "
198.     
199.                      checkedOut++;   
200.     
201.                  }   
202.     
203.                  Connection pooled = (Connection) pool.remove(last);   
204.     
205. if  (isolation!= null
206.     
207. if
208.     
209. return
210.     
211.              }   
212.     
213.          }   
214.     
215.     
216.     
217. "opening new JDBC connection"
218.     
219.          Connection conn = DriverManager.getConnection(url, connectionProps);   
220.     
221. if  (isolation!= null
222.     
223. if
224.     
225.     
226.     
227. if
228.     
229. "created connection to: "  + url +  ", Isolation Level: "
230.     
231.          }   
232.     
233. if
234.     
235.     
236.     
237. return
238.     
239.      }   
240.     
241.     
242.     
243. public   void  closeConnection(Connection conn)  throws
244.     
245.     
246.     
247. if
248.     
249.     
250.     
251. synchronized
252.     
253. int
254.     
255. if
256.     
257. if  ( log.isTraceEnabled() ) log.trace( "returning connection to pool, pool size: "  + (currentSize +  1
258.     
259.                  pool.add(conn);   
260.     
261. return
262.     
263.              }   
264.     
265.          }   
266.     
267.     
268.     
269. "closing JDBC connection"
270.     
271.     
272.     
273.          conn.close();   
274.     
275.     
276.     
277.      }   
278.     
279.     
280.     
281. protected   void
282.     
283.          close();   
284.     
285.      }   
286.     
287.     
288.     
289. public   void
290.     
291.     
292.     
293. "cleaning up connection pool: "
294.     
295.     
296.     
297.          Iterator iter = pool.iterator();   
298.     
299. while
300.     
301. try
302.     
303.                  ( (Connection) iter.next() ).close();   
304.     
305.              }   
306.     
307. catch
308.     
309. "problem closing pooled connection"
310.     
311.              }   
312.     
313.          }   
314.     
315.          pool.clear();   
316.     
317.     
318.     
319.      }   
320.     
321.     
322.     
323. /**
324.    
325.      * @see ConnectionProvider#supportsAggressiveRelease()
326.    
327.      */
328.     
329. public   boolean
330.     
331. return   false
332.     
333.      }   
334.     
335.     
336.     
337.  }


DriverManagerConnectionProvider类继承了ConnectionProvider接口,主要是使用用户提供的JDBC驱动程序来连接数据库,或者使用连接池的方式来连接数据库。    一个典型的JDBC驱动连接数据库的方式:


1. < property   name = "connection.driver_class" > com.mysql.jdbc.Driver </ property >
2.     
3.     
4.     
5.     
6.     
7. <!-- 连接数据库的URL-->
8.     
9.     
10.     
11. < property   name = "connection.url" >
12.     
13.     
14.     
15.  jdbc:mysql://localhost:3306/schoolproject   
16.     
17.     
18.     
19. </ property >
20.     
21.     
22.     
23. < property   name = "connection.useUnicode" > true </ property >
24.     
25.     
26.     
27. < property   name = "connection.characterEncoding" > UTF-8 </ property >
28.     
29.     
30.     
31.     
32.     
33. <!--连接的登录名-->
34.     
35.     
36.     
37. < property   name = "connection.username" > root </ property >
38.     
39.     
40.     
41.     
42.     
43. >
44.     
45.     
46.     
47. < property   name = "connection.password" > </ property >
48.     
49.     
50.     
51.     
52.     
53. <!--是否将运行期生成的SQL输出到日志以供调试-->
54.     
55.     
56.     
57. < property   name = "show_sql" > true </ property >
58.     
59.     
60.     
61.     
62.     
63. <!--指定连接的语言-->
64.     
65.     
66.     
67. < property   name = "dialect" > org.hibernate.dialect.MySQLDialect </ property >

 至于连接池,由于在hibernate3.0中,已经不再支持dbcp 了,hibernate的作者在hibernate.org中,明确指出在实践中发现dbcp有BUG,在某些种情会产生很多空连接不能释放,所以抛弃了 对dbcp的支持。因此官方推荐使用c3p0或Proxool连接池。

  C3P0连接配置


1. >
2.     
3.     
4.     
5. < property   name = "connection.driver_class" > com.mysql.jdbc.Driver </ property >
6.     
7.     
8.     
9. <!-- 连接数据库的URL-->
10.     
11.     
12.     
13. < property   name = "connection.url" >
14.     
15.     
16.     
17.  jdbc:mysql://localhost:3306/schoolproject   
18.     
19.     
20.     
21. </ property >
22.     
23.     
24.     
25. < property   name = "connection.useUnicode" > true </ property >
26.     
27.     
28.     
29. < property   name = "connection.characterEncoding" > UTF-8 </ property >
30.     
31.     
32.     
33. <!--连接的登录名-->
34.     
35.     
36.     
37. < property   name = "connection.username" > root </ property >
38.     
39.     
40.     
41. <!--登录密码-->
42.     
43.     
44.     
45. < property   name = "connection.password" > </ property >
46.     
47.     
48.     
49. <!-- C3P0连接池设定-->
50.     
51.     
52.     
53. < property   name = "hibernate.connection.provider_class" >
54.     
55. </ property >
56.     
57.     
58.     
59. < property   name = "hibernate.c3p0.max_size" > 20 </ property >
60.     
61.     
62.     
63. < property   name = "hibernate.c3p0.min_size" > 5 </ property >
64.     
65.     
66.     
67. < property   name = "hibernate.c3p0.timeout" > 120 </ property >
68.     
69.     
70.     
71. < property   name = "hibernate.c3p0.max_statements" > 100 </ property >
72.     
73.     
74.     
75. < property   name = "hibernate.c3p0.idle_test_period" > 120 </ property >
76.     
77.     
78.     
79. < property   name = "hibernate.c3p0.acquire_increment" > 2 </ property >
80.     
81.     
82.     
83. <!--是否将运行期生成的SQL输出到日志以供调试-->
84.     
85.     
86.     
87. < property   name = "show_sql" > true </ property >
88.     
89.     
90.     
91. <!--指定连接的语言-->
92.     
93.     
94.     
95. < property   name = "dialect" > org.hibernate.dialect.MySQLDialect </ property >


   首先看DriverManagerConnectionProvider的 configure(Properties props)方法,在这个方法中并没有去判断是否使用了连接池,真正判断使用连接池是在ConnectionProviderFactory这个类中,我 们以后会分析。   

  DriverManagerConnectionProvider这个类只是初始化了最基 本的连接配置,有如下几个:hibernate.connection.driver_class(JDBC驱动类)、 hibernate.connection.pool_size(连接池容量的上限数目)、 hibernate.connection.autocommit(允许被缓存的JDBC连接开启自动自动提交)、 hibernate.connection.isolation(设置JDBC事务隔离级别,可查看java.sql.Connection来了解各个值 的具体意义,但请注意多数数据库都不支持所有的隔离级别,取值1,2,4,8)。无论你是使用JDBC还是使用连接池方式,这几个最基本的设置都是要先初 始化的。其中pool_size的默认值为20。

  configure(Properties props)方法中的这个语句connectionProps = ConnectionProviderFactory.getConnectionProperties( props );值得注意, ConnectionProviderFactory.getConnectionProperties( props )主要是把HIBERNATE.CFG或者HIBERNATE.PROPERTIES的配置文件中的属性重新封装到另一个Properties 类——connectionProps中,且connectionProps的键值与 HIBERNATE.CFG或者HIBERNATE.PROPERTIES中的键值相比是没有“hibernate.connection”这样的字样 的,比如,在HIBERNATE.PROPERTIES中定义的“hibernate.connection.pool_size”属性键,到该 Properties 类 中的键就成了“pool_size ”。connectionProps主要是为后面的getConnection()方法而提供的。   

  接下来是getConnection()方法,在这里我们发现了synchronized 关键字,这个关键字是加在pool这个对象上的,也就是说某个时刻只有其中的一个线程可以访问这个对象的synchronized数据。每个对象都有一 个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被synchronized修饰的数据将被上锁 (因为"锁标志"被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它 线程才有机会访问synchronized数据。pool是什么?它是一个ArrayList,也就是连接池,里面都是一个个的Connection对 象,这个可以在后面的closeConnection(Connection conn)体现出来,正在pool上加synchronized修饰符就保证了多个线程不能并发访问此ArrayList而生成不正确的结果。当调用 getConnection()方法时,我们可以看到连接池就移除了一个连接。

  Connection conn = DriverManager.getConnection(url, connectionProps)语句中我们可以看到全局变量connectionProps是传入到了这个方法中的,返回了一个Connection 对象。   

   closeConnection(Connection conn)方法是将连接重新放回到连接池。   

  close()方法清空了连接池,关闭所有连接。   

  supportsAggressiveRelease()方法返回的是false,表示连 接释放模式会被设置为hibernate.connection.release_mode.AFTER_TRANSACTION也就是说在 org.hibernate.Transaction结束后释放连接。

DatasourceConnectionProvider类分析    DatasourceConnectionProvider类比较简单,不同的是,它通过JNDI的方式来查找数据源来获得连接,这个类中要注意的方法是 supportsAggressiveRelease()它返回的是true,表示在使用数据源连接的情况下,支持使用 hibernate.connection.release_mode.AFTER_STATEMENT这一个设置。

UserSuppliedConnectionProvider类分析    UserSuppliedConnectionProvider 这个类是留给用户自己扩展的,基本上什么都不干。