JavaWeb之JDBC(2.2):数据库事务、数据库连接池、DBUtils、DAO及其子类代码演示

写在前面:JDBCUtils类代码主要提供对MySQL数据库的连接、关闭功能,Customer和Order等bean类主要封装对应数据库相关属性并提供get、set、toString方法及构造器,具体代码请看前面的博文。

附上JDBCUTils类代码

package JavaWeb.JDBC.day3.util;

import java.io.FileInputStream;
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 JavaWeb.JDBC.day3.connection.DBCPTest;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * 提供数据库连接、关闭等操作的工具类
 */
public class JDBCUtils {
	/**
	 * 测试main方法
	 * @param args
	 * @throws SQLException
	 */
	public static void main(String[] args) throws SQLException {
		Connection conn = getC3P0Connection();
		System.out.println(conn);
	}

	// 关闭资源的操作
	public static void closeResource(Connection conn, Statement st, ResultSet rs) {
	
		try {
			DbUtils.close(conn);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		try {
			DbUtils.close(st);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		try {
			DbUtils.close(rs);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	// 关闭资源的操作
	public static void closeResource(Connection conn, Statement st) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		if (st != null) {
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	// 获取连接的操作
	public static Connection getConnection() throws Exception {
		// 1.加载配置文件
		Properties pros = new Properties();
		FileInputStream fis = new FileInputStream("D:\\Workspaces\\Java20190715\\TeacherProgram\\src\\jdbc.properties");
		pros.load(fis);

		// 2.获取连接所需的四个基本信息
		String driverClass = pros.getProperty("driverClass");
		String url = pros.getProperty("url");
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");

		// 3.加载驱动
		Class.forName(driverClass);

		// 4.获取连接
		Connection conn = DriverManager.getConnection(url, user, password);

		return conn;
	}
	
	//使用c3p0数据库连接池的方式
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0"); //保证此数据源是唯一的!
	public static Connection getC3P0Connection() throws SQLException {
		
		Connection conn = cpds.getConnection();
		return conn;
	}
	
	//使用dbcp数据库连接池的方式
	private static DataSource source;//保证此数据源是唯一的!
	static{
		try {
			Properties pros = new Properties();
			InputStream is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
			
			pros.load(is);
			
			source = BasicDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public static Connection getDBCPConnection() throws SQLException {
		
		Connection conn = source.getConnection();
		
		return conn;
	}

}

1.事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
2.事务处理的原则:
保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;
要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。

演示转账问题

例子:
AA 向 BB 转账 100
过程一:
update user_table set balance = balance - 100 where user = AA.
假设中途服务器宕机
过程二:
update user_table set balance = balance + 100 where user = BB.

注意:最下面是转账失败代码,阅读请留意

package JavaWeb.JDBC.day3.java;

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 JavaWeb.JDBC.day3.util.JDBCUtils;
import org.junit.Test;

public class TransactionTest {
	
	// 通用的查询,返回一条记录 (version 2.0)
	public <T> T getInstance(Connection conn,Class<T> clazz, String sql, Object... args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 1.预编译sql语句
			ps = conn.prepareStatement(sql);

			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.调用executeQuery(),获取结果集
			rs = ps.executeQuery();

			// 4.获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			// 5.获取结果集中列的个数
			int columnCount = rsmd.getColumnCount();

			// 6.处理结果集
			if (rs.next()) {// ①判断指针的下一个位置是否有数据 ②如果返回true,指针下移。如果返回false,指针不下移。

				T t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {// 处理列

					Object columnValue = rs.getObject(i + 1);// 获取列值

					String columnLabel = rsmd.getColumnLabel(i + 1);// 获取结果集中列的别名

					// 反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);

				}

				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(null, ps, rs);

		}

		return null;
	}
	
	
	/*
	 * 演示转账操作
	 * 
	 */
	@Test
	public void testUpdateWithTx() {
		
		Connection conn = null;
		try {
			String sql1 = "update user_table set balance = balance - 100 where user = ?";
			String sql2 = "update user_table set balance = balance + 100 where user = ?";
			
			conn = JDBCUtils.getConnection();
			
			//1.设置不能自动提交数据
			conn.setAutoCommit(false);
			//过程一:
			updateWithTx(conn,sql1,"AA");
			
			//出现异常
			System.out.println(10 / 0);
			
			//过程二:
			updateWithTx(conn,sql2,"BB");
			
			//2.提交数据
			conn.commit();
			
			System.out.println("转账成功!");
		} catch (Exception e) {
			e.printStackTrace();
			
			try {
				//3.回滚数据
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			
		}finally {
			if(conn != null) {
				//关闭连接
				JDBCUtils.closeResource(conn, null);
				
			}
		}
		
		
	}
	
	
	//通用的增删改 (version 2.0)
	public void updateWithTx(Connection conn ,String sql, Object... args) {
		PreparedStatement ps = null;
		try {
			// 1.
			ps = conn.prepareStatement(sql);
			// 2.填充占位符
			for(int i = 0;i < args.length;i++) {
				ps.setObject(i + 1, args[i]);
			}
			
			// 3.执行
			int count = ps.executeUpdate();

			System.out.println("影响了" + count + "条数据");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 4.连接一定不要关闭!
			JDBCUtils.closeResource(null, ps,null);
		}
	}

在这里插入图片描述
使用2.0版本转账方法发生了事务回滚
在这里插入图片描述
/*
* 1. 数据一旦提交,不可回滚。
* 2. 哪些操作,会导致数据的提交:
* 情况一:执行的DML操作,默认情况下,一旦执行完,就会自动提交数据。 (set autocommit = false)
* 情况二:一旦断开数据库的连接,也会提交之前未提交的数据。
*
*/

	@Test
	public void testUpdate() {
		
		String sql1 = "update user_table set balance = balance - 100 where user = ?";
		String sql2 = "update user_table set balance = balance + 100 where user = ?";
		
		
		update(sql1,"AA");
		
		//模拟网络出现阻塞的异常
		System.out.println(10 / 0);
		
		
		update(sql2,"BB");
		
		System.out.println("转账成功");
		
	}
	
	
	//通用的增删改 (version 1.0)
	public void update(String sql, Object... args) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			// 1.
			conn = JDBCUtils.getConnection();
			// 2.
			ps = conn.prepareStatement(sql);
			// 3.填充占位符
			for(int i = 0;i < args.length;i++) {
				ps.setObject(i + 1, args[i]);
			}			
			// 4.执行
			int count = ps.executeUpdate();
			System.out.println("影响了" + count + "条数据");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 5.
			JDBCUtils.closeResource(conn, ps,null);
		}
	}
	}

在这里插入图片描述
使用1.0版本方法转账失败,没有回滚
在这里插入图片描述

dbutils工具包包下QueryRunner、handlers.BeanHandler、handlers.BeanListHandler、handlers.MapHandler、handlers.ScalarHandler的使用

package JavaWeb.JDBC.day3.java;

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

import JavaWeb.JDBC.day3.bean.Customer;
import JavaWeb.JDBC.day3.util.JDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
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.ScalarHandler;
import org.junit.Test;


public class QueryRunnerTest {
	
	//查询一些特殊数据:查询最大值 、 平均数
	@Test
	public void testScalarValue() throws Exception {
		QueryRunner runner = new QueryRunner();
	
	Connection conn = JDBCUtils.getConnection();
	ScalarHandler handler = new ScalarHandler();
	
	//需求一:查询birth的最大值
//		String sql = "select max(birth) from customers";
//		Date birth = (Date) runner.query(conn, sql, handler);
//		System.out.println(birth);
	//需求二:查询表中的数据的数量
	String sql = "select count(*) from customers";
	long count = (long) runner.query(conn, sql, handler);
	System.out.println(count);
	
	JDBCUtils.closeResource(conn, null);
}

在这里插入图片描述

//查询表中的一条记录,以key-value的方式显示
@Test
public void testQueryForMap() throws Exception {
	QueryRunner runner = new QueryRunner();
	
	Connection conn = JDBCUtils.getConnection();
	
	String sql = "select id,name,email,birth from customers where id = ?";
	
	MapHandler handler = new MapHandler();
	
	Map<String, Object> map = runner.query(conn, sql, handler, 6);
	
	System.out.println(map);
	
	JDBCUtils.closeResource(conn, null);
}

在这里插入图片描述

//查询表中的多条记录构成的集合:BeanListHandler
@Test
public void testQueryForList() throws Exception {
	QueryRunner runner = new QueryRunner();
	
	Connection conn = JDBCUtils.getConnection();
	
	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, 10);
	
	list.forEach(System.out::println);
	
	JDBCUtils.closeResource(conn, null);
}

在这里插入图片描述

//查询表中的一条记录:BeanHandler
@Test
public void testQueryInstance() throws Exception {
	
	QueryRunner runner = new QueryRunner();
	
	Connection conn = JDBCUtils.getConnection();
	
	String sql = "select id,name,email,birth from customers where id = ?";
	
	BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
	
	Customer customer = runner.query(conn, sql, handler, 6);
	
	System.out.println(customer);
	JDBCUtils.closeResource(conn, null);
}

在这里插入图片描述

@Test
public void testInsert() {
	
	Connection conn = null;
	try {
		QueryRunner runner = new QueryRunner();
		
		conn = JDBCUtils.getC3P0Connection();
		String sql = "insert into customers(name,email,birth)values(?,?,?)";
		//调用如下的update()方法实现增、删、改的操作
		runner.update(conn, sql,"张三","zhangsan@gmail.com","2019-08-04");
	
	
	} catch (SQLException e) {
		e.printStackTrace();
	}
	
	JDBCUtils.closeResource(conn, null);
}
}

插入成功
在这里插入图片描述
以上是JDBC重点,下面介绍c3p0与dbcp连接池

使用 c3p0数据库连接池技术实现数据库连接

package JavaWeb.JDBC.day3.connection;

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

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;

/**

  • 1.实现数据库连接的方式:
  • ① 手动实现的连接 (DriverManager)
  • ② 使用数据库连接池
  • 2.使用数据库连接池的好处:
  • ① 更快的连接速度
  • ② 更好的资源重用
  • ③ 更便捷的数据库连接的管理
  • 3.JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口

*4.两种数据库连接池技术:
① C3P0 数据库连接池 ② DBCP数据库连接池
*/

public class C3P0Test {

//方式二:使用配置文件
@Test
public void testConnection2() throws SQLException {
	ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
	Connection conn = cpds.getConnection();
	System.out.println(conn);	
}

//方式一:
@Test
public void testConnection1() throws Exception {
	ComboPooledDataSource cpds = new ComboPooledDataSource();
	cpds.setDriverClass( "com.mysql.jdbc.Driver" ); 
	cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/test" );
	cpds.setUser("root");                                  
	cpds.setPassword("abc123");
	
	//
	cpds.setMaxPoolSize(100);
	
	Connection conn = cpds.getConnection();
	System.out.println(conn);
}

}

在这里插入图片描述
c3p0配置文件代码
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<named-config name="helloc3p0">
		<!-- 数据库连接的4个基本信息 -->
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///test</property>
		<property name="user">root</property>
		<property name="password">abc123</property>

		<!-- 涉及数据库连接池管理的其他信息 -->
		<!-- 当数据库连接池中的连接不足时,c3p0数据源一次性向数据库服务器申请的连接数 -->
		<property name="acquireIncrement">5</property>
		<!-- 初始化时,数据库连接池中的连接数 -->
		<property name="initialPoolSize">10</property>
		<!-- 连接池中最少的连接数 -->
		<property name="minPoolSize">10</property>
		<!-- 数据库连接池中维护的连接数的最大容量 -->
		<property name="maxPoolSize">100</property>
		<!-- 数据库连接池中,最多维护的Statement的个数 -->
		<property name="maxStatements">50</property>
		<!-- 一次连接中最多可以使用的Statement的个数 -->
		<property name="maxStatementsPerConnection">2</property>

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

使用DBCP数据库连接池技术实现数据库连接

package JavaWeb.JDBC.day3.connection;

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.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.junit.Test;

/**
 * 使用DBCP数据库连接池技术实现数据库连接
 * @author Administrator
 *
 */
public class DBCPTest {
	
	//方式二:使用配置文件
	@Test
	public void testGetConnection2() throws Exception {
		Properties pros = new Properties();
		//方式1:
//		FileInputStream is = new FileInputStream("src/dbcp.properties");
		//方式2:
		InputStream is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
	
	pros.load(is);
	
	DataSource source = BasicDataSourceFactory.createDataSource(pros);
	
	Connection conn = source.getConnection();
	System.out.println(conn);
}

//方式一:
@Test
public void testGetConnection1() throws SQLException {
	BasicDataSource source = new BasicDataSource();
	source.setDriverClassName("com.mysql.jdbc.Driver");
	source.setUrl("jdbc:mysql://localhost:3306/test");
	source.setUsername("root");
	source.setPassword("abc123");
	//
	source.setInitialSize(10);
	//...
	Connection conn = source.getConnection();
	System.out.println(conn);
}

}

在这里插入图片描述
dbcp配置文件则要简单很多,看不懂请学下io流的properties
在这里插入图片描述

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

DAO

DAO: data(base) access object 数据访问对象

不考虑事务的DAO1.0介绍

package JavaWeb.JDBC.day3.dao;

import JavaWeb.JDBC.day3.util.JDBCUtils;

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


public class DAO {

	// 通用的查询,返回多条记录 (version 2.0:考虑到事务)
	public <T> List<T> getForList(Connection conn, Class<T> clazz, String sql, Object... args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<>();
		try {
			// 1.预编译sql语句
			ps = conn.prepareStatement(sql);
			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.调用executeQuery(),获取结果集
			rs = ps.executeQuery();

			// 4.获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			// 5.获取结果集中列的个数
			int columnCount = rsmd.getColumnCount();

			// 6.处理结果集
			while (rs.next()) {// ①判断指针的下一个位置是否有数据 ②如果返回true,指针下移。如果返回false,指针不下移。

				T t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {// 处理列

					Object columnValue = rs.getObject(i + 1);// 获取列值

					String columnLabel = rsmd.getColumnLabel(i + 1);// 获取结果集中列的别名

					// 反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}
				list.add(t);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(null, ps, rs);
		}	
		return null;
	}

	// 通用的查询,返回一条记录 (version 2.0:考虑到事务)
	public <T> T getInstance(Connection conn, Class<T> clazz, String sql, Object... args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 1.预编译sql语句
			ps = conn.prepareStatement(sql);

			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.调用executeQuery(),获取结果集
			rs = ps.executeQuery();

			// 4.获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			// 5.获取结果集中列的个数
			int columnCount = rsmd.getColumnCount();

			// 6.处理结果集
			if (rs.next()) {// ①判断指针的下一个位置是否有数据 ②如果返回true,指针下移。如果返回false,指针不下移。

				T t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {// 处理列

					Object columnValue = rs.getObject(i + 1);// 获取列值

					String columnLabel = rsmd.getColumnLabel(i + 1);// 获取结果集中列的别名
					// 反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);
				}

				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(null, ps, rs);

		}

		return null;
	}

	// 通用的增删改 (version 2.0:考虑到事务)
	public void update(Connection conn, String sql, Object... args) {
		PreparedStatement ps = null;
		try {
			// 1.
			ps = conn.prepareStatement(sql);
			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.执行
			int count = ps.executeUpdate();

			System.out.println("影响了" + count + "条数据");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 4.连接一定不要关闭!
			JDBCUtils.closeResource(null, ps, null);
		}
	}
}

创建CustomerDAO类继承DAO,添加对customers表的增删改查方法
package JavaWeb.JDBC.day3.dao;

import JavaWeb.JDBC.day3.bean.Customer;

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


public class CustomerDAO extends DAO{
	
	
	/**
	 * 查询表中的所有记录
	 * @param conn
	 * @return
	 */
	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;
	}
	
	/**
	 * 查询指定id的对象
	 * @param conn
	 * @param id
	 * @return
	 */
	public Customer getById(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;
	}
	
	/**
	 * 修改数据表中的一条记录
	 * @param conn
	 * @param cust
	 */
	public void updateCustomer(Connection conn,Customer cust) {//cust = new Customer(10,"迪丽热巴",..,..)
		String sql = "update customers set name = ?,email = ?,birth = ? where id = ?";
		update(conn, sql,cust.getName(),cust.getEmail(),cust.getBirth(),cust.getId());
	}
	
	/**
	 * 删除数据表中指定id对应的数据
	 * @param conn
	 * @param id
	 */
	public void deleteById(Connection conn,int id) {
		String sql = "delete from customers where id = ?";
		
		update(conn, sql,id);
		
	}
	
	/**
	 * 向customers表中插入一条数据
	 * @param conn
	 * @param cust
	 */
	public void addCustomer(Connection conn,Customer cust) {
		String sql = "insert into customers(name,email,birth)values(?,?,?)";
		update(conn, sql,cust.getName(),cust.getEmail(),cust.getBirth());
	}
}

创建CustomerDAO的测试类CustomerDAOTest测试类测试以上方法
package JavaWeb.JDBC.day3.dao;

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

import JavaWeb.JDBC.day3.bean.Customer;
import JavaWeb.JDBC.day3.util.JDBCUtils;
import org.junit.Test;


/**
 * CustomerDAO的测试类
 *
 */
public class CustomerDAOTest {
	
	@Test
	public void testGetAll() throws Exception {
		CustomerDAO dao = new CustomerDAO();
		
//		Connection conn = JDBCUtils.getConnection();
//		Connection conn = JDBCUtils.getC3P0Connection();
		Connection conn = JDBCUtils.getDBCPConnection();
		
		List<Customer> list = dao.getAll(conn);
		list.forEach(System.out::println);
		
		JDBCUtils.closeResource(conn, null);
	}

在这里插入图片描述

	@Test
	public void testGetOne() throws Exception {
		CustomerDAO dao = new CustomerDAO();
		
		Connection conn = JDBCUtils.getConnection();
		
		Customer cust = dao.getById(conn, 8);
		
		System.out.println(cust);
		
		JDBCUtils.closeResource(conn, null);
	}

在这里插入图片描述

	@Test
	public void testAdd() throws Exception {
		
		CustomerDAO dao = new CustomerDAO();
		
		Connection conn = JDBCUtils.getConnection();
		Customer cust = new Customer(1,"任鑫","ren@126.com",new Date(1242423423L));
		dao.addCustomer(conn, cust);
		
		JDBCUtils.closeResource(conn, null);
		
	}
	
}

在这里插入图片描述
添加成功
在这里插入图片描述

考虑事务的DAO2.0介绍

反射工具类ReflectionUtil 准备

package JavaWeb.JDBC.day3.dao1;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ReflectionUtil {//反射的工具类
	/**
	 * 获取形参clazz的父类的泛型
	 * @param clazz
	 * @return
	 */
	public static Class getGenericParam(Class clazz) {//Class clazz = CustomerDAO.class
		Type type = clazz.getGenericSuperclass();
		ParameterizedType paramType = (ParameterizedType) type;
		Type[] typeArguments = paramType.getActualTypeArguments();//返回泛型参数构成的数组
		return (Class) typeArguments[0];
	}
}

DAO2.0代码(考虑事务)
package JavaWeb.JDBC.day3.dao1;

import JavaWeb.JDBC.day3.util.JDBCUtils;

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


/*
 * DAO: data(base) access object 数据访问对象
 */
public class DAO<T> {
	
	private Class<T>  clazz = null;
	
	{
		//给clazz赋值
		clazz = ReflectionUtil.getGenericParam(this.getClass());//比如:CustomerDAO
	}

	// 通用的查询,返回一条记录 (version 2.0:考虑到事务)
	public List<T> getForList(Connection conn, String sql, Object... args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<>();
		try {
			// 1.预编译sql语句
			ps = conn.prepareStatement(sql);

			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.调用executeQuery(),获取结果集
			rs = ps.executeQuery();

			// 4.获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			// 5.获取结果集中列的个数
			int columnCount = rsmd.getColumnCount();

			// 6.处理结果集
			while (rs.next()) {// ①判断指针的下一个位置是否有数据 ②如果返回true,指针下移。如果返回false,指针不下移。

				T t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {// 处理列

					Object columnValue = rs.getObject(i + 1);// 获取列值

					String columnLabel = rsmd.getColumnLabel(i + 1);// 获取结果集中列的别名

					// 反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);

				}

				list.add(t);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(null, ps, rs);

		}

		return null;
	}

	// 通用的查询,返回一条记录 (version 2.0:考虑到事务)
	public T getInstance(Connection conn,  String sql, Object... args) {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 1.预编译sql语句
			ps = conn.prepareStatement(sql);

			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.调用executeQuery(),获取结果集
			rs = ps.executeQuery();

			// 4.获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();
			// 5.获取结果集中列的个数
			int columnCount = rsmd.getColumnCount();

			// 6.处理结果集
			if (rs.next()) {// ①判断指针的下一个位置是否有数据 ②如果返回true,指针下移。如果返回false,指针不下移。

				T t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {// 处理列

					Object columnValue = rs.getObject(i + 1);// 获取列值

					String columnLabel = rsmd.getColumnLabel(i + 1);// 获取结果集中列的别名

					// 反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnValue);

				}

				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(null, ps, rs);

		}

		return null;
	}

	// 通用的增删改 (version 2.0:考虑到事务)
	public void update(Connection conn, String sql, Object... args) {
		PreparedStatement ps = null;
		try {
			// 1.
			ps = conn.prepareStatement(sql);
			// 2.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 3.执行
			int count = ps.executeUpdate();

			System.out.println("影响了" + count + "条数据");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 4.连接一定不要关闭!
			JDBCUtils.closeResource(null, ps, null);
		}
	}
}

另外两个CustomerDAO和CustomerDAOTest类代码不变

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值