当前位置:网站首页>JDBC原理

JDBC原理

2022-07-06 10:58:00 丸酸菌

數據庫連接方式

如果是如果驅動包版本是8.x的話,properties文件中的driverClass的路徑就是com.mysql.cj.jdbc.Driver,不是原來的com.mysql.jdbc.Driver

方式一:Driver實現類對象獲取連接

	@Test
	public void testConnection1() throws SQLException {
    
		// 獲取Driver實現類對象
		Driver driver = new com.mysql.jdbc.Driver();
		// url:jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
		// `jdbc:mysql`:協議
		// localhost:ip地址
		// 3306:默認mysql的端口號
		// test:test數據庫
		String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
		// 將用戶名和密碼封裝在Properties中
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "abc123");

		Connection conn = driver.connect(url, info);

		System.out.println(conn);
	}

說明:上述代碼中顯式出現了第三方數據庫的API

方式二:“方式一的迭代”,不出現第三方的api使得程序具有更好的可移植性

	@Test
	public void testConnection2() throws Exception {
    
		// 1.獲取Driver實現類對象:使用反射
//調用Class的靜態方法獲取Class類的實例:forName(String classPath)
		Class clazz = Class.forName("com.mysql.jdbc.Driver");
//調用Class對象的newInstance()方法獲取運行時類(new com.mysql.jdbc.Driver())的對象
		Driver driver = (Driver) clazz.newInstance();

		// 2.提供要連接的數據庫
		String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";

		// 3.提供連接需要的用戶名和密碼
		Properties info = new Properties();
		info.setProperty("user", "root");
		info.setProperty("password", "abc123");

		// 4.獲取連接
		Connection conn = driver.connect(url, info);
		System.out.println(conn);

	}

說明:相較於方式一,這裏使用反射實例化Driver,不在代碼中體現第三方數據庫的API。體現了面向接口編程思想。

方式三:DriverManager替換Driver

	
	@Test
	public void testConnection3() throws Exception {
    
		// 1.獲取Driver實現類的對象
		Class clazz = Class.forName("com.mysql.jdbc.Driver");
		Driver driver = (Driver) clazz.newInstance();

		// 2.提供另外三個連接的基本信息:
		String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
		String user = "root";
		String password = "abc123";

		// 注册驅動
		DriverManager.registerDriver(driver);

		// 獲取連接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
	}
	

說明:使用DriverManager實現數據庫的連接。體會獲取連接必要的4個基本要素。

方式四:加載驅動,不用顯示注册驅動。

	@Test
	public void testConnection4() throws Exception {
    
		// 1.提供三個連接的基本信息:
		String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
		String user = "root";
		String password = "abc123";
		
		// 2.加載Driver
		Class.forName("com.mysql.jdbc.Driver");
		//相較於方式三,可以省略如下的操作:
// Driver driver = (Driver) clazz.newInstance();
// // 注册驅動
// DriverManager.registerDriver(driver);
		//為什麼可以省略上述操作呢?
		/* * 在mysql的Driver實現類中,聲明了如下的操作: * static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } */

		// 3.獲取連接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
	}
	

說明:不必顯式的注册驅動了。因為在DriverManager的源碼中已經存在靜態代碼塊,實現了驅動的注册。

方式五(final版):將數據庫連接需要的4個基本信息聲明在配置文件中,通過讀取配置文件的方式,獲取連接

