初学者:Java中jdbc的封装

第一次写博客,如果有人看觉得写得好那就点赞关注收藏走一波哈哈哈,如果没人看那就权当复习了。。。。

在刚学习数据库知识的时候发现每次对数据库进行操作时都要进行连接,关闭等等一系列重复的代码编写。每次都需要经历加载驱动,获取连接,获取编译对象,执行sql语句,处理结果集、关闭资源这经典六步。而这其中很多代码是在重复使用的。
如下:`
package com.zwq.boke;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class ClectOracle {
public static void main(String[] args){
Connection connect =null ;//连接
Statement statement =null ;//编译
ResultSet resultSet = null;//结果集

    //第一步:加载驱动
    try {
		Class.forName("oracle.jdbc.OracleDriver");
	
    
    //第二部:获取连接
		connect=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORCL","scott","a");
    //第三步:获取执行语句对象
    try {
		statement=connect.createStatement();
	} catch (SQLException e) {
		e.printStackTrace();
	}
    //第四部:执行sql语句
    String sql="select * from reg";
		resultSet=statement.executeQuery(sql);
    //第五步:处理结果集
    while(resultSet.next()){
    	String id=resultSet.getString("rid");
    	String pwd=resultSet.getString("rpwd");
    	System.out.println(id+"====="+pwd);
    	}
    } catch (Exception e) {
		e.printStackTrace();
	}finally {
        //第六步:关闭资源
        try {
            if (resultSet!=null) resultSet.close();
            if (statement!=null) statement.close();
            if (connect!=null) connect.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
     }
}

}
像上面的代码我们每次对数据库进行操作都需要获取连接,关闭资源等等重复的操作。如果我们将这些重复的代码进行封装。我们每次只需要将sql语句,和相应的数据作为参数传递进方法中可以大大地节省我们的开发时间。(当然这是在你还没有学习orm框架之前…)。废话不多说,开始封装!
首先,先创建一个DbHelp类。将JDBC连接数据库的第一步加载驱动放入静态块中。第二步获取连接,第三步获取编译对象,第六步关闭资源放入静态方法中,代码如下
`public class DBHelper {
//这一步对应jdbc连接数据库库的第一步
static{
try{
Class.forName(“oracle.jdbc.driver.OracleDriver”);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
/*
* 获取数据库连接的方法对应第二步
/
private Connection getConnection(){
Connection con=null;
try {
con=DriverManager.getConnection(“jdbc:oracle:thin:@127.0.0.1:1521:ORCL”,“scott”,“a”);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
/
*
*对应jdbc连接数据库的第三步
* 给预编译语句的占位符?赋值
* @param pstmt 要赋值的预编译块
* @param params 给占位符的值
*/
private void setParams(PreparedStatement pstmt,Object … params){
if(params!=null&&params.length>0){
for(int i=0,len=params.length;i<len;i++){
try {
pstmt.setObject(i+1, params[i]);
} catch (SQLException e) {
System.out.println(“第”+(i+1)+“个注值失败”+e.getMessage());
e.printStackTrace();
}
}
}
}
//第三步的重载方法
private void setParams(PreparedStatement pstmt,List params){
if(params!=null&&params.size()>0){
for(int i=0,len=params.size();i<len;i++){
try {
pstmt.setObject(i+1, params.get(i));
} catch (SQLException e) {
System.out.println(“第”+(i+1)+“个注值失败”+e.getMessage());
e.printStackTrace();
}
}
}
}

/**
 * 关闭资源的方法---对应jdbc连接数据库的第六步
 * @param rs 要关闭的结果集
 * @param pstmt 要编译的预编译块
 * @param con 要关闭的连接
 */
private void close(ResultSet rs,PreparedStatement pstmt,Connection con){
	if(rs!=null){
		try {
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	if(pstmt!=null){
		try {
			pstmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	if(con!=null){
		try {
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

/**
 * 关闭资源的方法
 * @param pstmt 要编译的预编译块
 * @param con 要关闭的连接
 */
private void close(PreparedStatement pstmt,Connection con){		
	if(pstmt!=null){
		try {
			pstmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	if(con!=null){
		try {
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}在这里插入代码片`

为什么驱动加载要放入静态块中呢?因为我们驱动只需加载一次,并且必须先执行。在new一个DbHelp对象时,也会先执行静态快中的代码。补充下静态快和代码块的知识点0.0。如下
在这里插入图片描述
运行上面代码结果如下
在这里插入图片描述
可以看出即使代码块写在前边。先运行的还是静态快。new了两个A对象。静态块也只会运行一次。这和jdbc连接数据库第一步的要求完美匹配。
为什么这些步骤的封装方法都是私有的?因为我不希望外边能调用这些方法。这些方法只需在内部调用即可。如果外部调用可能会冒出一些想不到的异常。。。
第三步预编译的封装中三个点的含义--------见连接可变长参数
第三步预编译的重载含义:方便接受不同的参数类型。可以是list集合,也可以是散装的。主要是为了方便,也符合java的多态性
第六步关闭资源的重载的含义:可以看到两个方法的参数不一样,其中一个方法的参数中有resultset,另一个没有。因为当我们只有查找的时候才会有结果集。增删改都不会有结果集。所以有结果集的时候才会关闭结果集资源。没有就不会关闭。
然后我们对增删改查的方法进行封装。这些方法设为public。外部只需调用这些方法就可以对数据库进行操作代码如下:

/**
	 * 更新数据的方法
	 * @param sql 要执行的sql语句
	 * @param params 要执行的sql语句中对应占位符?的值,在添加是必须按照sql语句中?的顺序给定
	 * @return 语句执行后,影响的数据的行数
	 */
	public int update(String sql,List<Object> params){
		int result=0;
		
		Connection con=null;
		PreparedStatement pstmt=null;
		try{
			con=this.getConnection(); //获取数据库的连接
			pstmt=con.prepareStatement(sql); //预编译执行语句
			//给预编译sql语句中的占位符赋值
			setParams(pstmt,params);
			//执行更新并获取结果
			result=pstmt.executeUpdate();
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			close(pstmt,con);
		}
		return result;
	}
	
	/**
	 * 根据结果集对象获取这个结果集中每个列的列名,并以数组的方式返回
	 * @param rs 要获取每个列列名的结果集对象
	 * @return 存放了这个结果集中所有列的列名的一个字符串数组
	 * @throws SQLException
	 */
	public String[] getColumnName(ResultSet rs) throws SQLException{
		ResultSetMetaData rsmd=rs.getMetaData();
		int len =rsmd.getColumnCount();//获取给定结果集中列的数量
		String[] colNames=new String[len];
		//循环取出每个列的列名存放到colName数组中
		for(int i=0;i<len;i++){
			colNames[i]=rsmd.getColumnName(i+1).toLowerCase();//将每个列的列名全部转为小写字母
		}
		return colNames;
	}
	
	/**
	 * 查询
	 * @param sql 要执行的查询语句
	 * @param params 查询语句中对应?的 值
	 * @return  返回list一行数据,通过列名查询到的(所有数据存放在一个list中,每一行数据存放在一个map中)
	 */
	public List<Map<String,Object>> finds(String sql,List<Object> params){
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			Map<String,Object> map=null;
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			while(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,Object>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getObject(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中
				list.add(map);
				map=null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return list;
	}
	
	public Map<String,String> find(String sql,List<Object> params){
		Map<String,String> map=null;
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			if(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,String>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getString(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return map;
	}
	public List<Map<String,Object>> finds(String sql,Object ... params){
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			Map<String,Object> map=null;
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			while(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,Object>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getObject(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中
				list.add(map);
				map=null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return list;
	}
	
	public Map<String,String> find(String sql,Object ... params){
		Map<String,String> map=null;
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			if(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,String>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getString(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return map;
	}
在这里插入代码片

这一堆代码中对增删改查进行了封装。其中增删改的操作封装在update中。这个方法的思路见方法体中的注解。在我们对数据库进行增加,修改,删除操作时。会执行PreparedStatement类中的executeUpdate()方法。如果返回的数字是1,表示增删改成功。如果是0则表示失败。。
为什么要对查找方法进行重载呢?因为在我们的实际应用有时我们只需要查找一条数据。大部分时候我们需要查找多条数据。我们首先通过getColumnName(Rs)方法或获取列名,**因为在对结果集进行操作的时候我们需要通过列名来获取。**然后在find方法中通过列名获取结果集,将每一行的数据村放入一个map中。每一行对应一个map。再将map村放入list中就能获取结果集中的所有内容。详情看代码注解。。。(嘻嘻,偷懒一下)。至此我们jdbc操作数据库的方法封装完成。完整代码如下

package com.zwq.boke;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DBHelper {
	static{
		try{
			Class.forName("oracle.jdbc.driver.OracleDriver");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
	}
	/*
	 * 获取数据库连接的方法
	 */
	private Connection getConnection(){
		Connection con=null;
		try {
			con=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORCL","scott","a");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return con;
	}
	/**
	 * 给预编译语句的占位符?赋值
	 * @param pstmt 要赋值的预编译块
	 * @param params 给占位符的值
	 */
	private void setParams(PreparedStatement pstmt,Object ... params){
		if(params!=null&&params.length>0){
			for(int i=0,len=params.length;i<len;i++){
				try {
					pstmt.setObject(i+1, params[i]);
				} catch (SQLException e) {
					System.out.println("第"+(i+1)+"个注值失败"+e.getMessage());
					e.printStackTrace();
				}
			}
		}
	}
	private void setParams(PreparedStatement pstmt,List<Object> params){
		if(params!=null&&params.size()>0){
			for(int i=0,len=params.size();i<len;i++){
				try {
					pstmt.setObject(i+1, params.get(i));
				} catch (SQLException e) {
					System.out.println("第"+(i+1)+"个注值失败"+e.getMessage());
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 关闭资源的方法
	 * @param rs 要关闭的结果集
	 * @param pstmt 要编译的预编译块
	 * @param con 要关闭的连接
	 */
	private void close(ResultSet rs,PreparedStatement pstmt,Connection con){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(pstmt!=null){
			try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 关闭资源的方法
	 * @param pstmt 要编译的预编译块
	 * @param con 要关闭的连接
	 */
	private void close(PreparedStatement pstmt,Connection con){		
		if(pstmt!=null){
			try {
				pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(con!=null){
			try {
				con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * 更新数据的方法
	 * @param sql 要执行的sql语句
	 * @param params 要执行的sql语句中对应占位符?的值,在添加是必须按照sql语句中?的顺序给定
	 * @return 语句执行后,影响的数据的行数
	 */
	public int update(String sql,List<Object> params){
		int result=0;
		
		Connection con=null;
		PreparedStatement pstmt=null;
		try{
			con=this.getConnection(); //获取数据库的连接
			pstmt=con.prepareStatement(sql); //预编译执行语句
			//给预编译sql语句中的占位符赋值
			setParams(pstmt,params);
			//执行更新并获取结果
			result=pstmt.executeUpdate();
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			close(pstmt,con);
		}
		return result;
	}
	
	/**
	 * 根据结果集对象获取这个结果集中每个列的列名,并以数组的方式返回
	 * @param rs 要获取每个列列名的结果集对象
	 * @return 存放了这个结果集中所有列的列名的一个字符串数组
	 * @throws SQLException
	 */
	public String[] getColumnName(ResultSet rs) throws SQLException{
		ResultSetMetaData rsmd=rs.getMetaData();
		int len =rsmd.getColumnCount();//获取给定结果集中列的数量
		String[] colNames=new String[len];
		//循环取出每个列的列名存放到colName数组中
		for(int i=0;i<len;i++){
			colNames[i]=rsmd.getColumnName(i+1).toLowerCase();//将每个列的列名全部转为小写字母
		}
		return colNames;
	}
	
	/**
	 * 查询
	 * @param sql 要执行的查询语句
	 * @param params 查询语句中对应?的 值
	 * @return  返回list一行数据,通过列名查询到的(所有数据存放在一个list中,每一行数据存放在一个map中)
	 */
	public List<Map<String,Object>> finds(String sql,List<Object> params){
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			Map<String,Object> map=null;
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			while(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,Object>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getObject(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中
				list.add(map);
				map=null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return list;
	}
	
	public Map<String,String> find(String sql,List<Object> params){
		Map<String,String> map=null;
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			if(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,String>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getString(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return map;
	}
	public List<Map<String,Object>> finds(String sql,Object ... params){
		List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			Map<String,Object> map=null;
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			while(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,Object>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getObject(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中
				list.add(map);
				map=null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return list;
	}
	
	public Map<String,String> find(String sql,Object ... params){
		Map<String,String> map=null;
		Connection con=null; 
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		
		try {
			con=getConnection();  //获取连接
			pstmt=con.prepareStatement(sql); //预编译查询语句
			setParams(pstmt,params); //给预编译语句的占位符赋值
			rs=pstmt.executeQuery();//执行查询语句并获取结果集
			String[] colNames=getColumnName(rs); //获取结果集中每个列的列名
			//处理结果
			if(rs.next()){
				//每循环一次就是一行数据,我们需要将这一行数据的每一个列中的值存放到一个map中,以列名为键,以这一列的值为值
				map=new HashMap<String,String>();
				
				//通过列名循环取出每一个列
				for(String colName:colNames){
					map.put(colName, rs.getString(colName));
				}
				//当所有列已经循环取完后,说明这一条数据已经取完了,那么我们将这一条数据存放到list中				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			close(rs,pstmt,con);
		}
		return map;
	}
}

在这里插入代码片

实际操作一下
增加一行数据
结果为1说明插入数据成功。
结果为1说明插入数据成功。
查看一下数据库
在这里插入图片描述
删除一行数据
删除成功
删除成功
删除成功
查找一行数据
查找单行数据成功
查找单行数据成功
查找多行数据
查找多行数据成功
查找多行数据成功
至此,jdbc连接数据库的封装已经基本完成。这段代码连接的是oracle数据库。不同的数据库需要修改相应的数据,大家自己琢磨。在没有学习orm框架之前。这段代码的作用还是挺大的。大家可以拿去使用。并且还有很多可以完善的地方。大家可以更具自己的需求进行修改。如果觉得有用,大家可以点赞关注收藏走一波哈哈哈哈。。。。终于写完了,难忘的第一次,溜了溜了。。。。

猜你喜欢

转载自blog.csdn.net/weixin_42525456/article/details/86635431
今日推荐