通过对JDBC操作数据库的学习,我们会发现,由于JDBC操作数据库的步骤基本没有大的变化,针对所有的数据访问操作,都会存在大量重复代码,因此,对操作数据库的步骤封装就显得十分有必要了,如下:

准备属性文件

为了不用修改java源代码,可以将连接数据库的常见字符串直接配置到properties文件中:
在项目的src根目录下新建一个jdbc.properties文件。
文件内容:
#mysql connection config
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mydb
user=root
password=123456
maxActive=10
minIdle=1
maxWait=10000

DAO与VO模式

DAO(Data Access Object):数据访问对象,在实际开发中由于项目的结构复杂,一般会项目进行分层实现,常见的MVC模式为:Model、View、Controller等三层,而对数据的访问操作一般位于Model层,称之为数据模型,因此对操作数据的步骤一般也会在一个特定的位置一并处理,这一层我们称之为DAO层,该层为直接访问数据库,执行相关表的CRUD操作,不参与任何业务逻辑的实现,只负责操作数据库表中的数

连接池技术与Druid

由于数据库连接是一种资源,这种资源在使用前必须先创建,而这个创建过程是存在时间和空间的开销的,如果每次在执行数据库访问时都创建连接,并且使用完后要关闭连接,这个过程必然是效率低下的;因此,在实际开发中可以考虑在进行数据库操作前,先提前创建并维护一批数据库连接对象,当需要使用时,从这批对象中获取一个连接,用完之后再返还,从而避免了不必要的时间开销,提高程序的运行效率,这种技术在JDBC中称之为连接池技术(Connection Pool)。
Druid连接池使用前先导入Druid的依赖:druid-1.1.9.jar(或者其他版本)

反射

反射是java中类的一种自省机制,通过反射可以在运行时获取类中的成分,并且使用,从而提高了java的动态性;java中任何一个类都有一个对应的java.lang.Class对象,这个对象包含了类中的所有成分(属性,构造器,方法,注解等)

基于以上等多个知识对数据库操作进行封装

封装DBUtils

public class DBUtils {

	public static String driverClass;
	public static String url;
	public static String user;
	public static String password;
	public static int maxActive;
	public static int minIdle;
	public static long maxWait;
	private static DruidDataSource dataSource;

	static{
			init();
	}
	