/*此種方式的好處? * 1.實現了數據與代碼的分離。實現了解耦 * 2.如果需要修改配置文件信息,可以避免程序重新打包。*/
	@Test
	public void getConnection5() throws Exception{
    
		//1.讀取配置文件中的4個基本信息
//.class獲取Class類的實例
//getClassLoader獲取類的系統類加載器
//getResourceAsStream獲取類路徑下的指定文件的輸入流
		InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
		
		Properties pros = new Properties();
		pros.load(is);
		
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String url = pros.getProperty("url");
		String driverClass = pros.getProperty("driverClass");
		
		//2.加載驅動--加載Driver
		Class.forName(driverClass);
		// 注册驅動 Driver實現類中聲明了靜態代碼塊
		//3.獲取連接
		Connection conn = DriverManager.getConnection(url, user, password);
		System.out.println(conn);
		
		

其中,配置文件聲明在工程的src目錄下:【jdbc.properties】

user=root
password=abc123
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
driverClass=com.mysql.jdbc.Driver

說明:使用配置文件的方式保存配置信息,在代碼中加載配置文件

使用配置文件的好處:
①實現了代碼和數據的分離,如果需要修改配置信息,直接在配置文件中修改,不需要深入代碼
②如果修改了配置信息,省去重新編譯的過程。

PreparedStatement查詢

jdbc.properties

user=root
password=abc123
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
driverClass=com.mysql.jdbc.Driver

針對於Customers錶的增删改操作

public class PreparedStatementUpdateTest {
    

	
	
	//修改customers錶的一條記錄
	@Test
	public void testUpdate(){
    
		Connection conn = null;
		PreparedStatement ps = null;
		try {
    
			//1.獲取數據庫的連接
			conn = JDBCUtils.getConnection();
			//2.預編譯sql語句,返回PreparedStatement的實例
			String sql = "update customers set name = ? where id = ?";
			ps = conn.prepareStatement(sql);
			//3.填充占比特符
			ps.setObject(1,"莫紮特");
			ps.setObject(2, 18);
			//4.執行
			ps.execute();
		} catch (Exception e) {
    
			e.printStackTrace();
		}finally{
    
			//5.資源的關閉
			JDBCUtils.closeResource(conn, ps);
			
		}
	}
	

	// 向customers錶中添加一條記錄
	@Test
	public void testInsert() {
    
		Connection conn = null;
		PreparedStatement ps = null;
		try {
    
			// 1.讀取配置文件中的4個基本信息
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
			Properties pros = new Properties();
			pros.load(is);

			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.獲取連接
			conn = DriverManager.getConnection(url, user, password);
			//4.預編譯sql語句,返回PreparedStatement的實例
			String sql = "insert into customers(name,email,birth)values(?,?,?)";//?:占比特符
			ps = conn.prepareStatement(sql);
			//5.填充占比特符
			ps.setString(1, "哪吒");
			ps.setString(2, "[email protected]");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			java.util.Date date = sdf.parse("1000-01-01");
			ps.setDate(3, new Date(date.getTime()));
			
			//6.執行操作
			ps.execute();
		} catch (Exception e) {
    
			e.printStackTrace();
		}finally{
    
			//7.資源的關閉
			try {
    
				if(ps != null)
					ps.close();
			} catch (SQLException e) {
    
				e.printStackTrace();
			}
			try {
    
				if(conn != null)
					conn.close();
			} catch (SQLException e) {
    
				e.printStackTrace();
			}
		}
	}
}

封裝JDBCUtils

public class JDBCUtils {
    
	/** * @Description 獲取數據庫的連接 */
	public static Connection getConnection() throws Exception {
    
		// 1.讀取配置文件中的4個基本信息
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");

		Properties pros = new Properties();
		pros.load(is);

		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;
	}
	/** * @Description 關閉連接和Statement的操作 */
	public static void closeResource(Connection conn,Statement ps){
    
		try {
    
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(conn != null)
				conn.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
	}
	/** * @Description 關閉資源操作 */
	public static void closeResource(Connection conn,Statement ps,ResultSet rs){
    
		try {
    
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(conn != null)
				conn.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(rs != null)
				rs.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
	}
}

針對於Customers錶通用的增删改

//通用的增删改操作
	public void update(String sql,Object ...args){
    //sql中占比特符的個數與可變形參的長度相同!
		Connection conn = null;
		PreparedStatement ps = 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.執行
			ps.execute();
		} catch (Exception e) {
    
			e.printStackTrace();
		}finally{
    
			//5.資源的關閉
			JDBCUtils.closeResource(conn, ps);
			
		}
	}

針對於Customers錶的查詢操作返回一條記錄

public class CustomerForQuery {
    
	@Test
	public void testQuery1() {
    
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet resultSet = null;
		try {
    
			conn = JDBCUtils.getConnection();
			String sql = "select id,name,email,birth from customers where id = ?";
			ps = conn.prepareStatement(sql);
			ps.setObject(1, 1);

			// 執行,並返回結果集
			resultSet = ps.executeQuery();
			// 處理結果集
			if (resultSet.next()) {
    // next():判斷結果集的下一條是否有數據,如果有數據返回true,並指針下移;如果返回false,指針不會下移。

				// 獲取當前這條數據的各個字段值
				int id = resultSet.getInt(1);
				String name = resultSet.getString(2);
				String email = resultSet.getString(3);
				Date birth = resultSet.getDate(4);

				// 方式一:
// System.out.println("id = " + id + ",name = " + name + ",email = " + email + ",birth = " + birth);
				// 方式二:
// Object[] data = new Object[]{id,name,email,birth};
				// 方式三:將數據封裝為一個對象(推薦)
				Customer customer = new Customer(id, name, email, birth);
				System.out.println(customer);
			}
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			JDBCUtils.closeResource(conn, ps, resultSet);
		}
	}
//-------------------------------------------------------------------

針對於Customers錶的通用的查詢操作


	public Customer queryForCustomers(String sql, Object... args) {
    
		Connection conn = null;
		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
			ResultSetMetaData rsmd = rs.getMetaData();
			// 通過ResultSetMetaData獲取結果集中的列數
			int columnCount = rsmd.getColumnCount();

			if (rs.next()) {
    
				Customer cust = new Customer();
				// 處理結果集一行數據中的每一個列
				for (int i = 0; i < columnCount; i++) {
    
					// 獲取列值
					Object columValue = rs.getObject(i + 1);

					// 獲取每個列的列名
// String columnName = rsmd.getColumnName(i + 1);
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 給cust對象指定的columnName屬性,賦值為columValue:通過反射
					Field field = Customer.class.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(cust, columValue);
				}
				return cust;
			}
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			JDBCUtils.closeResource(conn, ps, rs);

		}

		return null;

	}


@Test
	public void testQueryForCustomers() {
    
		String sql = "select id,name,birth,email from customers where id = ?";
		Customer customer = queryForCustomers(sql, 13);
		System.out.println(customer);

		sql = "select name,email from customers where name = ?";
		Customer customer1 = queryForCustomers(sql, "周傑倫");
		System.out.println(customer1);
	}

}

未考慮數據庫事務通用的增删改

// ******************未考慮數據庫事務情况下的轉賬操作**************************
	/* * 針對於數據錶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'; */
	@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) {
    // sql中占比特符的個數與可變形參的長度相同!
		Connection conn = null;
		PreparedStatement ps = 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 {
    

			// 修改其為自動提交數據
			// 主要針對於使用數據庫連接池的使用
			try {
    
				conn.setAutoCommit(true);
			} catch (SQLException e) {
    
				e.printStackTrace();
			}

			// 5.資源的關閉
			JDBCUtils.closeResource(conn, ps);

		}
		return 0;

	}

