JDBC总结,DAO创建


总结JDBC相关东西和思路,用以回头查看。


—————————————分割线———————————————

一、最原始的连接数据库方式

首先来看一段最原始的连接数据库的方法:不实用JDBC,直接使用Oracle的java驱动去连接。

package com.lj95801.cla1;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;

import org.junit.Test;

public class testConnection_1 {
	
	@Test
	public void test1() throws SQLException{
		//1. 创建一个 Driver 实现类的对象(Oracle实现)
		Driver driver = new oracle.jdbc.driver.OracleDriver();
		
		//2. 准备连接数据库的基本信息: url, user, password
		String url = "jdbc:oracle:thin:@localhost:1521:orcl";
		Properties info = new Properties();
		info.put("user", "SCOTT");
		info.put("password", "tiger");
		
		//3. 调用 Driver 接口的 connect(url, info) 获取数据库连接
		Connection connection = driver.connect(url, info);
		
		System.out.println(connection);
	}
}

 
 

 
我们可以总结出: 

要操作数据库,首先必须要得到数据库的连接Connection类的一个引用,否则什么事情都干不了。

怎么得到这个Connection引用呢?

每个数据库(Oracle,MySQL等)都会实现Java的一个接口:Driver,而在这个接口的实现类中都会提供一个connect方法。通过 "driver.connect(...)" 的方式就能够得到这个数据库的连接。

想要连接数据库至少要向connect方法中传入三样东西:url(数据库在什么位置)、user(用户名)、password(密码)。

所以,上面的代码就很明了了。

2、我需要通用性

现在的状况是这样的:

①我可能会将数据库由MySQL升级到Oracle,那么我就要修改Driver驱动;

②我的密码可能要不定时的修改,那么我就要修改password;

③我的数据库可能要放在其他的服务器上面去,那么我就要修改url。

困难的是,这些信息可能散布在工程文件的各个部分。因此,修改及其困难。所以,将上面的代码修改成以下的方式:

package com.lj95801.cla1;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;

import org.junit.Test;

public class testConnection_1 {
		
	/**
	 * 编写一个通用的方法, 在不修改源程序的情况下, 可以获取任何数据库的连接
	 * 解决方案: 把数据库驱动 Driver 实现类的全类名、url、user、password 放入一个
	 * 配置文件中, 通过修改配置文件的方式实现和具体的数据库解耦. 
	 * @throws Exception 
	 */
	public Connection getConnection() throws Exception{
		String driverClass = null;
		String jdbcUrl = null;
		String user = null;
		String password = null;
		
		//1、读取类路径下的 jdbc.properties 文件,获得具体driver实现类和三样东西。
		InputStream in = 
				this.getClass().getClassLoader().getResourceAsStream("jdbc.properties");
		Properties properties = new Properties();
		properties.load(in);
		driverClass = properties.getProperty("driver");
		jdbcUrl = properties.getProperty("jdbcUrl");
		user = properties.getProperty("user");
		password = properties.getProperty("password");
		
		//2、通过反射创建Driver 对象. 
		Driver driver = 
				(Driver) Class.forName(driverClass).newInstance();

		Properties info = new Properties();
		info.put("user", user);
		info.put("password", password);

		//3、通过 Driver 的 connect 方法获取数据库连接. 
		Connection connection = driver.connect(jdbcUrl, info);
		
		in.close();

		return connection;
	}
	
	@Test
	public void test2() throws Exception{
		
		Connection connect = getConnection();
		
		System.out.println(connect);
	}
}

 

jdbc.properties的内容如下:

driver=oracle.jdbc.driver.OracleDriver
jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl
user=scott
password=tiger
 

这样做的好处就是:getConnection函数不和任何具体的数据库驱动耦合。我只是在jdbc.properties文件中读取必要的信息,然后进行连接得到connection。并且,所有的连接都读取这个文件中的内容。所以,无论你是要升级数据库也好,还是要修改用户和密码都只需要在jdbc.properties文件中集中修改。

这样代码就具有了一定的通用性。

下面先按照使用的逻辑先介绍一些常用和重要的接口和方法。实际上,使用JDBC就是使用下面这些相关的接口。因为这是java定义的接口标准,所以想要支持java操作的数据库都要实现这些必要的接口。我们编程的时候用接口标准的方法来操作,那么代码就具有了可移植性。

Connection接口中有以下常用的方法:

/*最终的SQL查询要归结到Statement或PreparedStatement上面来*/
Statement createStatement();
/*比上面这个要常用*/
PreparedStatement prepareStatement(String sql);
			 
void close();
boolean isClosed(); 
			 
/*和事物相关的,主要是有三个*/
void setAutoCommit(boolean autoCommit); //设置为false,取消自动提交
void commit(); 		//事物都处理完了,没有异常,则提交
void rollback(); 	//事物处理途中出现了异常,则要回滚到初始状态,通常放在catch语句中
/*以下两个参考使用*/
void rollback(Savepoint savepoint);
Savepoint setSavepoint();

 
 
 

PreparedStatement接口中的常用方法有:

</pre><pre name="code" class="java">void setObject(int parameterIndex, Object x);	//给sql语句的占位符填充内容 
/*执行查询或者是更新的命令*/ 
ResultSet executeQuery(); //执行查询,需要返回查询结果
int executeUpdate();	  //执行和更新相关的SQL语句,如:INSERT, UPDATE or DELETE
		
void setBlob(int parameterIndex, Blob x);	//比如说在数据库中插入图片 
		 
/*积累sql语句,当达到多少条以后一次性发送给数据库执行,可以提高效率*/
void addBatch();
int[] executeBatch(); 
 
 

ResultSet接口的实现类存放查询返回的结果,其中有如下常用的方法:

</pre><pre name="code" class="java">/*得到游标指示当前行的 列索引或者是列名 的值*/
Object getObject(String columnLabel); 
Object getObject(int columnIndex); 
		
/*ResultSetMetaData中存放了和返回结果的列相关的信息,比如列数目,列名等*/
ResultSetMetaData getMetaData(); 
 
/*移动游标相关的操作,最初状态是:指针指向结果第一行的前面,相当于beforefirst*/
boolean next();		//游标向后移动一个位置,如果移动以后指示的一行是有数据的就返回true,如果没有返回false 
boolean first();	//将游标移动到第一行,如果有数据返回true,没有但会false
void beforeFirst()  //将游标移动到第一行前面的位置,相当于初始状态
 
 

ResultSetMetaData接口中定义了如下的一些常用方法:

</pre><pre name="code" class="java">int getColumnCount();  //获取总的列数 
String getColumnLabel(int column);  //获取列索引值的别名(SQL语句中可以起别名) 
String getColumnName(int column)    //获取列索引值的本名

 
——————————  准备工作  —————————————— 

到目前为止,我们可以获得数据库的连接了。下面介绍如何利用这个连接来执行增、删、改、查的操作。首先看一看数据库表单customers的设计:

再看一看Student类,后面所有的实例都使用这个类:

</pre><pre name="code" class="java">package com.lj95801.cla1;

import java.util.List;
import com.lj95801.utils.JDBCDAO;

public class Student {
	private int id;
	private String name;
	private String email;
	
	public Student() {
		super();
	}

	public Student(int id, String name, String email) {
		super();
		this.id = id;
		this.name = name;
		this.email = email;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", email=" + email
				+ "]";
	}
}

 
下面介绍一个工具:BeanUtils。 

可以用这个类的静态方法很方便的设置其它类的属性值:

<pre name="code" class="java"><pre name="code" class="java">
@Testpublic void testBeanUtils() throws IllegalAccessException, InvocationTargetException{Student student = new Student();BeanUtils.setProperty(student, "id", 1234567); //设置id属性值BeanUtils.setProperty(student, "name", "李雷"); //设置name属性值System.out.println(student);}
 
 

 
执行结果: 

可以看出,其不用调用student的setXxx()方法就能够设置成功。

但是,其有特殊要求:BeanUtils.setProperty(student, "name", "李雷"),实际上它会调用student.setName("李雷")来执行初始化的。所以,Student类必须有对应的set方法,而且setXxx中的Xxx是BeanUtils.setProperty第二个参数首字母大写以后得到的。

也就是说,比如要BeanUtils.setProperty(student, "name", "李雷")能够成功调用,则Student中必须要有setName(String name)方法(注意:set后的第一个字母大写)但是方法中对谁赋值无关紧要。

————————————   具体方法介绍  ——————————

其中的增、删、改操作不涉及到数据的返回和处理,所以可以归结到一起来处理,下面的update方法可以完成:

</pre><pre name="code" class="java">/**
 * 更新。可处理的操作有:更新,删除,插入三种操作。
 * 
 * @param connection
 * @param sql
 * @param objects
 */
public static void update(Connection connection, String sql,
			Object... objects) {

	PreparedStatement preStatement = null;

	try {
		// 1、通过connection得到preStatement,它可以为sql占位符填充内容,防止sql注入
		preStatement = connection.prepareStatement(sql);

		// 2、for循环为sql语句填充占位符
		for (int i = 0; i < objects.length; i++) {
			preStatement.setObject(i + 1, objects[i]);
		}

		// 3、调用executeUpdate()方法执行更新
		preStatement.executeUpdate();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		// 4、释放资源
		release(null, preStatement, null, null);
	}
}

 
 

 
 
如何使用以上的方法呢?看下面的例子: 

<pre name="code" class="java"><pre name="code" class="java">
package com.lj95801.cla1;import java.sql.Connection;import org.junit.Test;import com.lj95801.utils.JDBCDAO;import com.lj95801.utils.JDBCTools;public class TestJDBCDAO {@Testpublic void testUpdate() throws Exception{String sql = null;//获得connectionConnection connection = JDBCTools.getConnection("jdbc.properties");//1、插入操作的sql语句。含有三个占位符,也就是三个问号。sql = "INSERT INTO customers(ste_id, name, email) VALUES(?, ?, ?)";JDBCDAO.update(connection, sql, 7, "李雷", "lilei@126.com");//2、执行删除操作sql = "DELETE FROM customers WHERE ste_id = ?";JDBCDAO.update(connection, sql, 5);//3、执行更新操作sql = "UPDATE customers SET email = ? WHERE ste_id = ?";JDBCDAO.update(connection, sql, "123456789@110.com",5);}}
 

再看查询操作,查询操作涉及到返回结果。所以较为复杂。

首先介绍查询的返回结果ResultSet:它的结构和数据库查询是一样的。如果返回一条记录,则只有一行;如果查询返回多行记录,则就有多行。而列数则和查询语句是一致的。如下:

如果执行resultSet.next()一次,则游标向下移动一行,指向"露西"。如果再执行一次,游标又向下移动一行。而列数,我的select语句中只查询了id, name, email,那么结果中就只有三列。

下面看看返回一行的函数:

<pre name="code" class="java"><pre name="code" class="java">
/** * 查询,并返回一条记录。具有通用性,能够将表的结果和一个类的属性对应起来。 * 从而,可以将数据库的查询结果和类的方法结合起来,使得数据具有了具体的意义。 * 但是,该方法只会返回一条记录,即便sql查询返回的是多条记录也只返回第一条。 * @param clazz * @param connection * @param sql * @param objects * @return 查询结果的映射类的实例。 */public static <T> T get(Class<T> clazz, Connection connection, String sql, Object ...objects){PreparedStatement preStatement = null;ResultSet resultSet = null;ResultSetMetaData rsmd = null;//1、创建泛型类的对象,将作为结果返回。无论有没有都不要返回null,而应该返回空实例。T classObj = null;try {//2、利用反射创建类的实例classObj = clazz.newInstance();//3、得到preStatement实例preStatement = connection.prepareStatement(sql);//4、填充sql占位符for(int i = 0; i < objects.length; i++){preStatement.setObject(i + 1, objects[i]);}//5、执行sql语句,其返回结果为resulSetresultSet = preStatement.executeQuery();//6、处理返回结果,将其映射为一个类的实例。这样,数据库中查询出来的数据就具有了具体的含义。if(resultSet.next()){//如果有数据,则进行下面的处理,否则直接返回了String key = null; Object value = null;//7、ResultSetMetaData很好,能够知道ResultSet的列名,列的数目等等。rsmd = resultSet.getMetaData();//8、得到列数int columnCount = rsmd.getColumnCount();//9、将返回结果的每一列和类的一个属性对应,将其赋值给类的属性for(int i = 0; i < columnCount; i++){//获取列名key = rsmd.getColumnLabel(i + 1);//利用列名来查询对应的结果value = resultSet.getObject(key);//10、使用BeanUtils工具,处理getter和setter是很好的。有特定要求BeanUtils.setProperty(classObj, key, value);}}} catch (Exception e) {e.printStackTrace();}finally{//11、关闭资源JDBCTools.releseJDBC(resultSet, null, null, preStatement);}return classObj;}
 

看看具体的使用方法:

<pre name="code" class="java"><pre name="code" class="java">
package com.lj95801.cla1;import java.sql.Connection;import org.junit.Test;import com.lj95801.utils.JDBCDAO;import com.lj95801.utils.JDBCTools;public class TestJDBCDAO {@Testpublic void testGet() throws Exception{String sql = null;Connection connection = JDBCTools.getConnection("jdbc.properties");//就是通过别名将类的属性和查询数据的各个列联系起来的。别名是有特殊要求的。sql = "SELECT ste_id \"id\",name \"name\",email \"email\" " + "FROM customers WHERE ste_id = ?";Student student = JDBCDAO.get(Student.class, connection, sql, 13);System.out.println(student);}}
 
执行结果: 

如果查询结果返回多个行呢?处理方法是:建立一个list,将每一行映射为一个类的实例,同时将这些类的实例都放到list中。当然,你完全可以将其放到map中。

<pre name="code" class="java"><pre name="code" class="java">
/** * 查询一组结果。比如说id>7的所有记录。将其保存为对应类型的list * @param clazz * @param connection * @param sql * @param objects * @return */public static <T> List<T> getForList(Class<T> clazz, Connection connection,String sql, Object... objects) {PreparedStatement preStatement = null;ResultSet resultSet = null;ResultSetMetaData rsmd = null;// 1、建立一个空的list,即便查询结果为空,我们也返回一个空的list,而返回null。好处很多。List<T> list = new ArrayList<T>();try {preStatement = connection.prepareStatement(sql);for (int i = 0; i < objects.length; i++) {preStatement.setObject(i + 1, objects[i]);}// 2、执行查询,结果存放在resultSet中resultSet = preStatement.executeQuery();// 3、遍历结果集if (resultSet.next()) {// 4、得到元数据rsmd = resultSet.getMetaData();// 5、获取列数int columnCount = rsmd.getColumnCount();do {//6、必须每一次遍历都要新建一个实例。因为list.add方法不是复制内容,而是添加引用地址。T classObj = clazz.newInstance();for (int i = 0; i < columnCount; i++) {String columnName = rsmd.getColumnLabel(i + 1);Object columnValue = resultSet.getObject(columnName);//7、完成数据到类的映射关系BeanUtils.setProperty(classObj, columnName, columnValue);}/* * 注意,这个list.add()这个方法不是将classObj的内容拷贝一份,而是将classObj的 * 地址添加到list中。从而,如果add以后,我再将classObj的内容改变了,那么list中对应 * 的内容也改变了。 */list.add(classObj);// 如果在下面修改classObj中id的内容,那么,list中对应的内容也将改变。// BeanUtils.setProperty(classObj, "id", 123456789);} while (resultSet.next());}} catch (Exception e) {e.printStackTrace();} finally {JDBCTools.releseJDBC(resultSet, null, null, preStatement);}return list;}
 
执行结果: 

如果查询结果是一个值呢?比如说查询ste_id=9对应的name值,或者是email的值。看下面代码:

<pre name="code" class="java"><pre name="code" class="java">
/** * 查询结果返回一个值的时候,使用这个函数。 * @param connection * @param sql * @param objects * @return */public static <E> E getForValue(Connection connection, String sql, Object... objects) {PreparedStatement prepStatement = null;ResultSet resultSet = null;//1、用反射创建泛型类的实例E returnValue = null; //有待完善,这条语句没有完成泛型类引用的创建try {prepStatement = connection.prepareStatement(sql);for (int i = 0; i < objects.length; i++) {prepStatement.setObject(i + 1, objects[i]);}resultSet = prepStatement.executeQuery();//2、如果查询有返回结果if (resultSet.next()) {//3、将第一个结果赋值给E的引用,即便查询返回结果有多条,也值处理第一个。returnValue = (E) resultSet.getObject(1);}} catch (Exception e) {e.printStackTrace();}finally{JDBCTools.releseJDBC(resultSet, null, null, prepStatement);}return returnValue;}
 
 

现在为止,我们可以将代码综合一下,做一个JDBC工具类,代码如下:

package com.lj95801.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.beanutils.BeanUtils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	
	/*使用C3P0来创建和管理数据库连接池*/
	private static ComboPooledDataSource cpds = null;
		
	/**
	 * 利用C3P0获取数据库连接
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException {
		if(cpds == null){
			cpds = new ComboPooledDataSource("HelloC3P0");
		}
		return cpds.getConnection();
	}
	
	/**
	 * 编写一个通用的方法, 在不修改源程序的情况下, 可以获取任何数据库的连接
	 * 解决方案: 把数据库驱动 Driver 实现类的全类名、url、user、password 放入一个
	 * 配置文件中, 通过修改配置文件的方式实现和具体的数据库解耦. 
	 * @param propertiesFile: 数据库的配置文件
	 * @return connection 数据库链接
	 */
	public Connection getConnection(String propertiesFile){
		//1、读取类路径下的 jdbc.properties 文件,获得具体driver实现类和三样东西。
		InputStream in = null;
		//3、通过 Driver 的 connect 方法获取数据库连接. 
		Connection connection = null;
		try {
			String driverClass = null;
			String jdbcUrl = null;
			String user = null;
			String password = null;
			
			in = this.getClass().getClassLoader().getResourceAsStream(propertiesFile);
			Properties properties = new Properties();
			properties.load(in);
			driverClass = properties.getProperty("driver");
			jdbcUrl = properties.getProperty("jdbcUrl");
			user = properties.getProperty("user");
			password = properties.getProperty("password");
			
			//2、通过反射创建Driver 对象. 
			Driver driver = 
					(Driver) Class.forName(driverClass).newInstance();

			Properties info = new Properties();
			info.put("user", user);
			info.put("password", password);
			//3、得到数据库链接
			connection = driver.connect(jdbcUrl, info);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return connection;
	}
	
	/**
	 * 更新。可处理的操作有:更新,删除,插入三种操作。
	 * 
	 * @param connection
	 * @param sql
	 * @param objects
	 */
	public static void update(Connection connection, String sql,
			Object... objects) {

		PreparedStatement preStatement = null;

		try {
			// 1、通过connection得到preStatement,它可以为sql占位符填充内容,防止sql注入
			preStatement = connection.prepareStatement(sql);

			// 2、for循环为sql语句填充占位符
			for (int i = 0; i < objects.length; i++) {
				preStatement.setObject(i + 1, objects[i]);
			}

			// 3、调用executeUpdate()方法执行更新
			preStatement.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 4、释放资源
			release(null, preStatement, null, null);
		}
	}
	
	
	/**
	 * 查询,并返回一条记录。具有通用性,能够将表的结果和一个类的属性对应起来。
	 * 从而,可以将数据库的查询结果和类的方法结合起来,使得数据具有了具体的意义。
	 * 但是,该方法只会返回一条记录,即便sql查询返回的是多条记录也只返回第一条。
	 * 
	 * @param clazz
	 * @param connection
	 * @param sql
	 * @param objects
	 * @return 查询结果的映射类的实例。
	 */
	public static <T> T get(Class<T> clazz, Connection connection, String sql,
			Object... objects) {
		PreparedStatement preStatement = null;
		ResultSet resultSet = null;
		ResultSetMetaData rsmd = null;

		// 1、创建泛型类的对象,将作为结果返回。无论有没有都不要返回null,而应该返回空实例。
		T classObj = null;

		try {
			// 2、利用反射创建类的实例
			classObj = clazz.newInstance();

			// 3、得到preStatement实例
			preStatement = connection.prepareStatement(sql);

			// 4、填充sql占位符
			for (int i = 0; i < objects.length; i++) {
				preStatement.setObject(i + 1, objects[i]);
			}

			// 5、执行sql语句,其返回结果为resulSet
			resultSet = preStatement.executeQuery();

			// 6、处理返回结果,将其映射为一个类的实例。这样,数据库中查询出来的数据就具有了具体的含义。
			if (resultSet.next()) {// 如果有数据,则进行下面的处理,否则直接返回了
				String key = null;
				Object value = null;

				// 7、ResultSetMetaData很好,能够知道ResultSet的列名,列的数目等等。
				rsmd = resultSet.getMetaData();

				// 8、得到列数
				int columnCount = rsmd.getColumnCount();

				// 9、将返回结果的每一列和类的一个属性对应,将其赋值给类的属性
				for (int i = 0; i < columnCount; i++) {
					// 获取列名
					key = rsmd.getColumnLabel(i + 1);
					// 利用列名来查询对应的结果
					value = resultSet.getObject(key);
					// 10、使用BeanUtils工具,处理getter和setter是很好的。有特定要求
					BeanUtils.setProperty(classObj, key, value);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 11、关闭资源
			release(resultSet, preStatement, null, null);
		}
		return classObj;
	}
	
	
	
	/**
	 * 查询一组结果。比如说id>7的所有记录。将其保存为对应类型的list
	 * @param clazz
	 * @param connection
	 * @param sql
	 * @param objects
	 * @return
	 */
	public static <T> List<T> getForList(Class<T> clazz, Connection connection,
			String sql, Object... objects) {
		PreparedStatement preStatement = null;
		ResultSet resultSet = null;
		ResultSetMetaData rsmd = null;

		// 1、建立一个空的list,即便查询结果为空,我们也返回一个空的list,而返回null。好处很多。
		List<T> list = new ArrayList<T>();

		try {
			preStatement = connection.prepareStatement(sql);
			for (int i = 0; i < objects.length; i++) {
				preStatement.setObject(i + 1, objects[i]);
			}
			// 2、执行查询,结果存放在resultSet中
			resultSet = preStatement.executeQuery();

			// 3、遍历结果集
			if (resultSet.next()) {
				// 4、得到元数据
				rsmd = resultSet.getMetaData();
				// 5、获取列数
				int columnCount = rsmd.getColumnCount();
				do {
					//6、必须每一次遍历都要新建一个实例。因为list.add方法不是复制内容,而是添加引用地址。
					T classObj = clazz.newInstance();
					for (int i = 0; i < columnCount; i++) {
						String columnName = rsmd.getColumnLabel(i + 1);
						Object columnValue = resultSet.getObject(columnName);
						//7、完成数据到类的映射关系
						BeanUtils.setProperty(classObj, columnName, columnValue);
					}
					/*
					 * 注意,这个list.add()这个方法不是将classObj的内容拷贝一份,而是将classObj的
					 * 地址添加到list中。从而,如果add以后,我再将classObj的内容改变了,那么list中对应
					 * 的内容也改变了。
					 */
					list.add(classObj);
					// 如果在下面修改classObj中id的内容,那么,list中对应的内容也将改变。
					// BeanUtils.setProperty(classObj, "id", 123456789);
				} while (resultSet.next());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			release(resultSet, preStatement, null, null);
		}
		return list;
	}

	
	/**
	 * 查询结果返回一个值的时候,使用这个函数。
	 * @param connection
	 * @param sql
	 * @param objects
	 * @return
	 */
	public static <E> E getForValue(Connection connection, String sql, Object... objects) {
		
		PreparedStatement prepStatement = null;
		ResultSet resultSet = null;
		
		//1、用反射创建泛型类的实例
		E returnValue = null;	//有待完善,这条语句没有完成泛型类引用的创建

		try {
			prepStatement = connection.prepareStatement(sql);
			for (int i = 0; i < objects.length; i++) {
				prepStatement.setObject(i + 1, objects[i]);
			}
			resultSet = prepStatement.executeQuery();
			//2、如果查询有返回结果
			if (resultSet.next()) {
				//3、将第一个结果赋值给E的引用,即便查询返回结果有多条,也值处理第一个。
				returnValue = (E) resultSet.getObject(1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			release(resultSet, prepStatement, null, null);
		}
		return returnValue;
	}
	
	/**
	 * 关闭资源。保证每个资源都能够完成关闭。
	 * @param resultSet
	 * @param preStatement
	 * @param statement
	 * @param connection
	 */
	public static void release(ResultSet resultSet, PreparedStatement preStatement, 
			Statement statement, Connection connection){
		try {
			try {
				if(resultSet != null){
					resultSet.close();
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				if(preStatement != null){
					preStatement.close();
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(statement != null){
					statement.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				if(connection != null){
					try {
						connection.close();
					} catch (SQLException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}	
}

C3P0配置文件如下(文件名为:c3p0-config.xml):

<c3p0-config>
	<!-- This app is massive! -->
	<named-config name="HelloC3P0">
	
		<!-- 指定连接数据源的基本属性 -->
		<property name="user">scott</property>
		<property name="password">tiger</property>
		<property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
		<property name="jdbcUrl">jdbc:oracle:thin:@localhost:1521:orcl</property>
		
		<!-- 若数据库连接池不足时,一次向数据库申请多少个连接 -->
		<property name="acquireIncrement">5</property>
		<!-- 初始化数据库连接池时连接的数量 -->
		<property name="initialPoolSize">5</property>
		<property name="minPoolSize">5</property>
		<property name="maxPoolSize">1000</property>

		<!-- C3P0数据库连接池可以维护的Statement的个数 -->
		<property name="maxStatements">0</property>
		<!-- 每个连接同时可以使用的Statement个数 -->
		<property name="maxStatementsPerConnection">5</property>

	</named-config>
</c3p0-config>







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值