	public static void init(){
		try {
			Properties prop=new Properties();
			InputStream is=DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
			prop.load(is);
			driverClass=prop.getProperty("driverClass");
			url=prop.getProperty("url");
			user=prop.getProperty("user");
			password=prop.getProperty("password");
			
			maxActive=Integer.parseInt(prop.getProperty("maxActive"));
			minIdle=Integer.parseInt(prop.getProperty("minIdle"));
			maxWait=Long.parseLong(prop.getProperty("maxWait"));
			
			dataSource=new DruidDataSource();
			dataSource.setDriverClassName(driverClass);
			dataSource.setUrl(url);
			dataSource.setUsername(user);
			dataSource.setPassword(password);
			dataSource.setMaxActive(maxActive);
			dataSource.setMinIdle(minIdle);
			dataSource.setMaxWait(maxWait);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static synchronized Connection getConn() {
		if(dataSource==null||dataSource.isClosed()){
			init();
		}
			try {
				return dataSource.getConnection();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		
	}
	
	public static void close(ResultSet rs,Statement stat,Connection conn){
		if(dataSource!=null){
			dataSource.close();
		}
	}
	
	//封装增删改操作
	public static int exeUpdate(String sql,Connection conn,Object... params){
		PreparedStatement ps=null;
		try {
			ps=conn.prepareStatement(sql);
			if(Objects.nonNull(params)){
				for(int i=0;i<params.length;i++){
					ps.setObject(i+1, params[i]);
				}
			}
			int i=ps.executeUpdate();
			return i;
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			close(null,ps,null);
		}
		return 0;
	}
	
	public static <T> List<T> query(String sql,CallBack callback,Object... params){
		List list=null;
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		try {
		    conn=getConn();
			ps=conn.prepareStatement(sql);
			if(Objects.nonNull(params)){
				for(int i=0;i<params.length;i++){
					ps.setObject(i+1, params[i]);
				}
			}
			rs=ps.executeQuery();
			list=callback.call(rs);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			close(rs,ps,conn);
		}
		return list;
		
	}
	
	//内部接口,里面包含一个函数
	public interface CallBack{
		List call(ResultSet rs) throws SQLException;
	}
	
	
	//封装通用的查询集合操作,对任何形式的查询,都能返回一个集合对象
	//t:需要返回的数据类型
	//sql:查询目标语句
	//params:执行查询所需的参数
	//返回指定对象
	public static <T> List<T> queryList(Class<T> t,String sql,Object... params){
		//声明空集合
		List<T> data=new ArrayList<>();
		//获取查询结果信息
		List<Map<String,Object>> list=getDataPair(sql,params);
		if(list.isEmpty()){
			return data;
		}
		for(Map<String,Object> map:list){
			T obj=parseMapToBean(map,t);
			data.add(obj);
		}
		
		return data;
	}
	
	//封装通用的查询对象操作,对任何形式的查询,都能返回一个确定的对象
    public static <T> T queryOne(Class<T> t,String sql,Object... params){
    	List<Map<String,Object>> list=getDataPair(sql,params);
		if(!list.isEmpty()){
			Map<String,Object> map=list.get(0);
			T obj=parseMapToBean(map,t);
			return obj;
		}
    	return null;
	}
    
    //将一个map集合对象转换为javaBean并返回
    private static <T>T parseMapToBean(Map<String, Object> map, Class<T> t) {
		T obj=null;
    	try {
    		//创建一个空实例
			obj=t.newInstance();
			//获取map集合的键集(所以列名称,即要返回对象的属性名)
			Set<String> keys=map.keySet();
			for(String cname:keys){
				//获取属性对象
				Field f=t.getDeclaredField(cname);
			    //获取set方法名称
				String setMethodName="set"+cname.substring(0,1).toUpperCase()+cname.substring(1);
			    //获取set方法对象
				Method method=t.getMethod(setMethodName, f.getType());
				//执行方法
		        method.invoke(obj, map.get(cname));
				
			}
			
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return obj;
	}

	private static List<Map<String,Object>> getDataPair(String sql,Object... params){
    	Connection conn=null;
    	PreparedStatement ps=null;
    	ResultSet rs=null;
    	List<Map<String,Object>> list=new ArrayList<>();
    	try {
			conn=getConn();
			ps=conn.prepareStatement(sql);
			if(Objects.nonNull(params)){
				for(int i=0;i<params.length;i++){
					ps.setObject(i+1, params[i]);
				}
			}
			rs=ps.executeQuery();
			//获取结果集元数据
			ResultSetMetaData rsmd=rs.getMetaData();
			//获取列总数,列名称,获取标签名,获取列值,将相关数据存储到map集合
			//获取总列数
			int count=rsmd.getColumnCount();
			
			while(rs.next()){
				//对结果集每遍历一次,获取一条数据
				Map<String,Object> map=new HashMap<>();
				//遍历每一列
				for(int i=1;i<=count;i++){
					//获取列名称
					String columnName=rsmd.getColumnName(i);
					//获取标签名(别名)
					String columnLabel=rsmd.getColumnLabel(i);
					//获取列值
					Object value=rs.getObject(columnLabel);
					if(Objects.nonNull(value)){
					//将数据存入map
					map.put(columnName, value);
					}
				}
				//将map集合存入List
				list.add(map);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			DBUtils.close(rs, ps, conn);
		}
    	return list;
    }	
}

导入该工具类后可以将对数据库的增删查改操作简化:

public boolean insert(Student stu) {
		String sql="insert into student(sname,sex,age,birthday) values(?,?,?,?)";
		int i=DBUtils.exeUpdate(sql, conn, stu.getSname(),stu.getSex(),stu.getAge(),stu.getBirthday());
		return i>0;
	}
public boolean update(Student stu) {
		String sql="update student set age=? where sname=?";
		int i=DBUtils.exeUpdate(sql, conn, stu.getAge(),stu.getSname());
		return i>0;
	}
public boolean delete(int id) {
		String sql="delete from student where id=?";
		int i=DBUtils.exeUpdate(sql, conn, id);
		return i>0;
	}
public List<Student> findAll() {
		String sql="select *from student";
		return DBUtils.queryList(Student.class, sql);
	}
public Student findOne(int id) {
		String sql="select *from student where id=?";
		return DBUtils.queryOne(Student.class, sql,id);
	}