考慮數據庫事務後通用的增删改

	@Test
	public void testUpdateWithTx() {
    
		Connection conn = null;
		try {
    
			conn = JDBCUtils.getConnection();
			System.out.println(conn.getAutoCommit());// true
			// 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) {
    
				e1.printStackTrace();
			}
		} finally {
    
			JDBCUtils.closeResource(conn, null);
		}
	}
//-------------------------------------------------------------------
	// 通用的增删改操作---version 2.0 (考慮上事務)
	public int update(Connection conn, String sql, Object... args) {
    // sql中占比特符的個數與可變形參的長度相同!
		PreparedStatement ps = null;
		try {
    
			// 1.預編譯sql語句,返回PreparedStatement的實例
			ps = conn.prepareStatement(sql);
			// 2.填充占比特符
			for (int i = 0; i < args.length; i++) {
    
				ps.setObject(i + 1, args[i]);// 小心參數聲明錯誤!!
			}
			// 3.執行
			return ps.executeUpdate();
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			// 4.資源的關閉
			JDBCUtils.closeResource(null, ps);

		}
		return 0;

	}

考慮數據庫事務後通用的查詢

public <T> T getInstance(Connection conn, Class<T> clazz, 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();
			// 獲取結果集的元數據 :ResultSetMetaData
			ResultSetMetaData rsmd = rs.getMetaData();
			// 通過ResultSetMetaData獲取結果集中的列數
			int columnCount = rsmd.getColumnCount();

			if (rs.next()) {
    
				T t = clazz.newInstance();
				// 處理結果集一行數據中的每一個列
				for (int i = 0; i < columnCount; i++) {
    
					// 獲取列值
					Object columValue = rs.getObject(i + 1);

					// 獲取每個列的列名
					// String columnName = rsmd.getColumnName(i + 1);
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 給t對象指定的columnName屬性,賦值為columValue:通過反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columValue);
				}
				return t;
			}
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			JDBCUtils.closeResource(null, ps, rs);

		}

		return null;
	}

