用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。如下图所示:
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。如下图所示:
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中.
数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
实现DataSource接口,并实现连接池功能的步骤:
数据库连接池核心代码
使用动态代理技术构建连接池中的connection
1 proxyConn = (Connection) Proxy.newProxyInstance(this.getClass() 2 .getClassLoader(), conn.getClass().getInterfaces(), 3 new InvocationHandler() { 4 //此处为内部类,当close方法被调用时将conn还回池中,其它方法直接执行 5 public Object invoke(Object proxy, Method method, 6 Object[] args) throws Throwable { 7 if (method.getName().equals("close")) { 8 pool.addLast(conn); 9 return null;10 }11 return method.invoke(conn, args);12 }13 });
数据库连接池编写范例:
1 package me.gacl.demo; 2 3 import java.io.InputStream; 4 import java.io.PrintWriter; 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 import java.sql.Connection; 9 import java.sql.DriverManager; 10 import java.sql.SQLException; 11 import java.util.LinkedList; 12 import java.util.Properties; 13 import javax.sql.DataSource; 14 15 /** 16 * @ClassName: JdbcPool 17 * @Description:编写数据库连接池 18 * @author 19 * @date 20 * 21 */ 22 public class JdbcPool implements DataSource{ 23 24 /** 25 * @Field: listConnections 26 * 使用LinkedList集合来存放数据库链接, 27 * 由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适 28 */ 29 private static LinkedList<Connection> listConnections = new LinkedList<Connection>(); 30 31 static{ 32 //在静态代码块中加载db.properties数据库配置文件 33 InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties"); 34 Properties prop = new Properties(); 35 try { 36 prop.load(in); 37 String driver = prop.getProperty("driver"); 38 String url = prop.getProperty("url"); 39 String username = prop.getProperty("username"); 40 String password = prop.getProperty("password"); 41 //数据库连接池的初始化连接数大小 42 int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize")); 43 //加载数据库驱动 44 Class.forName(driver); 45 for (int i = 0; i < jdbcPoolInitSize; i++) { 46 Connection conn = DriverManager.getConnection(url, username, password); 47 System.out.println("获取到了链接" + conn); 48 //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池 49 listConnections.add(conn); 50 } 51 52 } catch (Exception e) { 53 throw new ExceptionInInitializerError(e); 54 } 55 } 56 57 @Override 58 public PrintWriter getLogWriter() throws SQLException { 59 // TODO Auto-generated method stub 60 return null; 61 } 62 63 @Override 64 public void setLogWriter(PrintWriter out) throws SQLException { 65 // TODO Auto-generated method stub 66 67 } 68 69 @Override 70 public void setLoginTimeout(int seconds) throws SQLException { 71 // TODO Auto-generated method stub 72 73 } 74 75 @Override 76 public int getLoginTimeout() throws SQLException { 77 // TODO Auto-generated method stub 78 return 0; 79 } 80 81 @Override 82 public <T> T unwrap(Class<T> iface) throws SQLException { 83 // TODO Auto-generated method stub 84 return null; 85 } 86 87 @Override 88 public boolean isWrapperFor(Class<?> iface) throws SQLException { 89 // TODO Auto-generated method stub 90 return false; 91 } 92 93 /* 获取数据库连接 94 * @see javax.sql.DataSource#getConnection() 95 */ 96 @Override 97 public Connection getConnection() throws SQLException { 98 //如果数据库连接池中的连接对象的个数大于0 99 if (listConnections.size()>0) {100 //从listConnections集合中获取一个数据库连接101 final Connection conn = listConnections.removeFirst();102 System.out.println("listConnections数据库连接池大小是" + listConnections.size());103 //返回Connection对象的代理对象104 return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){105 @Override106 public Object invoke(Object proxy, Method method, Object[] args)107 throws Throwable {108 if(!method.getName().equals("close")){109 return method.invoke(conn, args);110 }else{111 //如果调用的是Connection对象的close方法,就把conn还给数据库连接池112 listConnections.add(conn);113 System.out.println(conn + "被还给listConnections数据库连接池了!!");114 System.out.println("listConnections数据库连接池大小为" + listConnections.size());115 return null;116 }117 }118 });119 }else {120 throw new RuntimeException("对不起,数据库忙");121 }122 }123 124 @Override125 public Connection getConnection(String username, String password)126 throws SQLException {127 return null;128 }129 }
db.properties配置文件如下:
1 driver=com.mysql.jdbc.Driver2 url=jdbc:mysql://localhost:3306/jdbcStudy3 username=root4 password=XDP5 6 jdbcPoolInitSize=10
写一个JdbcUtil测试数据库连接池
1 package me.gacl.utils; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import me.gacl.demo.JdbcPool; 8 9 public class JdbcUtil {10 11 /**12 * @Field: pool13 * 数据库连接池14 */ 15 private static JdbcPool pool = new JdbcPool();16 17 /**18 * @Method: getConnection19 * @Description: 从数据库连接池中获取数据库连接对象20 * @Anthor21 * @return Connection数据库连接对象22 * @throws SQLException23 */ 24 public static Connection getConnection() throws SQLException{25 return pool.getConnection();26 }27 28 /**29 * @Method: release30 * @Description: 释放资源,31 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象32 * @Anthor33 *34 * @param conn35 * @param st36 * @param rs37 */ 38 public static void release(Connection conn,Statement st,ResultSet rs){39 if(rs!=null){40 try{41 //关闭存储查询结果的ResultSet对象42 rs.close();43 }catch (Exception e) {44 e.printStackTrace();45 }46 rs = null;47 }48 if(st!=null){49 try{50 //关闭负责执行SQL命令的Statement对象51 st.close();52 }catch (Exception e) {53 e.printStackTrace();54 }55 }56 57 if(conn!=null){58 try{59 //关闭Connection数据库连接对象60 conn.close();61 }catch (Exception e) {62 e.printStackTrace();63 }64 }65 }66 }
现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。 也有一些开源组织提供了数据源的独立实现:
在使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了,直接从数据源获得数据库的连接。
DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 文件:
Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
1.导入相关jar包 commons-dbcp-1.2.2.jar、commons-pool.jar 2、在类目录下加入dbcp的配置文件:dbcpconfig.properties
dbcpconfig.properties的配置信息如下:
1 #连接设置 2 driverClassName=com.mysql.jdbc.Driver 3 url=jdbc:mysql://localhost:3306/jdbcstudy 4 username=root 5 password=XDP 6 7 #<!-- 初始化连接 --> 8 initialSize=10 9 10 #最大连接数量11 maxActive=5012 13 #<!-- 最大空闲连接 -->14 maxIdle=2015 16 #<!-- 最小空闲连接 -->17 minIdle=518 19 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->20 maxWait=6000021 22 23 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 24 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。25 connectionProperties=useUnicode=true;characterEncoding=UTF826 27 #指定由连接池所创建的连接的自动提交(auto-commit)状态。28 defaultAutoCommit=true29 30 #driver default 指定由连接池所创建的连接的只读(read-only)状态。31 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)32 defaultReadOnly=33 34 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。35 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE36 defaultTransactionIsolation=READ_UNCOMMITTED
如下图所示:
3、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池
1 package me.gacl.util; 2 3 import java.io.InputStream; 4 import java.sql.Connection; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 import java.util.Properties; 9 import javax.sql.DataSource;10 import org.apache.commons.dbcp.BasicDataSourceFactory;11 12 /**13 * @ClassName: JdbcUtils_DBCP14 * @Description: 数据库连接工具类15 * @author16 * @date17 *18 */ 19 public class JdbcUtils_DBCP {20 /**21 * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现22 * DBCP连接池就是java.sql.DataSource接口的一个具体实现23 */24 private static DataSource ds = null;25 //在静态代码块中创建数据库连接池26 static{27 try{28 //加载dbcpconfig.properties配置文件29 InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");30 Properties prop = new Properties();31 prop.load(in);32 //创建数据源33 ds = BasicDataSourceFactory.createDataSource(prop);34 }catch (Exception e) {35 throw new ExceptionInInitializerError(e);36 }37 }38 39 /**40 * @Method: getConnection41 * @Description: 从数据源中获取数据库连接42 * @Anthor43 * @return Connection44 * @throws SQLException45 */ 46 public static Connection getConnection() throws SQLException{47 //从数据源中获取数据库连接48 return ds.getConnection();49 }50 51 /**52 * @Method: release53 * @Description: 释放资源,54 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象55 * @Anthor56 *57 * @param conn58 * @param st59 * @param rs60 */ 61 public static void release(Connection conn,Statement st,ResultSet rs){62 if(rs!=null){63 try{64 //关闭存储查询结果的ResultSet对象65 rs.close();66 }catch (Exception e) {67 e.printStackTrace();68 }69 rs = null;70 }71 if(st!=null){72 try{73 //关闭负责执行SQL命令的Statement对象74 st.close();75 }catch (Exception e) {76 e.printStackTrace();77 }78 }79 80 if(conn!=null){81 try{82 //将Connection连接对象还给数据库连接池83 conn.close();84 }catch (Exception e) {85 e.printStackTrace();86 }87 }88 }89 }
测试DBCP数据源
1 package me.gacl.test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import org.junit.Test; 7 import me.gacl.util.JdbcUtils_DBCP; 8 9 public class DataSourceTest {10 11 @Test12 public void dbcpDataSourceTest() {13 Connection conn = null;14 PreparedStatement st = null;15 ResultSet rs = null;16 try{17 //获取数据库连接18 conn = JdbcUtils_DBCP.getConnection();19 String sql = "insert into test1(name) values(?)";20 st = conn.prepareStatement(sql);21 st.setString(1, "gacl");22 st.executeUpdate();23 //获取数据库自动生成的主键24 rs = st.getGeneratedKeys();25 if(rs.next()){26 System.out.println(rs.getInt(1));27 }28 }catch (Exception e) {29 e.printStackTrace();30 }finally{31 //释放资源32 JdbcUtils_DBCP.release(conn, st, rs);33 }34 }35 }
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。
c3p0与dbcp区别
1.导入相关jar包 c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-0.9.2-pre1.jar 2、在类目录下加入C3P0的配置文件:c3p0-config.xml
c3p0-config.xml的配置信息如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 3 c3p0-config.xml必须位于类路径下面 4 private static ComboPooledDataSource ds; 5 static{ 6 try { 7 ds = new ComboPooledDataSource("MySQL"); 8 } catch (Exception e) { 9 throw new ExceptionInInitializerError(e);10 }11 }12 -->13 14 <c3p0-config>15 <!--16 C3P0的缺省(默认)配置,17 如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源18 -->19 <default-config>20 <property name="driverClass">com.mysql.jdbc.Driver</property>21 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>22 <property name="user">root</property>23 <property name="password">XDP</property>24 25 <property name="acquireIncrement">5</property>26 <property name="initialPoolSize">10</property>27 <property name="minPoolSize">5</property>28 <property name="maxPoolSize">20</property>29 </default-config>30 31 <!--32 C3P0的命名配置,33 如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”这样写就表示使用的是name是MySQL的配置信息来创建数据源34 -->35 <named-config name="MySQL">36 <property name="driverClass">com.mysql.jdbc.Driver</property>37 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy</property>38 <property name="user">root</property>39 <property name="password">XDP</property>40 41 <property name="acquireIncrement">5</property>42 <property name="initialPoolSize">10</property>43 <property name="minPoolSize">5</property>44 <property name="maxPoolSize">20</property>45 </named-config>46 47 </c3p0-config>
如下图所示:
3、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池
1 package me.gacl.util; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import com.mchange.v2.c3p0.ComboPooledDataSource; 8 9 /**10 * @ClassName: JdbcUtils_C3P011 * @Description: 数据库连接工具类12 * @author13 * @date14 *15 */ 16 public class JdbcUtils_C3P0 {17 18 private static ComboPooledDataSource ds = null;19 //在静态代码块中创建数据库连接池20 static{21 try{22 //通过代码创建C3P0数据库连接池23 /*ds = new ComboPooledDataSource();24 ds.setDriverClass("com.mysql.jdbc.Driver");25 ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy");26 ds.setUser("root");27 ds.setPassword("XDP");28 ds.setInitialPoolSize(10);29 ds.setMinPoolSize(5);30 ds.setMaxPoolSize(20);*/31 32 //通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下33 //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源34 ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源35 36 }catch (Exception e) {37 throw new ExceptionInInitializerError(e);38 }39 }40 41 /**42 * @Method: getConnection43 * @Description: 从数据源中获取数据库连接44 * @Anthor45 * @return Connection46 * @throws SQLException47 */ 48 public static Connection getConnection() throws SQLException{49 //从数据源中获取数据库连接50 return ds.getConnection();51 }52 53 /**54 * @Method: release55 * @Description: 释放资源,56 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象57 * @Anthor58 *59 * @param conn60 * @param st61 * @param rs62 */ 63 public static void release(Connection conn,Statement st,ResultSet rs){64 if(rs!=null){65 try{66 //关闭存储查询结果的ResultSet对象67 rs.close();68 }catch (Exception e) {69 e.printStackTrace();70 }71 rs = null;72 }73 if(st!=null){74 try{75 //关闭负责执行SQL命令的Statement对象76 st.close();77 }catch (Exception e) {78 e.printStackTrace();79 }80 }81 82 if(conn!=null){83 try{84 //将Connection连接对象还给数据库连接池85 conn.close();86 }catch (Exception e) {87 e.printStackTrace();88 }89 }90 }91 }
测试C3P0数据源
1 package me.gacl.test; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import org.junit.Test; 7 import me.gacl.util.JdbcUtils_C3P0; 8 import me.gacl.util.JdbcUtils_DBCP; 9 10 public class DataSourceTest {11 12 @Test13 public void c3p0DataSourceTest() {14 Connection conn = null;15 PreparedStatement st = null;16 ResultSet rs = null;17 try{18 //获取数据库连接19 conn = JdbcUtils_C3P0.getConnection();20 String sql = "insert into test1(name) values(?)";21 st = conn.prepareStatement(sql);22 st.setString(1, "gacl");23 st.executeUpdate();24 //获取数据库自动生成的主键25 rs = st.getGeneratedKeys();26 if(rs.next()){27 System.out.println(rs.getInt(1));28 }29 }catch (Exception e) {30 e.printStackTrace();31 }finally{32 //释放资源33 JdbcUtils_C3P0.release(conn, st, rs);34 }35 }36 }
在实际开发中,我们有时候还会使用服务器提供给我们的数据库连接池,比如我们希望Tomcat服务器在启动的时候可以帮我们创建一个数据库连接池,那么我们在应用程序中就不需要手动去创建数据库连接池,直接使用Tomcat服务器创建好的数据库连接池即可。要想让Tomcat服务器在启动的时候帮我们创建一个数据库连接池,那么需要简单配置一下Tomcat服务器。
JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包, 这 套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需 通过名称检索即可。其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。
Tomcat服务器创建的数据源是以JNDI资源的形式发布的,所以说在Tomat服务器中配置一个数据源实际上就是在配置一个JNDI资源,通过查看Tomcat文档,我们知道使用如下的方式配置tomcat服务器的数据源:
1 <Context>2 <Resource name="jdbc/datasource" auth="Container"3 type="javax.sql.DataSource" username="root" password="XDP"4 driverClassName="com.mysql.jdbc.Driver" 5 url="jdbc:mysql://localhost:3306/jdbcstudy"6 maxActive="8" maxIdle="4"/>7 </Context>
服务器创建好数据源之后,我们的应用程序又该怎么样得到这个数据源呢,Tomcat服务器创建好数据源之后是以JNDI的形式绑定到一个JNDI容器中的,我们可以把JNDI想象成一个大大的容器,我们可以往这个容器中存放一些对象,一些资源,JNDI容器中存放的对象和资源都会有一个独一无二的名称,应用程序想从JNDI容器中获取资源时,只需要告诉JNDI容器要获取的资源的名称,JNDI根据名称去找到对应的资源后返回给应用程序。我们平时做javaEE开发时,服务器会为我们的应用程序创建很多资源,比如request对象,response对象,服务器创建的这些资源有两种方式提供给我们的应用程序使用:第一种是通过方法参数的形式传递进来,比如我们在Servlet中写的doPost和doGet方法中使用到的request对象和response对象就是服务器以参数的形式传递给我们的。第二种就是JNDI的方式,服务器把创建好的资源绑定到JNDI容器中去,应用程序想要使用资源时,就直接从JNDI容器中获取相应的资源即可。
对于上面的name="jdbc/datasource"数据源资源,在应用程序中可以用如下的代码去获取
1 Context initCtx = new InitialContext();2 Context envCtx = (Context) initCtx.lookup("java:comp/env");3 dataSource = (DataSource)envCtx.lookup("jdbc/datasource");
此种配置下,数据库的驱动jar文件需放置在tomcat的lib下
1、在Web项目的WebRoot目录下的META-INF目录创建一个context.xml文件
如下图所示:
2、在context.xml文件配置tomcat服务器的数据源
1 <Context> 2 <Resource 3 name="jdbc/datasource" 4 auth="Container" 5 type="javax.sql.DataSource" 6 username="root" 7 password="XDP" 8 driverClassName="com.mysql.jdbc.Driver" 9 url="jdbc:mysql://localhost:3306/jdbcstudy"10 maxActive="8" 11 maxIdle="4"/>12 </Context>
3、将数据库的驱动jar文件需放置在tomcat的lib下
4、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中获取JNDI容器中的数据源
1 package me.gacl.util; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 import javax.naming.Context; 8 import javax.naming.InitialContext; 9 import javax.sql.DataSource;10 11 /**12 * @ClassName: JdbcUtils_DBCP13 * @Description: 数据库连接工具类14 * @author15 * @date16 *17 */ 18 public class JdbcUtils_JNDI {19 20 private static DataSource ds = null;21 //在静态代码块中创建数据库连接池22 static{23 try{24 //初始化JNDI25 Context initCtx = new InitialContext();26 //得到JNDI容器27 Context envCtx = (Context) initCtx.lookup("java:comp/env");28 //从JNDI容器中检索name为jdbc/datasource的数据源29 ds = (DataSource)envCtx.lookup("jdbc/datasource");30 }catch (Exception e) {31 throw new ExceptionInInitializerError(e);32 }33 }34 35 /**36 * @Method: getConnection37 * @Description: 从数据源中获取数据库连接38 * @Anthor39 * @return Connection40 * @throws SQLException41 */ 42 public static Connection getConnection() throws SQLException{43 //从数据源中获取数据库连接44 return ds.getConnection();45 }46 47 /**48 * @Method: release49 * @Description: 释放资源,50 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象51 * @Anthor52 *53 * @param conn54 * @param st55 * @param rs56 */ 57 public static void release(Connection conn,Statement st,ResultSet rs){58 if(rs!=null){59 try{60 //关闭存储查询结果的ResultSet对象61 rs.close();62 }catch (Exception e) {63 e.printStackTrace();64 }65 rs = null;66 }67 if(st!=null){68 try{69 //关闭负责执行SQL命令的Statement对象70 st.close();71 }catch (Exception e) {72 e.printStackTrace();73 }74 }75 76 if(conn!=null){77 try{78 //将Connection连接对象还给数据库连接池79 conn.close();80 }catch (Exception e) {81 e.printStackTrace();82 }83 }84 }85 }
写一个Servlet测试JNDI数据源
1 package me.gacl.test; 2 3 import java.io.IOException; 4 import java.sql.Connection; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest;10 import javax.servlet.http.HttpServletResponse;11 import me.gacl.util.JdbcUtils_JNDI;12 13 public class JNDITest extends HttpServlet {14 15 public void doGet(HttpServletRequest request, HttpServletResponse response)16 throws ServletException, IOException {17 Connection conn = null;18 PreparedStatement st = null;19 ResultSet rs = null;20 try{21 //获取数据库连接22 conn = JdbcUtils_JNDI.getConnection();23 String sql = "insert into test1(name) values(?)";24 st = conn.prepareStatement(sql);25 st.setString(1, "gacl");26 st.executeUpdate();27 //获取数据库自动生成的主键28 rs = st.getGeneratedKeys();29 if(rs.next()){30 System.out.println(rs.getInt(1));31 }32 }catch (Exception e) {33 e.printStackTrace();34 }finally{35 //释放资源36 JdbcUtils_JNDI.release(conn, st, rs);37 }38 }39 40 public void doPost(HttpServletRequest request, HttpServletResponse response)41 throws ServletException, IOException {42 doGet(request, response);43 }44 45 }