jdbc下

1. 数据库事务

数据一旦提交,就不可回滚。

  • 哪些操作会导致数据的自动提交?
  • DDL操作一旦执行都会自动提交(表的创建删除和修改)

  • set autocommit=false的方式对DDL操作失效

  • DML操作一旦执行都会自动提交(数据的增删改)

  •  >我们可以通过set autocommit=false的方式取消DML操作的自动提交
    
  • 默认在关闭连接会进行自动提交

通用的增删改查都需要做哪些更改?

  • 将连接作为参数传入方法
  • 删除原方法内的创建连接的代码
  • 原代码中关闭连接的那个改为null

在哪创建连接在哪关,考虑上事务时,需要在具体的处理代码中

  1. 创建连接
  2. 调用通用增删改查方法
  3. 再关闭连接

jdbcstu.transaction\TransactionTest.java

package jdbcstu1.transaction;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.junit.Test;
import jdbcstu1.util.JDBCUtils;

public class TransactionTest {
	
	/*
	 * 针对于数据表user_table来说,AA用户给BB用户转账100
	 * update user_table set balance=balance-100 where user='AA'
	 * update user_table set balance=balance+100 where user='BB'
	 * 这两句话要么都执行,要么都不执行(事务);出现异常需要回滚
	 * 数据一旦提交,就不可回滚。
	 * 哪些操作会导致数据的自动提交?
	 * 	  >DDL操作一旦执行都会自动提交(表的创建删除和修改)
	 * 	  >set autocommit=false的方式对DDL操作失效
	 * 	  >DML操作一旦执行都会自动提交(数据的增删改)
	 * 		>我们可以通过set autocommit=false的方式取消DML操作的自动提交
	 * 	  >默认在关闭连接会进行自动提交
	 */
	/*******************未考虑数据库事务的一个转账操作************************/
	@Test
	public void testUpdate() {
		String sql1="update user_table set balance=balance-100 where user=?";
		update(sql1,"AA");
		
		//模拟网络异常
		System.out.println(10/0);
		
		String sql2="update user_table set balance=balance+100 where user=?";
		update(sql2,"BB");
		System.out.println("转账成功");
	}
	
	
	//通用的增删改操作(同库不同表)---version 1.0
		public int update(String sql,Object...args)  {
			PreparedStatement ps = null;
			Connection conn = null;
			try {
				//1.获取数据库的连接
				conn = JDBCUtils.getConnection();
				//2.预编译sql语句返回PreparedStatement的实例
				ps = conn.prepareStatement(sql);
				//3.填充占位符
				for(int i=0;i<args.length;i++) {
					ps.setObject(i+1, args[i]);//小心参数声明错误
				}
				//4.执行
				return ps.executeUpdate();
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				//5.资源的关闭
				JDBCUtils.closeResource(conn, ps);
			}
			return 0;
			}
		
	/*****************考虑数据库事务后的转账操作
	 * @throws Exception *********************/
	//通用的增删改操作(同库不同表)---version 2.0
		/*
		 * 从外面传入连接,并在外面关闭连接;而不是在里面造里面关
		 */
		@Test
		public void testUpdateWithTX() {//事务的缩写
			Connection conn = null;
			try {
				conn = JDBCUtils.getConnection();
				//1.取消数据的自动提交功能
				conn.setAutoCommit(false);
				String sql1="update user_table set balance=balance-100 where user=?";
				update(conn,sql1,"AA");
				
				//模拟网络异常
				System.out.println(10/0);
				
				String sql2="update user_table set balance=balance+100 where user=?";
				update(conn,sql2,"BB");
				System.out.println("转账成功");
				
				//2.提交数据
				conn.commit();
			} catch (Exception e) {
				e.printStackTrace();
				//3.当出现异常进入这里,在这里回滚数据
				try {
					conn.rollback();
				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}finally {
				JDBCUtils.closeResource(conn, null);
			}
			
		}
	public int update(Connection conn,String sql,Object...args)  {
		PreparedStatement ps = null;
		try {
			//2.预编译sql语句返回PreparedStatement的实例
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);//小心参数声明错误
			}
			//4.执行
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//5.资源的关闭
			JDBCUtils.closeResource(null, ps);
		}
		return 0;
		}

	//******************************************************
	@Test
	public void testTransactionSelect() throws Exception {
		
			Connection conn = JDBCUtils.getConnection();
			//获取当前连接的隔离级别
			System.out.println(conn.getTransactionIsolation());
			//设置数据库的隔离级别
			conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
			//取消自动提交数据
			conn.setAutoCommit(false);
			String sql="select user,password,balance from user_table where user=? ";
			User user = getInstance(conn,User.class,sql,"CC");
			System.out.println(user);
	}
	@Test
	public void testTransactionUpdate() throws Exception {
		Connection conn = JDBCUtils.getConnection();
		
		//取消自动提交数据
		conn.setAutoCommit(false);
		String sql="update user_table set balance=? where user=?";
		update(conn,sql,5000,"CC");
		
		Thread.sleep(15000);
		System.out.println("修改结束");
	}
	
	
	//返回一个对象的查询,将连接作为参数的查询版本
	//通用的查询操作用于返回数据表中的一条记录(version 2.0 考虑上事务)
	public <T>T getInstance(Connection conn,Class<T> clazz,String sql, Object... args) {// 获取一个对象实例,泛型方法T是对应的运行时类。返回值类型是T,T是一个参数
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}
			rs = ps.executeQuery();
			// 获取结果集的元数据(修饰现有数据的数据)
			ResultSetMetaData rsmd = rs.getMetaData();
			int columnCount = rsmd.getColumnCount();
			if (rs.next()) {
				// 如下述所言这里造对象
//				Customer cust = new Customer();对于通用查询来说应该利用反射来得到应该造哪个类的对象
				T t=clazz.newInstance();
				/**
				 * 现在是查一条数据,若是查多条可以写成while(数据库表中的行) 获取结果集列数,根据结果集列数来判断需要读取多少个字段值
				 * 列数封装在rs的元数据中,在if之前使用getMetaData()方法获取结果集的元数据 通过ResultSetMetaData获取结果集的列数
				 */
				// 处理结果集一行数据中的每一个列
				for (int i = 0; i < columnCount; i++) {// 根据列数(数据库表中的列),循环读取属性字段值
					// 获取列值
					Object columValue = rs.getObject(i + 1);
					/**
					 * 将数据封装到一个对象当中,对象需要给属性们附上所查到的值;构造对象(两种方式,这里推荐方式二)
					 * 方式一:在构造器中将属性直接填进去(不推荐,因为对应同参数个数的构造器不一定有)
					 * 方式二:先用空参构造器造一个对象,根据查询属性字段通过Set方法将值设置进去(推荐)
					 * 对象造一次故不能写到for里,最好写到if里,for外;不写到if里因为可能存在没有结果集却造了个对象的情况
					 */
					/**
					 * 现在需要给cust这个对象指定的某一个属性名赋值为value 需要获取结果集当中的列名,将这个列名对应的同名的属性赋值为相应的value
					 */

					// 获取每个列的列名
					String columnLabel = rsmd.getColumnLabel(i+1);// 获取i+1这列
					// 将cust这个对象叫columnName这个名的属性赋值为columValue这个值,通过反射
					/**
					 * Customer类中找叫columnName的属性,把那个属性对应cust对象的值赋值为columValue 即调用运行时类的指定属性用户值的操作
					 */
					//Field field = Customer.class.getDeclaredField(columnName);// 先将叫这个名的属性拿到
					Field field = clazz.getDeclaredField(columnLabel);// 先将叫这个名的属性拿到
					field.setAccessible(true);// 拿到的这个属性可能是私有的,将它变得能访问
					field.set(t, columValue);// 将这个属性名的值设置给当前的cust,赋值为columValue

				}
				return t;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(null, ps, rs);
			// 如果没附上值,则返回null
		}
		return null;
		// 再去掉throws用try catch以及用finally,赋值为null
	}
}