JDBCUtils(含連接池)

public class JDBCUtils {
    
	/** * @Description 獲取數據庫的連接 */
	public static Connection getConnection() throws Exception {
    
		// 1.讀取配置文件中的4個基本信息
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");

		Properties pros = new Properties();
		pros.load(is);

		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;
	}
//-------------------------------------------------------------------
	/** * 使用Druid數據庫連接池技術 */
	private static DataSource source;
	static{
    
		try {
    
			Properties pros = new Properties();
			
			InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
			
			pros.load(is);
			
			source = DruidDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
    
			e.printStackTrace();
		}
	}
	public static Connection getConnection1() throws SQLException{
    
		Connection conn = source.getConnection();
		return conn;
	}
//-------------------------------------------------------------------
	/** * @Description 使用DBCP數據庫連接池技術獲取數據庫連接 */
	//創建一個DBCP數據庫連接池
	private static DataSource source1;
	static{
    
		try {
    
			Properties pros = new Properties();
			FileInputStream is = new FileInputStream(new File("src/dbcp.properties"));
			pros.load(is);
			source1 = BasicDataSourceFactory.createDataSource(pros);
		} catch (Exception e) {
    
			e.printStackTrace();
		}
	}
	public static Connection getConnection2() throws Exception{
    
		Connection conn = source1.getConnection();
		return conn;
	}
//-------------------------------------------------------------------
	/** * @Description 使用C3P0的數據庫連接池技術 */
	//數據庫連接池只需提供一個即可。
	private static ComboPooledDataSource cpds = new ComboPooledDataSource("hellc3p0");
	public static Connection getConnection4() throws SQLException{
    
		Connection conn = cpds.getConnection();
		return conn;
	}
//-------------------------------------------------------------------
//-------------------------------------------------------------------
//-------------------------------------------------------------------
	/** * @Description 關閉連接和Statement的操作 */
	public static void closeResource(Connection conn,Statement ps){
    
		try {
    
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(conn != null)
				conn.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
	}
	/** * @Description 關閉ResultSet結果集資源操作 */
	public static void closeResource(Connection conn,Statement ps,ResultSet rs){
    
		try {
    
			if(ps != null)
				ps.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(conn != null)
				conn.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
		try {
    
			if(rs != null)
				rs.close();
		} catch (SQLException e) {
    
			e.printStackTrace();
		}
	}
//-------------------------------------------------------------------
	/** * @Description 使用dbutils.jar中提供的DbUtils工具類,實現資源的關閉 */
	public static void closeResource1(Connection conn,Statement ps,ResultSet rs){
    
// try {
    
// DbUtils.close(conn);
// } catch (SQLException e) {
    
// e.printStackTrace();
// }
// try {
    
// DbUtils.close(ps);
// } catch (SQLException e) {
    
// e.printStackTrace();
// }
// try {
    
// DbUtils.close(rs);
// } catch (SQLException e) {
    
// e.printStackTrace();
// }
		
		DbUtils.closeQuietly(conn);
		DbUtils.closeQuietly(ps);
		DbUtils.closeQuietly(rs);
	}
}

BaseDAO/DAO

DAO: data(base) access object

/** * 封裝了針對於數據庫進行通用的基本操作 */
public abstract class BaseDAO<T> {
    
//獲取泛型T的Class對象,獲取泛型的類型,泛型是在被子類繼承時才確定
	private Class<T> clazz ;

// public BaseDAO(){
    
// 
// }

	{
    	
		
//通過this獲取所屬類再獲取所屬類的父類,在强轉成帶泛型的父類,在獲取泛型數組,再取第一個泛型類型 
//因為此類是抽象類被子類繼承,當子類對象被創建時會調用父類構造函數時調用靜態方法或者構造器方法
//此時傳遞的this值是調用類的值也就是繼承類的值或者說是繼承父類的子類的值)
		// this.getClass()獲取調用父類的子類類型
		// getGenericSuperclass()用來獲取當前類的父類的類型
		//獲取當前BaseDAO的子類繼承的父類中的泛型
		Type genericSuperclass = this.getClass().getGenericSuperclass();
		
		// ParameterizedType錶示的是帶泛型的類型
		ParameterizedType paramType = (ParameterizedType) genericSuperclass;
		
		//獲取了父類的泛型參數
		// getActualTypeArguments獲取具體的泛型的類型
		// 這個方法會返回一個Type類型的泛型數組
		Type[] typeArguments = paramType.getActualTypeArguments();
		
		//獲取具體的泛型的類型·泛型的第一個參數
		clazz = (Class<T>) typeArguments[0];
	}
	
//-------------------------------------------------------------------
	// 通用的增删改操作---version 2.0 (考慮上事務)
	public int update(Connection conn, String sql, Object... args) {
    
	// sql中占比特符的個數與可變形參的長度相同!
		PreparedStatement ps = null;
		try {
    
			// 1.獲取PreparedStatement的實例,預編譯sql語句
			ps = conn.prepareStatement(sql);
			// 2.填充占比特符
			for (int i = 0; i < args.length; i++) {
    
				ps.setObject(i + 1, args[i]);//Object防止參數聲明錯誤
			}
			// 3.執行executeUpdate返回操作行數
			return ps.executeUpdate();
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			// 4.資源的關閉
			JDBCUtils.closeResource(null, ps);
		}
		return 0;
	}
//-------------------------------------------------------------------
	// 通用的查詢操作,用於返回數據錶中的一條記錄(version 2.0:考慮上事務)
	public T getInstance(Connection conn, String sql, Object... args) {
    
		//
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
    
			// 1.獲取PreparedStatement()的實例,預編譯sql語句
			ps = conn.prepareStatement(sql);
			// 2.填充占比特符
			for (int i = 0; i < args.length; i++) {
    
				ps.setObject(i + 1, args[i]);
			}
			// 3.執行executeQuery()返回ResultSet結果集對象
			rs = ps.executeQuery();
			// getMetaData()獲取結果集的元數據 :ResultSetMetaData
			ResultSetMetaData rsmd = rs.getMetaData();
			// 通過元數據getColumnCount()獲取結果集中的列數
			int columnCount = rsmd.getColumnCount();
			// 4.處理結果集行數據,判斷結果集的下一條是否有數據,如果有數據返回true,並指針下移;如果返回false,指針不會下移。
			if (rs.next()) {
    
				//創建返回值T類型的對象
				T t = clazz.getDeclaredConstructor().newInstance();
				// 5. 處理結果集一行數據中的每一個列
				for (int i = 0; i < columnCount; i++) {
    
					// 獲取列值
					Object columValue = rs.getObject(i + 1);

					// 獲取每個列的列名
					// String columnName = rsmd.getColumnName(i + 1);
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 給t對象指定的columnLabel屬性,賦值為columValue:通過反射
					//當前clazz的值是子類繼承父類中定義泛型的值(詳細看代碼頭部)
					//getDeclaredField()調用私有的屬性,獲取運行時類中指定變量名的屬性
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columValue);
				}
				return t;
			}
		} catch (Exception e) {
    
			e.printStackTrace();
		} finally {
    
			JDBCUtils.closeResource(null, ps, rs);
		}
		return null;
	}
//-------------------------------------------------------------------
// 通用的查詢操作,用於返回數據錶中的多條記錄構成的集合(version 2.0:考慮上事務)
	public List<T> getForList(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();
			// 獲取結果集的元數據 :ResultSetMetaData
			ResultSetMetaData rsmd = rs.getMetaData();
			// 通過ResultSetMetaData獲取結果集中的列數
			int columnCount = rsmd.getColumnCount();
			// 創建集合對象
			ArrayList<T> list = new ArrayList<T>();
			while (rs.next()) {
    
				T t = clazz.getDeclaredConstructor().newInstance();
				// 處理結果集一行數據中的每一個列:給t對象指定的屬性賦值
				for (int i = 0; i < columnCount; i++) {
    
					// 獲取列值
					Object columValue = rs.getObject(i + 1);

					// 獲取每個列的列名
					// String columnName = rsmd.getColumnName(i + 1);
					String columnLabel = rsmd.getColumnLabel(i + 1);

					// 給t對象指定的columnName屬性,賦值為columValue:通過反射
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columValue);
				}
				list.add(t);
			}

