Java中JDBC的資料庫連線池
資料庫連線池
池引數(所有池引數都有預設值):
初始大小:10個
最小空閒連線數:3個
增量:一次建立的最小單位(5個)
最大空閒連線數:12個
最大連線數:20個
最大的等待時間:1000毫秒
四大連線引數
連線池也是使用四大連線引數來完成建立連線物件!
實現的介面
連線池必須實現:javax.sql.DataSource介面!
連線池返回的Connection物件,它的close()方法與眾不同!呼叫它的close()不是關閉,而是把連線歸還給池!代表該連結不被佔用了。
資料庫連線池
連線池的概念
用池來管理Connection,這可以重複使用Connection。有了池,所以我們就不用自己來建立Connection,而是通過池來獲取Connection物件。當使用完Connection後,呼叫Connection的close()方法也不會真的關閉Connection,而是把Connection“歸還”給池。池就可以再利用這個Connection物件了。
JDBC資料庫連線池介面(DataSource)
Java為資料庫連線池提供了公共的介面:javax.sql.DataSource,各個廠商可以讓自己的連線池實現這個介面。這樣應用程式可以方便的切換不同廠商的連線池!
自定義連線池(CloudPool)
分析:CloudPool需要有一個List,用來儲存連線物件。在CloudPool的構造器中建立5個連線物件放到List中!當用人呼叫了CloudPool的getConnection()時,那麼就從List拿出一個返回。當List中沒有連線可用時,丟擲異常。
我們需要對Connection的close()方法進行增強,所以我們需要自定義CloudConnection類,對Connection進行裝飾!即對close()方法進行增強。因為需要在呼叫close()方法時把連線“歸還”給池,所以CloudPool類需要擁有池物件的引用,並且池類還要提供“歸還”的方法。
CloudPool.java
public class CloudPool implements DataSource { private static Properties props = new Properties(); private List<Connection> list = new ArrayList<Connection>(); static { InputStream in = CloudPool.class.getClassLoader() .getResourceAsStream("dbconfig.properties" try { props.load(in); Class.forName(props.getProperty("driverClassName")); } catch (Exception e) { throw new RuntimeException(e); } } public CloudPool () throws SQLException { for (int i = 0; i < 5; i++) { Connection con = DriverManager.getConnection( props.getProperty("url"), props.getProperty("username"), props.getProperty("password")); CloudPool conWapper = new CloudConnection(con, this); list.add(conWapper); } } public void add(Connection con) { list.add(con); } public Connection getConnection() throws SQLException { if(list.size() > 0) { return list.remove(0); } throw new SQLException("沒連線了"); }} |
CloudConnection.java
public class CloudConnection extends ConnectionWrapper { private ItcastPool pool; public CloudConnection(Connection con, CloudPool pool) { super(con); this.pool = pool; } @Override public void close() throws SQLException { pool.add(this); } } |
C3P0連線池
C3P0簡介
C3P0也是開源免費的連線池,現在做的大部分專案都是使用C3P0連線池。
C3P0的使用
C3P0中池類是:ComboPooledDataSource。
public void fun1() throws PropertyVetoException, SQLException { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb1"); ds.setUser("root"); ds.setPassword("123"); ds.setDriverClass("com.mysql.jdbc.Driver"); ds.setAcquireIncrement(5); ds.setInitialPoolSize(20); ds.setMinPoolSize(2); ds.setMaxPoolSize(50); Connection con = ds.getConnection(); System.out.println(con); con.close(); } |
配置檔案要求:
l 檔名稱:必須叫c3p0-config.xml
l 檔案位置:必須在src下
c3p0也可以指定配置檔案,而且配置檔案可以是properties,也可騍xml的。當然xml的高階一些了。但是c3p0的配置檔名必須為c3p0-config.xml,並且必須放在類路徑下。
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="user">root</property> <property name="password">123</property> <property name="acquireIncrement">3</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">2</property> <property name="maxPoolSize">10</property> </default-config> <named-config name="oracle-config"> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="user">root</property> <property name="password">123</property> <property name="acquireIncrement">3</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">2</property> <property name="maxPoolSize">10</property> </named-config> </c3p0-config> |
c3p0的配置檔案中可以配置多個連線資訊,可以給每個配置起個名字,這樣可以方便的通過配置名稱來切換配置資訊。上面檔案中預設配置為mysql的配置,名為oracle-config的配置也是mysql的配置
public void fun2() throws PropertyVetoException, SQLException { ComboPooledDataSource ds = new ComboPooledDataSource(); Connection con = ds.getConnection(); System.out.println(con); con.close(); } |
public void fun2() throws PropertyVetoException, SQLException { ComboPooledDataSource ds = new ComboPooledDataSource("orcale-config"); Connection con = ds.getConnection(); System.out.println(con); con.close(); } |
Tomcat配置連線池
Tomcat配置JNDI資源
JNDI(Java Naming and Directory Interface),Java命名和目錄介面。JNDI的作用就是:在伺服器上配置資源,然後通過統一的方式來獲取配置的資源。
我們這裡要配置的資源當然是連線池了,這樣專案中就可以通過統一的方式來獲取連線池物件了。
下圖是Tomcat文件提供的:
配置JNDI資源需要到<Context>元素中配置<Resource>子元素:
l name:指定資源的名稱,這個名稱可以隨便給,在獲取資源時需要這個名稱;
l factory:用來建立資源的工廠,這個值基本上是固定的,不用修改;
l type:資源的型別,我們要給出的型別當然是我們連線池的型別了;
l bar:表示資源的屬性,如果資源存在名為bar的屬性,那麼就配置bar的值。對於DBCP連線池而言,你需要配置的不是bar,因為它沒有bar這個屬性,而是應該去配置url、username等屬性。
<Context> <Resource name="mydbcp" type="org.apache.tomcat.dbcp.dbcp.BasicDataSource" factory="org.apache.naming.factory.BeanFactory" username="root" password="123" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1/mydb1" maxIdle="3" maxWait="5000" maxActive="5" initialSize="3"/> </Context> |
<Context> <Resource name="myc3p0" type="com.mchange.v2.c3p0.ComboPooledDataSource" factory="org.apache.naming.factory.BeanFactory" user="root" password="123" classDriver="com.mysql.jdbc.Driver" jdbcUrl="jdbc:mysql://127.0.0.1/mydb1" maxPoolSize="20" minPoolSize ="5" initialPoolSize="10" acquireIncrement="2"/> </Context> |
獲取資源
配置資源的目的當然是為了獲取資源了。只要你啟動了Tomcat,那麼就可以在專案中任何類中通過JNDI獲取資源的方式來獲取資源了。
下圖是Tomcat文件提供的,與上面Tomcat文件提供的配置資源是對應的。
獲取資源:
l Context:javax.naming.Context;
l InitialContext:javax.naming.InitialContext;
l lookup(String):獲取資源的方法,其中”java:comp/env”是資源的入口(這是固定的名稱),獲取過來的還是一個Context,這說明需要在獲取到的Context上進一步進行獲取。”bean/MyBeanFactory”對應<Resource>中配置的name值,這回獲取的就是資源物件了。
Context cxt = new InitialContext(); DataSource ds = (DataSource)cxt.lookup("java:/comp/env/mydbcp"); Connection con = ds.getConnection(); System.out.println(con); con.close(); |
Context cxt = new InitialContext(); Context envCxt = (Context)cxt.lookup("java:/comp/env"); DataSource ds = (DataSource)env.lookup("mydbcp"); Connection con = ds.getConnection(); System.out.println(con); con.close(); |
上面兩種方式是相同的效果。
修改JdbcUtils
因為已經學習了連線池,那麼JdbcUtils的獲取連線物件的方法也要修改一下了。
JdbcUtils.java
public class JdbcUtils { private static DataSource dataSource = new ComboPooledDataSource(); public static DataSource getDataSource() { return dataSource; } public static Connection getConnection() { try { return dataSource.getConnection(); } catch (Exception e) { throw new RuntimeException(e); } } } |