jdbcstu.transaction\ConnectionTest.java

package jdbcstu1.transaction;

import java.sql.Connection;

import org.junit.Test;

import jdbcstu1.util.JDBCUtils;

public class ConnectionTest {
	@Test
	public void testGetConnection() throws Exception {
		Connection conn = JDBCUtils.getConnection();
		System.out.println(conn);
		
	}

}

jdbc.transaction\User.java

package jdbcstu1.transaction;

public class User {
	private String  user;
	private String  password;
	private int balance;
	public User() {
		super();
	}
	public User(String user, String password, int balance) {
		super();
		this.user = user;
		this.password = password;
		this.balance = balance;
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getBalance() {
		return balance;
	}
	public void setBalance(int balance) {
		this.balance = balance;
	}
	@Override
	public String toString() {
		return "User [user=" + user + ", password=" + password + ", balance=" + balance + "]";
	}
}


jdbcstu.util\JDBCUtils

package jdbcstu1.util;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**alt+shift+j  创建文档注释
 * @Description 因为每次获取连接和关闭连接都是必须要做的,所以我们可以将这两部分代码封装起来
 * 				这个是自己创建的工具类的包。
 * @author Field
 * @version
 * @date 2021年3月29日 下午8:52:27
 */


public class JDBCUtils {
	/**
	 * 打/**+Enter
	 * @Description 获取数据库连接
	 * @author Dell
	 * @version
	 * @date 2021年3月29日 下午9:10:00
	 * @return
	 * @throws Exception
	 */
	
	//静态方法,返回的是一个连接,方法名为getConnection
	public static Connection getConnection() throws Exception {
		//1.读取配置文件中四个基本信息;类.class.方法即类的加载器中系统加载器.方法(文件名)
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");//ctrl+1生成流
		Properties pros = new Properties();
		pros.load(is);//通过pros加载文件
		String user=pros.getProperty("user");//通过这个来读取
		String password=pros.getProperty("password");
		String url=pros.getProperty("url");
		String driverClass=pros.getProperty("driverClass");
		//2.加载驱动
		Class.forName(driverClass);
		
		//3.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);
		
		return conn;
	}
	