			return list;
		} 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()){
    
				return (E) rs.getObject(1);
			}
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			JDBCUtils.closeResource(null, ps, rs);
		}
		return null;
	}	
}

DbUtils

/* * commons-dbutils 是 Apache 組織提供的一個開源 JDBC工具類庫,封裝了針對於數據庫的增删改查操作 * */
public class QueryRunnerTest {
    
	
	//測試插入
	@Test
	public void testInsert() {
    
		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, "蔡徐坤","[email protected]","1997-09-08");
			System.out.println("添加了" + insertCount + "條記錄");
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	//測試查詢
	/* * BeanHander:是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 = ?";
			BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
			Customer customer = runner.query(conn, sql, handler, 23);
			System.out.println(customer);
		} catch (SQLException e) {
    
			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, 23);
			list.forEach(System.out::println);
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			
			JDBCUtils.closeResource(conn, null);
		}
		
	}
	
	/* * MapHander:是ResultSetHandler接口的實現類,對應錶中的一條記錄。 * 將字段及相應字段的值作為map中的key和value */
	@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, 23);
			System.out.println(map);
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			JDBCUtils.closeResource(conn, null);
			
		}
		
	}
	
	/* * MapListHander:是ResultSetHandler接口的實現類,對應錶中的多條記錄。 * 將字段及相應字段的值作為map中的key和value。將這些map添加到List中 */
	@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, 23);
			list.forEach(System.out::println);
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			JDBCUtils.closeResource(conn, null);
			
		}
		
	}
	/* * ScalarHandler:用於查詢特殊值 */
	@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) {
    
			e.printStackTrace();
		}finally{
    
			JDBCUtils.closeResource(conn, null);
			
		}
		
	}
	@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) {
    
			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 = ?";
			ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>(){
    

				@Override
				public Customer handle(ResultSet rs) throws SQLException {
    
// System.out.println("handle");
// return null;
					
// return new Customer(12, "成龍", "[email protected]", new Date(234324234324L));
					
					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,23);
			System.out.println(customer);
		} catch (SQLException e) {
    
			e.printStackTrace();
		}finally{
    
			JDBCUtils.closeResource(conn, null);
			
		}
		
	}
	
}

原网站

版权声明
本文为[丸酸菌]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060912228651.html