	public static void  closeResource(Connection conn,Statement ps) {//PreparedStatement,这里写成Statement大一点,PreparedStatement也能放
		/**
		 *  关闭连接和statement操作
		 */
		try {
			if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
			ps.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//关闭执行实例
		try {
			if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
			  conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
		
	}
	/**
	 * 
	 * @Description关闭资源操作(连接、Statement、结果集)
	 * @version
	 * @date 2021年3月31日 下午8:49:18
	 * @param conn
	 * @param ps
	 * @param rs
	 */
	public static void  closeResource(Connection conn,Statement ps,ResultSet rs) {//多一个参数构成方法的重载,需要导入sql下的包(面向接口编程不出现其他第三方API)
		try {
			if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
			ps.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//关闭执行实例
		try {
			if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
			  conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
		try {
			if(rs!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
			  rs.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

配置文件jdbc.properties

user=root
password=admin
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
driverClass=com.mysql.jdbc.Driver

2. BaseDAO(封装数据表操作)

  • 将对数据库表的通用操作方法封装到BaseDAO抽象类中,用抽象类的方式表示不能对其实例化
  • 将这个类作为基础父类,针对于具体的表会造它具体的DAO然后去继承于这个BaseDAO,然后针对于具体的表可重写方法。
  • 但一般为了代码规范首先会造具体表的接口,将要实现的方法写在里面,这样更加清楚。
  • 比如下BaseDAO(基础父类:通用方法操作)、CustomerDAO接口、CustomerDAO接口的实现类

如下为BaseDAO

package jdbcstu2.dao;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import jdbcstu1.util.JDBCUtils;

/*
 * DAO:data(base) access object
 * 封装了针对于数据表的通用的操作
 */

/*
 * 仅提供通用方法,不会去造它的对象
 * 故abstract修饰此类,表示仅是抽象类,不能对它实例化
 * 这是基础父类,针对于具体的表会造它具体的DAO然后去继承于这个BaseDAO
 * 但为了代码规范,一般先造一个接口
 */

public abstract class BaseDAO {
	//考虑了事务的增删改
	public int update(Connection conn,String sql,Object...args)  {
		PreparedStatement ps = null;
		try {
			//2.预编译sql语句返回PreparedStatement的实例
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);//小心参数声明错误
			}
			//4.执行
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//5.资源的关闭
			JDBCUtils.closeResource(null, ps);
		}
		return 0;
		}

//通用的查询操作用于返回数据表中的一条记录(version 2.0 考虑上事务)
	public <T>T getInstance(Connection conn,Class<T> clazz,String sql, Object... args) {// 获取一个对象实例,泛型方法T是对应的运行时类。返回值类型是T,T是一个参数
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}
			rs = ps.executeQuery();
			// 获取结果集的元数据(修饰现有数据的数据)
			ResultSetMetaData rsmd = rs.getMetaData();
			int columnCount = rsmd.getColumnCount();
			if (rs.next()) {
				// 如下述所言这里造对象
//				Customer cust = new Customer();对于通用查询来说应该利用反射来得到应该造哪个类的对象
				T t=clazz.newInstance();
				/**
				 * 现在是查一条数据,若是查多条可以写成while(数据库表中的行) 获取结果集列数,根据结果集列数来判断需要读取多少个字段值
				 * 列数封装在rs的元数据中,在if之前使用getMetaData()方法获取结果集的元数据 通过ResultSetMetaData获取结果集的列数
				 */
				// 处理结果集一行数据中的每一个列
				for (int i = 0; i < columnCount; i++) {// 根据列数(数据库表中的列),循环读取属性字段值
					// 获取列值
					Object columValue = rs.getObject(i + 1);
					/**
					 * 将数据封装到一个对象当中,对象需要给属性们附上所查到的值;构造对象
					 * 先用空参构造器造一个对象,根据查询属性字段通过Set方法将值设置进去(推荐)
					 * 对象造一次故不能写到for里,最好写到if里,for外;不写到if里因为可能存在没有结果集却造了个对象的情况
					 */
					/**
					 * 现在需要给cust这个对象指定的某一个属性名赋值为value 需要获取结果集当中的列名,将这个列名对应的同名的属性赋值为相应的value
					 */

					// 获取每个列的列名
					String columnLabel = rsmd.getColumnLabel(i+1);// 获取i+1这列
					// 将cust这个对象叫columnName这个名的属性赋值为columValue这个值,通过反射
					/**
					 * Customer类中找叫columnName的属性,把那个属性对应cust对象的值赋值为columValue 即调用运行时类的指定属性用户值的操作
					 */
					//Field field = Customer.class.getDeclaredField(columnName);// 先将叫这个名的属性拿到
					Field field = clazz.getDeclaredField(columnLabel);// 先将叫这个名的属性拿到
					field.setAccessible(true);// 拿到的这个属性可能是私有的,将它变得能访问
					field.set(t, columValue);// 将这个属性名的值设置给当前的cust,赋值为columValue

				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(null, ps, rs);
			// 如果没附上值,则返回null
		}
		return null;
		// 再去掉throws用try catch以及用finally,赋值为null
	}
	
	//通用的查询操作,用于返回表中多条记录构成的集合   version2(考虑上事务的)
		public <T> List<T> getForList(Connection conn,Class<T> clazz,String sql, Object... args){//ctrl+shift+O选择util下的list
			PreparedStatement ps = null;
			ResultSet rs = null;
			try {
				ps = conn.prepareStatement(sql);
				for (int i = 0; i < args.length; i++) {
					ps.setObject(i + 1, args[i]);
				}
				rs = ps.executeQuery();
				// 获取结果集的元数据(修饰现有数据的数据)
				ResultSetMetaData rsmd = rs.getMetaData();
				int columnCount = rsmd.getColumnCount();
				/**
				    *  造一个集合将对象放到集合当中,然后返回集合
				 */
				//创建集合对象
				ArrayList<T> list = new ArrayList<T>();//Ctrl+shift+O引入包
			
				while(rs.next()) {//查询多条记录,这里将if换成while
					// 如下述所言这里造对象
					T t=clazz.newInstance();
					/**
					 * 现在是查一条数据,若是查多条可以写成while(数据库表中的行) 获取结果集列数,根据结果集列数来判断需要读取多少个字段值
					 * 列数封装在rs的元数据中,在if之前使用getMetaData()方法获取结果集的元数据 通过ResultSetMetaData获取结果集的列数
					 */
					// 处理结果集一行数据中的每一个列:给t对象指定属性赋值
					for (int i = 0; i < columnCount; i++) {// 根据列数(数据库表中的列),循环读取属性字段值
						// 获取列值
						Object columValue = rs.getObject(i + 1);
						/**
						 * 将数据封装到一个对象当中,对象需要给属性们附上所查到的值;构造对象
						 * 先用空参构造器造一个对象,根据查询属性字段通过Set方法将值设置进去(推荐)
						 * 对象造一次故不能写到for里,最好写到if里,for外;不写到if里因为可能存在没有结果集却造了个对象的情况
						 */
						/**
						 * 现在需要给cust这个对象指定的某一个属性名赋值为value 需要获取结果集当中的列名,将这个列名对应的同名的属性赋值为相应的value
						 */

						// 获取每个列的列名
						String columnLabel = rsmd.getColumnLabel(i+1);// 获取i+1这列
						// 将cust这个对象叫columnName这个名的属性赋值为columValue这个值,通过反射
						/**
						 * Customer类中找叫columnName的属性,把那个属性对应cust对象的值赋值为columValue 即调用运行时类的指定属性用户值的操作
						 */
						//Field field = Customer.class.getDeclaredField(columnName);// 先将叫这个名的属性拿到
						Field field = clazz.getDeclaredField(columnLabel);// 先将叫这个名的属性拿到
						field.setAccessible(true);// 拿到的这个属性可能是私有的,将它变得能访问
						field.set(t, columValue);// 将这个属性名的值设置给当前的cust,赋值为columValue

					}
					list.add(t);//将对象加入集合
				}
				return list;//整个while循环结束后,在这里返回集合
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				JDBCUtils.closeResource(null, ps, rs);
			}
			return null;
		}
		
	//针对于组函数的通用查询特殊值的方法(查个数等)
	public <E>E getValue(Connection conn,String sql,Object...args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(sql);
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);
			}
			rs = ps.executeQuery();
			if(rs.next()) {
				rs.getObject(1);
				//返回值为泛型
				return (E) rs.getObject(1);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(null, ps, rs);
		}
		return null;
	}
}

以下代码是CustomerDAO的接口

 package jdbcstu2.dao;

import java.sql.Connection;
import java.sql.Date;
import java.util.List;

import jdbcstu2.bean.Customer;//无参构造器,带参构造器,get、set方法,toString方法

/*
 * 此接口用于规范针对于customers表的常用操作
 */
public interface CustomerDAO {
	/* 定义抽象方法,针对于Customer表可以做些什么呢?
	 * 1.insert的一条数据
	 * 2.等等
	 * 具体看你有什么诉求就提供什么功能
	 */
	/**
	 * 
	 * @Description 将cust对象添加到数据库中
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:32:10
	 * @param conn
	 * @param cust
	 */
	public abstract void insert(Connection conn,Customer cust);
	
	/**
	 * 
	 * @Description 针对指定的ID删除表中的一条记录
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:34:07
	 * @param conn
	 * @param cust
	 */
	public abstract void deleteById(Connection conn,int id);
	
	/**
	 * 
	 * @Description 针对于内存中的cust对象去修改数据表中的记录
	 * Java层面所new的Customer对象的ID是多少就将表中对应ID的属性改成java对象的属性(改其对应ID的记录)
	 * 把指定ID的这一条记录改成新的对象
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:36:06
	 * @param conn
	 * @param id
	 * @param cust
	 */
	public abstract void update(Connection conn,Customer cust);
	
	/**
	 * 
	 * @Description 针对指定的ID查询得到对应的Customer对象
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:42:42
	 * @param conn
	 * @param id
	 */
	public abstract Customer getCustomerById(Connection conn,int id);
	
	/**
	 * 
	 * @Description 查询表中的所有记录构成的集合
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:45:30
	 * @param conn
	 * @return
	 */
	public abstract List<Customer> getAll(Connection conn);
	
	/**
	 * 
	 * @Description 返回数据表中的数据条目数
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:48:33
	 * @param conn
	 * @return
	 */
	public abstract Long getCount(Connection conn);
	
	/**
	 * 
	 * @Description 返回数据表中最大的生日(数值最大)
	 * @author Dell
	 * @version
	 * @date 2021年4月6日 下午7:51:18
	 * @param conn
	 * @return
	 */
	public abstract Date getMaxBirth(Connection conn);

}

如下为CustomerDAO接口的实现类

package jdbcstu2.dao;

import java.sql.Connection;
import java.sql.Date;
import java.util.List;

import jdbcstu2.bean.Customer;

//重写实现这些方法
public class CustomerDAOImpl extends BaseDAO implements CustomerDAO {

	@Override
	public void insert(Connection conn, Customer cust) {
		String sql="insert into customers(name,email,birth)values(?,?,?)";
		update(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth());
		
	}

	@Override
	public void deleteById(Connection conn, int id) {
		String sql="delete from customers where id=?";
		update(conn, sql, id);
		
	}

	@Override
	public void update(Connection conn, Customer cust) {
		String sql="update customers set name=?,email=?,birth=? where id=?";
		update(conn, sql, cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
		
	}

	@Override
	public Customer getCustomerById(Connection conn, int id) {
		String sql="select id,name,email,birth from customers where id=?";
		Customer customer = getInstance(conn, Customer.class, sql, id);
		return customer;
	}

	@Override
	public List<Customer> getAll(Connection conn) {
		String sql="select id,name,email,birth from customers";
		List<Customer> list = getForList(conn, Customer.class, sql);
		return list;
	}

	@Override
	public Long getCount(Connection conn) {
		String sql="select count(*) from customers";
		return getValue(conn, sql);
	}

	@Override
	public Date getMaxBirth(Connection conn) {
		String sql="select max(birth) from customers";
		return getValue(conn, sql);
	}
	

}

测试实现类中的方法,防止某个select写错没有发现之类的

  1. 新建原包名.junit(针对于该包的测试)
  2. 包中选择新建JUnit Test Case
  3. name处写上将要测试的类名Test
  4. Class under test处用来指明到底要测谁(Browers后写上要测的类名)
  5. 选择next,勾选要测试的方法(如该类下的所有方法);然后Finish
  6. 此时已经自动把方法名写上再改写即可

以下为测试类

package jdbcstu2.dao.junit;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.Date;
import java.util.List;

import org.junit.Test;

import jdbcstu1.util.JDBCUtils;
import jdbcstu2.bean.Customer;
import jdbcstu2.dao.CustomerDAOImpl;

/**
 * 
 * @Description 测试CustomerDAOImpl.java中所有方法
 * @author Dell
 * @version
 * @date 2021年4月6日 下午9:02:38
 */
public class CustomerDAOImplTest {
	
	//先创造一个CustomerDAOImpl类的对象
	private CustomerDAOImpl dao = new CustomerDAOImpl();//就不对外暴露了

	@Test
	public void testInsert() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			Customer cust = new Customer(1,"林子风", "zifeng@126.com", new Date(4555614135668L));
			dao.insert(conn,cust);
			System.out.println("添加成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testDeleteById() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			dao.deleteById(conn, 13);
	
			System.out.println("删除成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testUpdateConnectionCustomer() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			Customer cust= new Customer(18,"贝多芬","beiduofen@126.com",new Date(4512653235L));
			dao.update(conn, cust);
			
			
			System.out.println("修改成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testGetCustomerById() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			Customer cust = dao.getCustomerById(conn, 20);
			System.out.println(cust);
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testGetAll() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			List<Customer> list = dao.getAll(conn);
			list.forEach(System.out::println);
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testGetCount() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			Long count = dao.getCount(conn);
			
			
			
			System.out.println("表中的记录数为:"+count);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

	@Test
	public void testGetMaxBirth() {
		Connection conn = null;
		try {
			conn = JDBCUtils.getConnection();
			
			Date maxBirth = dao.getMaxBirth(conn);
			
			
			System.out.println("最大的生日为:"+maxBirth);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
	}

}


2.1 BaseDAO优化(也可以不用优化)

CustomerDAOImpl继承BaseDAO的后面指明要操作的是哪个表对应过来的类,在这里即

在CustomerDAO接口实现类中的方法实参中删除Customer.class参数,牵扯到获取父类泛型问题

实现类如下所示

package jdbcstu3.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;

import jdbcstu.bean.Customer;

//重写实现这些方法
public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
    //优化后:CustomerDAOImpl继承BaseDAO的后面指明要操作的是哪个表对应过来的类,在这里即<Customer>

	
		
	@Override
	public void insert(Connection conn, Customer cust) {
		String sql="insert into customers(name,email,birth)values(?,?,?)";
		update(conn,sql,cust.getName(),cust.getEmail(),cust.getBirth());
		
	}

	@Override
	public void deleteById(Connection conn, int id) {
		String sql="delete from customers where id=?";
		update(conn, sql, id);
		
	}

	@Override
	public void update(Connection conn, Customer cust) {
		String sql="update customers set name=?,email=?,birth=? where id=?";
		update(conn, sql, cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
		
	}

	@Override
	public Customer getCustomerById(Connection conn, int id) {
		String sql="select id,name,email,birth from customers where id=?";
		Customer customer = getInstance(conn,sql, id);//优化后:删除Customer.class参数
		return customer;
	}

	@Override
	public List<Customer> getAll(Connection conn) {
		String sql="select id,name,email,birth from customers";
		List<Customer> list = getForList(conn,sql);//优化后:删除Customer.class参数
		return list;
	}

	@Override
	public Long getCount(Connection conn) {
		String sql="select count(*) from customers";
		return getValue(conn, sql);
	}

	@Override
	public Date getMaxBirth(Connection conn) {
		String sql="select max(birth) from customers";
		return getValue(conn, sql);
	}
	

}

  • 增加代码块获取子类(当前)对象的父类的泛型
  • 这个代码块一定是要在创建对象之前执行的
  • 这个代码块可以写到Customer接口类中,也可以写到BaseDAO中。但写到BaseDAO中最好-
  • 同时并更改方法名中前的泛型,以及方法中形参Class clazz;类名中新增泛型参数;成员新增声明clazz;删除方法名中的。
  • 当前谁的对象调用的这个或者说当前new的是谁的对象,this就是指谁的对象

如下所示的新增代码块后的BaseDAO

package jdbcstu3.dao;
//优化dao;反射之获取父类泛型

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import jdbcstu1.util.JDBCUtils;

/*
 * DAO:data(base) access object
 * 封装了针对于数据表的通用的操作
 */

/*
 * 仅提供通用方法,不会去造它的对象
 * 故abstract修饰此类,表示仅是抽象类,不能对它实例化
 * 这是基础父类,针对于具体的表会造它具体的DAO然后去继承于这个BaseDAO
 * 但为了代码规范,一般先造一个接口
 */

public abstract class BaseDAO<T> {//优化后新增了泛型参数<T>
	
    
    
    
    
    
    
	private Class<T> clazz=null;//优化后新增,但是null肯定不靠谱,需要对clazz做实例化。
    /* 实例化为谁取决于子类实现BaseDAO时父类的泛型是谁。
     * 如果在每一个子类在实例化前都写一个获取父类的泛型,有些麻烦。
     * 故:将获取父类泛型的这段代码写到父类中通过继承子类就能获得了
     * 写到父类中对这个属性进行赋值,保证在调低下的方法之前clazz要有值
     * 调方法是通过对象来调的,即在获取对象前clazz属性有值就行
     * 出现对象之前可以给属性赋值的位置有:1.显示赋值(麻烦,需要写多行代码,要重做个方法) 2.代码块中赋值 3.构造器中实例化
     * 我们在这里选择代码块的方式,注意:一定是非静态的;因为属性的声明是非静态的,这里如果写成静态的将不能调用(静态结构中不能调用非静态的)
     * 在测试中在new子类对象时,子类对象构造器中有super空就会加载父类结构,加载父类结构时就先后把构造器和代码块就加载了,在执行时就要获取当前对象父类的泛型
     */
    
	//构造器中对clazz实例化(需要在造对象之前进行实例化)
//	public BaseDAO() {
//		
//	}
	
//写一个代码块,获取当前对象的父类的泛型
	//获取当前BaseDAO的子类继承父类中的泛型
		{
			Type genericSuperclass = this.getClass().getGenericSuperclass();//这个this仍然是子类的对象。得到这个类的带泛型的父类(这是Type类型的)
            //这个this虽然在父类方法中,但这个this仍然是子类的对象,因为是子类对象去调用new的是子类的对象,只new了子类的对象也没有new父类的对象。因此这个this仍然是子类的对象。(造的是子类对象,这个this还是子类对象)
            //当前调用的new的是谁的对象,this就是指谁的对象;这里只new了子类的对象也没有new父类的对象,因此这个this仍然是子类的对象。(本例中这个父类是抽象类也不能new对象)
            //当前谁的对象调用的这个或者说当前new的是谁的对象,this就是指谁的对象
            //this.getClass先获取当前这个类(当前对象); 	  
            //this.getClass().getGenericSuperclass();获取当前这个类带泛型的父类
            
            
			ParameterizedType paramType=(ParameterizedType)genericSuperclass;//做强转,带参数的Type
			Type[] typeArguments = paramType.getActualTypeArguments();//获取了父类的泛型参数(有多个,返回的是数组)
			clazz=(Class<T>) typeArguments[0];//泛型的第一个参数即Customer,再将它赋值给clazz即可。同时赋值前再做一个强转。
		}
    
    
    
    
    
    
    
	//考虑了事务的增删改
	public int update(Connection conn,String sql,Object...args)  {
		PreparedStatement ps = null;
		try {
			//2.预编译sql语句返回PreparedStatement的实例
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);//小心参数声明错误
			}
			//4.执行
			return ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//5.资源的关闭
			JDBCUtils.closeResource(null, ps);
		}
		return 0;
		}

//通用的查询操作用于返回数据表中的一条记录(version 2.0 考虑上事务)
	public T getInstance(Connection conn,String sql, Object... args) {// 获取一个对象实例,泛型方法T是对应的运行时类。返回值类型是T,T是一个参数
        //优化后:删除形参中Class<T> clazz; 并删除方法名T前的<T>,因为声明了父类的泛型这里不再是泛型方法。
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}
			rs = ps.executeQuery();
			// 获取结果集的元数据(修饰现有数据的数据)
			ResultSetMetaData rsmd = rs.getMetaData();
			int columnCount = rsmd.getColumnCount();
			if (rs.next()) {
				
				T t=clazz.newInstance();
                //优化后:在删除了删除形参中Class<T> clazz后,这里会报错,因为这里要用clazz却没有了,故要获取这个clazz到底是谁?如何获取?----这个clazz在哪出现呢?------在实现类名处声明时的父类的泛型中出现。即获取当前这个类的父类的泛型。让它对父类中的clazz做实例化。
                
				// 处理结果集一行数据中的每一个列
				for (int i = 0; i < columnCount; i++) {// 根据列数(数据库表中的列),循环读取属性字段值
					// 获取列值
					Object columValue = rs.getObject(i + 1);
	

					// 获取每个列的列名
					String columnLabel = rsmd.getColumnLabel(i+1);// 获取i+1这列
					
					Field field = clazz.getDeclaredField(columnLabel);// 先将叫这个名的属性拿到
					field.setAccessible(true);// 拿到的这个属性可能是私有的,将它变得能访问
					field.set(t, columValue);// 将这个属性名的值设置给当前的cust,赋值为columValue

				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtils.closeResource(null, ps, rs);
			// 如果没附上值,则返回null
		}
		return null;
		// 再去掉throws用try catch以及用finally,赋值为null
	}
	
	//通用的查询操作,用于返回表中多条记录构成的集合   version2(考虑上事务的)
		public  List<T> getForList(Connection conn,String sql, Object... args){//ctrl+shift+O选择util下的list
            //优化后:删除形参中Class<T> clazz,并删除方法名T前的<T>,因为声明了父类的泛型这里不再是泛型方法。
            
			PreparedStatement ps = null;
			ResultSet rs = null;
			try {
				ps = conn.prepareStatement(sql);
				for (int i = 0; i < args.length; i++) {
					ps.setObject(i + 1, args[i]);
				}
				rs = ps.executeQuery();
				// 获取结果集的元数据(修饰现有数据的数据)
				ResultSetMetaData rsmd = rs.getMetaData();
				int columnCount = rsmd.getColumnCount();
				/**
				    *  造一个集合将对象放到集合当中,然后返回集合
				 */
				//创建集合对象
				ArrayList<T> list = new ArrayList<T>();//Ctrl+shift+O引入包
			
				while(rs.next()) {//查询多条记录,这里将if换成while
					// 如下述所言这里造对象
					T t=clazz.newInstance();
					/**
					 * 现在是查一条数据,若是查多条可以写成while(数据库表中的行) 获取结果集列数,根据结果集列数来判断需要读取多少个字段值
					 * 列数封装在rs的元数据中,在if之前使用getMetaData()方法获取结果集的元数据 通过ResultSetMetaData获取结果集的列数
					 */
					// 处理结果集一行数据中的每一个列:给t对象指定属性赋值
					for (int i = 0; i < columnCount; i++) {// 根据列数(数据库表中的列),循环读取属性字段值
						// 获取列值
						Object columValue = rs.getObject(i + 1);
						/**
						 * 将数据封装到一个对象当中,对象需要给属性们附上所查到的值;构造对象
						 * 先用空参构造器造一个对象,根据查询属性字段通过Set方法将值设置进去(推荐)
						 * 对象造一次故不能写到for里,最好写到if里,for外;不写到if里因为可能存在没有结果集却造了个对象的情况
						 */
						/**
						 * 现在需要给cust这个对象指定的某一个属性名赋值为value 需要获取结果集当中的列名,将这个列名对应的同名的属性赋值为相应的value
						 */

						// 获取每个列的列名
						String columnLabel = rsmd.getColumnLabel(i+1);// 获取i+1这列
						// 将cust这个对象叫columnName这个名的属性赋值为columValue这个值,通过反射
						/**
						 * Customer类中找叫columnName的属性,把那个属性对应cust对象的值赋值为columValue 即调用运行时类的指定属性用户值的操作
						 */
						//Field field = Customer.class.getDeclaredField(columnName);// 先将叫这个名的属性拿到
						Field field = clazz.getDeclaredField(columnLabel);// 先将叫这个名的属性拿到
						field.setAccessible(true);// 拿到的这个属性可能是私有的,将它变得能访问
						field.set(t, columValue);// 将这个属性名的值设置给当前的cust,赋值为columValue

					}
					list.add(t);//将对象加入集合
				}
				return list;//整个while循环结束后,在这里返回集合
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				JDBCUtils.closeResource(null, ps, rs);
			}
			return null;
		}
		
	//针对于组函数的通用查询特殊值的方法(查个数等)
	public <E>E getValue(Connection conn,String sql,Object...args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(sql);
			for(int i=0;i<args.length;i++) {
				ps.setObject(i+1, args[i]);
			}
			rs = ps.executeQuery();
			if(rs.next()) {
				rs.getObject(1);
				//返回值为泛型
				return (E) rs.getObject(1);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(null, ps, rs);
		}
		return null;
	}
}

3. 数据库连接池

3.1 C3P0

需要导入第三方jar包(先放到lib文件下,再选中右键添加build path)

c3p0test.java

package jdbcstu4.connection;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

import org.junit.Test;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;

public class C3P0test {
	//方式一:这是将配置信息写到代码中的硬编码方式(不提倡)
	@Test
	public void testGetConnection() throws Exception{
		//获取c3p0数据库连接池
		ComboPooledDataSource cpds = new ComboPooledDataSource();//DataSource接口的具体实现类
		cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //填写jdbc driver的路径            
		cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/test" );
		cpds.setUser("root");                                  
		cpds.setPassword("admin");
		//通过设置相关的参数,对数据库连接池进行管理
		cpds.setInitialPoolSize(10);//这里设置的初始时数据库连接池中的连接数
		
		Connection conn = cpds.getConnection();
		System.out.println(conn);	
		
		//DataSources.destroy( cpds );//销毁c3p0数据库连接池(一般情况下也不会关闭数据库连接池的)
	}
	//方式二:使用配置文件
	@Test
	public void testGetConnection1() throws SQLException {
		ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致
		Connection conn = cpds.getConnection();
		System.out.println(conn);
		
	}

}

使用.xml文件的方式写数据库配置数据。xml一般用来给前端传送数据或者写配置

src下右键new一个xml文件。文件名为c3p0-config.xml

创建好.xml文件是表格样式的可以在底下点source

可从官方文档那里粘过来.xml写法例子。删掉默认配置部分、用户重写部分。

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>


	
	<named-config name="hellc3p0"><!-- 文件名 -->
	    <!--提供获取连接的4个基本信息-->
	    <property name="driverClass">com.mysql.jdbc.Driver</property><!-- 这里的名字一定要一致 -->
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property><!-- 若连本地且默认端口为3306,可写为jdbc:mysql:///test -->
		<property name="user">root</property>
		<property name="password">admin</property>
		
		<!--进行数据库连接池管理的基本信息-->
		<!-- 当数据库连接池中的连接数不够时,c3p0一次性向数据库服务器申请的连接数 -->
		<property name="acquireIncrement">5</property>
		<!-- c3p0数据库连接池中初始化时的连接数 -->
		<property name="initialPoolSize">10</property>
		<!-- c3p0数据库连接池中维护的最少连接数 -->
		<property name="minPoolSize">10</property>
		<!-- c3p0数据库连接池中维护的最多的连接数 -->
		<property name="maxPoolSize">100</property>

		<!-- c3p0数据库连接池中最多维护的Statement的个数 -->
		<property name="maxStatements">50</property>
		<!-- 每个连接中可以最多使用的Statement的个数 -->
		<property name="maxStatementsPerConnection">2</property>


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

JDBCUtils.java文件如下

package jdbcstu4.util;

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

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	/**
	 * 
	 * @Description 使用c3p0的数据库连接技术
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午8:37:39
	 * @return
	 * @throws SQLException
	 */
	
	//这个放到这里较好,并且前面加上private static
	//因为如果放到里面,每次调用getConnection时就会new一个。但它new一个就行(数据库连接池仅需提供一个即可)
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致;
	
	public static Connection getConnection1() throws SQLException {
		Connection conn = cpds.getConnection();
		
		return conn;
	}

}

3.2 DBCP

  • DBCP需要导入两个jar包:commons-dbcp-1.4.jar和commons-pool-1.5.5.jar
  • XXXXFactory是造XXXX类的对象的

DBCPTest.java文件如下

package jdbcstu4.connection;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;

public class DBCPTest {
	/**
	 * 
	 * @Description 测试DBCP的数据库连接池技术
	 * @author Dell
	 * @version
	 * @throws SQLException 
	 * @date 2021年4月7日 下午9:11:20
	 */
	//方式一:不推荐
	@Test
	public void testGetConnection() throws SQLException {
		//创建了DBCP的数据库连接池
		BasicDataSource source=new BasicDataSource();//在这一行ctrl+T可以看到它具体的实现类(可以看到有BasicDataSource,则可以new一个(其要有空参构造器,有的))
		//设置基本信息
		source.setDriverClassName("com.mysql.jdbc.Driver");
		source.setUrl("jdbc:mysql:///test");
		source.setUsername("root");
		source.setPassword("admin");
		
		//还可以设置其他涉及数据库连接池管理的相关属性
		source.setInitialSize(10);
		source.setMaxActive(10);
		//等等
		
		Connection conn = source.getConnection();
		System.out.println(conn);
		
	}
	//方式二:推荐:使用配置文件
	@Test
	public void testGetConnection1() throws Exception {
		Properties pros = new Properties();
		
		//加载配置文件的方式1:类的加载器
		//InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
		//方式2:
		FileInputStream is=new FileInputStream(new File("src/dbcp.properties"));
		
		
		pros.load(is);//加载一个流
		DataSource source = BasicDataSourceFactory.createDataSource(pros);
		//出现arg0是因为没有导入源码(按下ctrl键不松手,再将鼠标移到该函数位置选择Open Declaration(或直接进入)
		//进入后选择Attach Source,选择External location选择commons-dbcp-1.4-src.zip)
		Connection conn = source.getConnection();
		System.out.println(conn);
		
		
	}

}

dbcp.properties文件,(一定要是位于src下)

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
username=root
password=admin

initialSize=10

JDBCUtils.java文件如下

package com.atguigu4.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	/**
	 * 
	 * @Description 使用c3p0的数据库连接技术
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午8:37:39
	 * @return
	 * @throws SQLException
	 */
	
	//这个放到这里较好,并且前面加上private static
	//因为如果放到里面,每次调用getConnection时就会new一个。但它new一个就行(数据库连接池仅需提供一个即可)
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致;
	
	public static Connection getConnection1() throws SQLException {
		Connection conn = cpds.getConnection();
		
		return conn;
	}
	
	/**
	 * 
	 * @Description 使用DBCP数据库连接池技术获取数据库连接
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午10:10:27
	 * @return
	 * @throws Exception
	 */
	//同样的(数据库连接池仅需提供一个即可)因此考虑使用静态代码块
	private static DataSource source;
	static {
	        try {
				//创建一个DBCP数据库连接池
				Properties pros = new Properties();
				//方式2:
				FileInputStream is=new FileInputStream(new File("src/dbcp.properties"));
				pros.load(is);//加载一个流
				source = BasicDataSourceFactory.createDataSource(pros);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	public static Connection getConnection2 () throws Exception {
		
		Connection conn = source.getConnection();
		return conn;
	}

}

3.3 Druid(德鲁伊)数据库连接池

首先加载驱动

DruidTest.java文件如下

package jdbcstu4.connection;

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

import javax.sql.DataSource;

import org.junit.Test;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

public class DruidTest {
	@Test
	public void getConnection() throws Exception {
		Properties pros = new Properties();
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
		
		pros.load(is);
		
		DataSource source = DruidDataSourceFactory.createDataSource(pros);
		Connection conn = source.getConnection();
		System.out.println(conn);
		
	}

}

Druid.properties文件如下

url=jdbc:mysql:///test
username=root
password=admin
driverClassName=com.mysql.jdbc.Driver

initialSize=10
maxActive=10

JDBCUtils.java文件如下

package com.atguigu4.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	/**
	 * 
	 * @Description 使用c3p0的数据库连接技术
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午8:37:39
	 * @return
	 * @throws SQLException
	 */
	
	//这个放到这里较好,并且前面加上private static
	//因为如果放到里面,每次调用getConnection时就会new一个。但它new一个就行(数据库连接池仅需提供一个即可)
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致;
	
	public static Connection getConnection1() throws SQLException {
		Connection conn = cpds.getConnection();
		
		return conn;
	}
	
	/**
	 * 
	 * @Description 使用DBCP数据库连接池技术获取数据库连接
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午10:10:27
	 * @return
	 * @throws Exception
	 */
	//同样的(数据库连接池仅需提供一个即可)因此考虑使用静态代码块
	private static DataSource source;
	static {
	        try {
				//创建一个DBCP数据库连接池
				Properties pros = new Properties();
				//方式2:
				FileInputStream is=new FileInputStream(new File("src/dbcp.properties"));
				pros.load(is);//加载一个流
				source = BasicDataSourceFactory.createDataSource(pros);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	public static Connection getConnection2 () throws Exception {
		
		Connection conn = source.getConnection();
		return conn;
	}
	
	/**
	 * 使用Druid数据库连接池技术
	 */
	private static DataSource source1;
	static {
		try {
			Properties pros = new Properties();
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
			
			pros.load(is);
			
			source1 = DruidDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConnection3() throws SQLException {
		Connection conn = source1.getConnection();
		return conn;
	}

}

4. Apache-DBUtils实现CRUD操作(增删改查)

首先,导入jar包(commons-dbutils-1.3);Apache提供封装了jdbc增删改查的工具类库

QueryRunnerTest.java文件

package jdbcstu5.dbutils;

import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

import jdbcstu2.bean.Customer;
import jdbcstu4.util.JDBCUtils;

public class QueryRunnerTest {
	//测试插入
	@Test
	public void testInsert(){
		//调用下面方法时出现args0了,需要关联源码(commons-dbutils-1.3-src.zip)
		Connection conn = null;
		try {
			QueryRunner runner = new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="insert into customers(name,email,birth)values(?,?,?)";
			int insertCount = runner.update(conn, sql, "张果果","guoguo@126.com","1998-05-12");//牵扯到事务类就选择传入连接的
			System.out.println("添加了"+insertCount+"条记录");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	//测试查询
	/*
	 * BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条记录。(返回一个对象)
	 */
	@Test
	public void testQuery1() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select id,name,email,birth from customers where id=?";
			//本例中想要封装的是Customer类,它没有空参构造器需要传一下,参数要写Customer.class
			BeanHandler<Customer> handler=new BeanHandler<>(Customer.class);
			Customer customer = runner.query(conn, sql, handler, 25);//第三个参数是结果集的处理器(这是一个接口所以只能传它的具体实现类);
			//如需要返回一个对象,则根据官方文档可看,可以使用BeanHandler<T>实现类(带泛型,看你具体想封装的是哪一个类了)
			System.out.println(customer);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	/*
	 *BeanListHandler是ResultSetHandler接口的实现类,用于封装表中的多条记录构成的集合。
	 */
	@Test
	public void testQuery2() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select id,name,email,birth from customers where id<?";
			
			BeanListHandler<Customer> handler=new BeanListHandler<>(Customer.class);
			
			List<Customer> list = runner.query(conn, sql, handler, 25);//第三个参数是结果集的处理器(这是一个接口所以只能传它的具体实现类);
			list.forEach(System.out::println);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	
	/*
	 *MapHandler是ResultSetHandler接口的实现类,对应表中的一条记录
	 *将字段及相应字段的值作为map中的key和value。(返回结果是键值对map的形式,而不是对象)
	 */
	@Test
	public void testQuery3() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select id,name,email,birth from customers where id=?";
			//看文档中没有泛型且有空参构造器
			MapHandler handler=new MapHandler();
			
			Map<String, Object> map = runner.query(conn, sql, handler, 25);
			
			System.out.println(map);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	

	/*
	 *MapListHandler是ResultSetHandler接口的实现类,对应表中的多条记录
	 *将字段及相应字段的值作为map中的key和value。将这些map添加到list中(返回结果是键值对map的形式,而不是对象)
	 */
	@Test
	public void testQuery4() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select id,name,email,birth from customers where id<?";
			//看文档中没有泛型且有空参构造器
			MapListHandler handler=new MapListHandler();
			
			List<Map<String,Object>> list = runner.query(conn, sql, handler, 25);
			list.forEach(System.out::println);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	/*
	 * 查看表中记录个数(特殊的查询)
	 */
	@Test
	public void testQuery5() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select count(*) from customers";
			//看文档中没有泛型且有空参构造器
			ScalarHandler handler = new ScalarHandler();
			
			Long count=(Long) runner.query(conn, sql, handler);
			System.out.println(count);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	/*
	 * ScalarHandler:用于查询特殊值
	 * 查看最大生日(特殊的查询)
	 */
	@Test
	public void testQuery6() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select max(birth) from customers";
			//看文档中没有泛型且有空参构造器
			ScalarHandler handler = new ScalarHandler();
			
			Date maxBirth=(Date) runner.query(conn, sql, handler);
			System.out.println(maxBirth);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	/*
	 * 当没有能满足的实现类时,可以自己写一个实现类
	 * 自定义ResultSetHandler的实现类
	 */
	@Test
	public void testQuery7() {
		Connection conn = null;
		try {
			QueryRunner runner=new QueryRunner();
			conn = JDBCUtils.getConnection3();
			String sql="select id,name,email,birth from customers where id=?";
			//自己写一个handler(匿名实现类)
			//假设写一个单条语句查询
			ResultSetHandler<Customer> handler=new ResultSetHandler<Customer>(){

				@Override
				public Customer handle(ResultSet rs) throws SQLException {
					if(rs.next()) {
						int id=rs.getInt("id");
						String name=rs.getString("name");
						String email = rs.getString("email");
						Date birth = rs.getDate("birth");
						Customer customer = new Customer(id, name, email, birth);
						return customer;
					}
					return null;
				}
			};
			Customer customer = runner.query(conn, sql, handler,25);
			System.out.println(customer);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}


}

jdbcstu4.util.JDBCUtils文件

package jdbcstu4.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	/**
	 * 
	 * @Description 使用c3p0的数据库连接技术
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午8:37:39
	 * @return
	 * @throws SQLException
	 */
	
	//这个放到这里较好,并且前面加上private static
	//因为如果放到里面,每次调用getConnection时就会new一个。但它new一个就行(数据库连接池仅需提供一个即可)
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致;
	
	public static Connection getConnection1() throws SQLException {
		Connection conn = cpds.getConnection();
		
		return conn;
	}
	
	/**
	 * 
	 * @Description 使用DBCP数据库连接池技术获取数据库连接
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午10:10:27
	 * @return
	 * @throws Exception
	 */
	//同样的(数据库连接池仅需提供一个即可)因此考虑使用静态代码块
	private static DataSource source;
	static {
	        try {
				//创建一个DBCP数据库连接池
				Properties pros = new Properties();
				//方式2:
				FileInputStream is=new FileInputStream(new File("src/dbcp.properties"));
				pros.load(is);//加载一个流
				source = BasicDataSourceFactory.createDataSource(pros);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	public static Connection getConnection2 () throws Exception {
		
		Connection conn = source.getConnection();
		return conn;
	}
	
	/**
	 * 使用Druid数据库连接池技术
	 */
	private static DataSource source1;
	static {
		try {
			Properties pros = new Properties();
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
			
			pros.load(is);
			
			source1 = DruidDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConnection3() throws SQLException {
		Connection conn = source1.getConnection();
		return conn;
	}
	
	
    
    
    /**
     *
     * 以下是原来的自己写的方法
     */
	
	
	//静态方法,返回的是一个连接,方法名为getConnection
		public static Connection getConnection() throws Exception {
			//1.读取配置文件中四个基本信息;类.class.方法即类的加载器中系统加载器.方法(文件名)
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");//ctrl+1生成流
			Properties pros = new Properties();
			pros.load(is);//通过pros加载文件
			String user=pros.getProperty("user");//通过这个来读取
			String password=pros.getProperty("password");
			String url=pros.getProperty("url");
			String driverClass=pros.getProperty("driverClass");
			//2.加载驱动
			Class.forName(driverClass);
			
			//3.获取连接
			Connection conn = DriverManager.getConnection(url, user, password);
			
			return conn;
		}
		
		
		
		public static void  closeResource(Connection conn,Statement ps) {//PreparedStatement,这里写成Statement大一点,PreparedStatement也能放
			/**
			 *  关闭连接和statement操作
			 */
			try {
				if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭执行实例
			try {
				if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
			
		}
		/**
		 * 
		 * @Description关闭资源操作(连接、Statement、结果集)
		 * @version
		 * @date 2021年3月31日 下午8:49:18
		 * @param conn
		 * @param ps
		 * @param rs
		 */
		public static void  closeResource(Connection conn,Statement ps,ResultSet rs) {//多一个参数构成方法的重载,需要导入sql下的包(面向接口编程不出现其他第三方API)
			try {
				if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭执行实例
			try {
				if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
			try {
				if(rs!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}


}

5.DbUtils类关闭资源的方式

JDBCUtils.java文件

package jdbcstu4.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils {
	/**
	 * 
	 * @Description 使用c3p0的数据库连接技术
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午8:37:39
	 * @return
	 * @throws SQLException
	 */
	
	//这个放到这里较好,并且前面加上private static
	//因为如果放到里面,每次调用getConnection时就会new一个。但它new一个就行(数据库连接池仅需提供一个即可)
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");//与配置文件中自定义写的名字一致;
	
	public static Connection getConnection1() throws SQLException {
		Connection conn = cpds.getConnection();
		
		return conn;
	}
	
	/**
	 * 
	 * @Description 使用DBCP数据库连接池技术获取数据库连接
	 * @author Dell
	 * @version
	 * @date 2021年4月7日 下午10:10:27
	 * @return
	 * @throws Exception
	 */
	//同样的(数据库连接池仅需提供一个即可)因此考虑使用静态代码块
	private static DataSource source;
	static {
	        try {
				//创建一个DBCP数据库连接池
				Properties pros = new Properties();
				//方式2:
				FileInputStream is=new FileInputStream(new File("src/dbcp.properties"));
				pros.load(is);//加载一个流
				source = BasicDataSourceFactory.createDataSource(pros);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	public static Connection getConnection2 () throws Exception {
		
		Connection conn = source.getConnection();
		return conn;
	}
	
	/**
	 * 使用Druid数据库连接池技术
	 */
	private static DataSource source1;
	static {
		try {
			Properties pros = new Properties();
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
			
			pros.load(is);
			
			source1 = DruidDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getConnection3() throws SQLException {
		Connection conn = source1.getConnection();
		return conn;
	}
	
	
	
	
	//静态方法,返回的是一个连接,方法名为getConnection
		public static Connection getConnection() throws Exception {
			//1.读取配置文件中四个基本信息;类.class.方法即类的加载器中系统加载器.方法(文件名)
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");//ctrl+1生成流
			Properties pros = new Properties();
			pros.load(is);//通过pros加载文件
			String user=pros.getProperty("user");//通过这个来读取
			String password=pros.getProperty("password");
			String url=pros.getProperty("url");
			String driverClass=pros.getProperty("driverClass");
			//2.加载驱动
			Class.forName(driverClass);
			
			//3.获取连接
			Connection conn = DriverManager.getConnection(url, user, password);
			
			return conn;
		}
		
		
		
		public static void  closeResource(Connection conn,Statement ps) {//PreparedStatement,这里写成Statement大一点,PreparedStatement也能放
			/**
			 *  关闭连接和statement操作
			 */
			try {
				if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭执行实例
			try {
				if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
			
		}
		/**
		 * 
		 * @Description关闭资源操作(连接、Statement、结果集)
		 * @version
		 * @date 2021年3月31日 下午8:49:18
		 * @param conn
		 * @param ps
		 * @param rs
		 */
		public static void  closeResource(Connection conn,Statement ps,ResultSet rs) {//多一个参数构成方法的重载,需要导入sql下的包(面向接口编程不出现其他第三方API)
			try {
				if(ps!=null)//避免空指针问题,因为对象没有创建报异常,finally这里进行关闭操作,从而出现空指针的调用,因此加以判断,避免空指针问题
				ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭执行实例
			try {
				if(conn!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}//关闭连接,(关闭了资源则可以不用再抛出异常,对上面的大块进行统一try catch,再还要对两个关闭进行try catch)
			try {
				if(rs!=null)//避免空指针问题,因为获取连接的时候报异常,对象没拿到却仍然在finally这里进行关闭操作,因此加以判断,避免空指针问题
				  rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		/**
		 * 
		 * @Description 使用dbutils.jar中提供的DbUtils工具类,实现资源的关闭
		 * @author Dell
		 * @version
		 * @date 2021年4月8日 下午9:35:18
		 * @param conn
		 * @param ps
		 * @param rs
		 */
		//方法一
		public static void  closeResource1(Connection conn,Statement ps,ResultSet rs) {//多一个参数构成方法的重载,需要导入sql下的包(面向接口编程不出现其他第三方API)
//			try {
//				DbUtils.close(conn);
//			} catch (SQLException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			try {
//				DbUtils.close(ps);
//			} catch (SQLException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			try {
//				DbUtils.close(rs);
//			} catch (SQLException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			

			
			//方法二
			DbUtils.closeQuietly(conn);
			DbUtils.closeQuietly(ps);
			DbUtils.closeQuietly(rs);

		}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值