Java JDBC操作数据库(实践项目--框架基础)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43599377/article/details/101439008

Java JDBC操作数据库(实践项目–框架基础)

今天来做一个简单的JDBC的框架主要实现Java操作数据库的增删改查
先来看一下目录结构:
在这里插入图片描述

下面利用process画图工具对这个项目的结构简单的勾勒
在这里插入图片描述
**1 先来看一下配置文件—》**是写在一个叫db.properties中的文件里
在这里插入图片描述
2 链接数据库代码
这个代码主要是来连接数据库,因为有配置文件,所以以后在其他地方运行,只需要来改配置文件即可

package com.haoyu.jdbc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.Properties;

public final class JdbcUtilPlus {

	private static String driver="com.mysql.jdbc.Driver";
	private static String url;
	private static String user;
	private static String password;

	//准备一个连接池 pool池子
	private static LinkedList<Connection> pool=new LinkedList<Connection>(); 
	
	static {
		try {
			//初始化配置信息url user password  prop是一种以.properties结尾的特殊文件
			//里面存入数据的方式是key-value形式
			Properties prop=new Properties();
			//需要把db.properties这个文件加载到prop类中去读
			prop.load(JdbcUtilPlus.class.getClassLoader().getResourceAsStream("db.properties"));
			//依次取出值赋值给成员变量
			url=prop.getProperty("url");
			user=prop.getProperty("user");
			password=prop.getProperty("password");
			// 初始化静态变量
			Class.forName(driver);
			//初始化连接池中的connections
			Integer counts=Integer.parseInt(prop.getProperty("counts"));
			for(int i=0;i<counts;i++) {
				//产生一个原生态的连接
				Connection conn=DriverManager.getConnection(url, user, password);
				//产生一个代理了close方法的代理连接
				conn=getProxyConnection(conn);
				//将代理连接放入连接池
				pool.add(conn);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 获取java与mysql之间的sql连接
	public static Connection getConnection() throws SQLException {
//		Connection conn = DriverManager.getConnection(url, user, password);
		//删除并拿到conneciton之前,需要看池子中是否还有连接
		Connection conn=null;
		if(pool!=null&&pool.size()>0) {
			conn=pool.removeLast();
		}
		return conn;
	}

	// 释放资源
	public static void release(Connection conn,Statement statement,ResultSet rs) {
		
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			rs=null;
		}
		
		try {
			if (statement != null) {
				statement.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			statement=null;
		}
		//这里可以这样设计,但是,oop告诉我们,最好是对象本身执行close的时候加入pool
		//可是,如果要复写close方法,必须是在conn这个对象创建的时候就复写close方法
		//public void close(){pool.add(conn);}
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			conn=null;
		}
	}
	//代理模式--AOP  面向切面
	//动态代理Proxy--一个对象new的过程中,jvm对其进行复写编译
	//已经有方法结构的类,在运行时候,对其复写操作,产生一个子类,代理类
	public static Connection getProxyConnection(Connection conn) {
		//Proxy java自带的一个动态代理的操作类  newProxyInstance 创建代理实例
		//使用一个孕育class的摇篮,孕育一个有原本结构的class,在handler中对指定方法进行复写,返回一个复写了方法的子类
		return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader()//
				,new Class[] {Connection.class}//
				,new InvocationHandler() {
			
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						Object result=null;
						if(method.getName().equals("close")) {
							pool.add(conn);
						}else {
							result=method.invoke(conn, args);
						}
						return result;
					}
				});
	}
	
}

3 操作数据库方法的接口
一些对数据库的增删改查

package com.haoyu.dao;

import java.util.List;

import com.haoyu.inter.ResultSetHandler;
//基本的dao的操作规范定义
public interface BaseDao<T> {
	public void add(String sql,Object[] params);
	public void update(String sql,Object[] params);
	public void delete(String sql,Object[] params);
	public T selectOneById(Integer id);
//	public List<T> selectByConditions(String sql,Object[] params);
	public T query(String sql, Object[] params,ResultSetHandler rsHandler);
	public List<T> selectAll();
}

3 实现操作数据库方法

package com.haoyu.dao;

import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import com.haoyu.inter.BeanForListHandler;
import com.haoyu.inter.BeanHandler;
import com.haoyu.inter.ResultSetHandler;
import com.haoyu.jdbc.JdbcUtilPlus;

//泛型参数变量 子类的泛型参数决定父类的泛型参数
public class BaseDaoImpl<T> implements BaseDao<T> {
	private Class clazz;
	
	public BaseDaoImpl() {
		clazz=(Class)((ParameterizedType)this.getClass()//
				.getGenericSuperclass())//
				.getActualTypeArguments()[0];
	}
	
	public BaseDaoImpl(int i) {
		
	}

	//sql=insert into user (id,name) values (?,?) +(ps)  params= {1,"apple"}
	//insert into user (id,name) values (1,'apple')
	//再通过connection传递给mysql操作
	private void modify(String sql,Object[] params) {
		//拿到连接
		Connection conn=null;
		//Statement-->PreparedStatement  
		//-- params 拼装组合并且使用占位符?的方式,简便拼装过程
		PreparedStatement ps=null;
		try {
			//实例化上面两个空对象
			conn=JdbcUtilPlus.getConnection();
			//这个快递盒必须符合运输线路定义的快递盒规范
			//prepare 准备  statemenet 快递盒
			ps=conn.prepareStatement(sql);
			//接下来要针对说明书放组件  params  也就是给sql拼接参数
			//按照说明书拼接组件   sql+params
			//如果参数是空,就不需要凭借,直接执行sql,例如:insert into user (id,name) values (1,'apple')
			if(params!=null&&params.length>0) {
				//按照说明书拼装组件
				for(int i=0;i<params.length;i++) {
					ps.setObject(i+1,params[i]);
				}
			}
			//放入快递盒通过连接桥梁传递过去
			ps.executeUpdate();//快递盒自己调用更新执行的方法,将拼接好的sql执行到数据中
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			JdbcUtilPlus.release(conn, ps, null);
		}
	}
	//增加数据操作
	@Override
	public void add(String sql, Object[] params) {
		modify(sql,params);
	}
//修改数据操作
	@Override
	public void update(String sql, Object[] params) {
		modify(sql,params);
	}
//删除数据操作
	@Override
	public void delete(String sql, Object[] params) {
		modify(sql,params);
	}
	//查询一个数据操作
	@Override
	public T selectOneById(Integer id) {
		String sql="select * from "+clazz.getSimpleName()+" where id=?";
		Object[] params= {id};
		return query(sql,params,new BeanHandler(clazz));
	}

	//一个查询的基本模板,可以替代上面的查询
	@Override
	public T query(String sql, Object[] params,ResultSetHandler rsHandler) {
		//建立mysql与db的桥梁
		Connection conn=null;
		//物流系统,快递盒--说明书+组件
		PreparedStatement ps=null;
		//db返回过来的特殊数据集合结构
		ResultSet rs=null;
		try {
			conn=JdbcUtilPlus.getConnection();//建立连接
			//prepareStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。
			ps=conn.prepareStatement(sql);//创建容器
			if(params!=null&&params.length>0) {
				//按照说明书拼装组件
				for(int i=0;i<params.length;i++) {
					ps.setObject(i+1,params[i]);
				}
			}
			//执行查询返回一个特殊结构的数据集合
			rs=ps.executeQuery();
			//表结构信息类--通过他取出该表有多少列,每一列叫什么名字
			//该类需要通过结果集来获取
			return (T) rsHandler.handler(rs);
		}catch(Exception e) {
			throw new RuntimeException(e+"查询出问题");
		}
	}
	//多条查询
	@Override
	public List<T> selectAll() {
		//得到类的简写名称
		String sql="select * from "+clazz.getSimpleName();
		return (List<T>) query(sql, null,new BeanForListHandler(clazz));
	}
}


/*
@Override
public List<T> selectByConditions(String sql, Object[] params) {
	//建立mysql与db的桥梁
	Connection conn=null;
	//物流系统,快递盒--说明书+组件
	PreparedStatement ps=null;
	//db返回过来的特殊数据集合结构
	ResultSet rs=null;
	try {
		conn=JdbcUtilPlus.getConnection();
		ps=conn.prepareStatement(sql);
		if(params!=null&&params.length>0) {
			//按照说明书拼装组件
			for(int i=0;i<params.length;i++) {
				ps.setObject(i+1,params[i]);
			}
		}
		//执行查询返回一个特殊结构的数据集合
		rs=ps.executeQuery();
		//表结构信息类--通过他取出该表有多少列,每一列叫什么名字
		//该类需要通过结果集来获取
		ResultSetMetaData rsmd=rs.getMetaData();
		int columns=rsmd.getColumnCount();
		List<T> lists=new ArrayList<T>();
		//结果集的指针从第一条数据之上指向下一条,并返回true false 代表有没有值
		while(rs.next()) {//只要在循环,就意味着下一条有值
			T target=(T) clazz.newInstance();
			//取出的每一条数据,都要根据列名,取出每一条中每一列的值
			//采用的方式就用列名取每一条数据中的对应列(一个单元格) --》龙暗1
			
			 2 龙暗1
			 3 龙暗2   
			 
			//循环每一列
			for(int i=0;i<columns;i++) {
				String columnName=rsmd.getColumnLabel(i+1);
				Object value=rs.getObject(columnName);
				//获取stu的所有字段
				Field[] fs=target.getClass().getDeclaredFields();
				for(Field field:fs) {
					//可访问私有成员
					field.setAccessible(true);
					String name=field.getName();
					if(name.equals(columnName)) {
						field.set(target, value);
						break;
					}
				}
			}
			lists.add(target);
		}
		return lists;
	}catch(Exception e) {
		throw new RuntimeException(e+"查询出问题");
	}
}*/

4 建立一个与数据表结构一样的类

package com.haoyu.bean;

public class Stu {
	private Integer id;
	private String name;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Stu [id=" + id + ", name=" + name + "]";
	}
}

package com.haoyu.dao;

import com.haoyu.bean.Stu;

public class StuDaoImpl extends BaseDaoImpl<Stu> implements StuDao{
	
}

package com.haoyu.dao;

import com.haoyu.bean.Stu;

public interface StuDao extends BaseDao<Stu>{

}

5 针对多条查询和单条数据查询。

package com.haoyu.inter;

import java.sql.ResultSet;

public interface ResultSetHandler {
	//结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等。 


	public Object handler(ResultSet rs);//简单的来说,就是一个返回结果集的东西
	
}


多条查询
package com.haoyu.inter;

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

//处理多个值的handler
//返回一个值的处理方案
public class BeanForListHandler implements ResultSetHandler {
	private Class clazz;
	public BeanForListHandler(Class clazz) {
		this.clazz = clazz;
	}
	@Override
	public Object handler(ResultSet rs) {
		try {
			// 该类需要通过结果集来获取
			ResultSetMetaData rsmd = rs.getMetaData();
			int columns = rsmd.getColumnCount();
			List list=new ArrayList();
			// 结果集的指针从第一条数据之上指向下一条,并返回true false 代表有没有值
			while (rs.next()) {// 只要在循环,就意味着下一条有值
				Object target = clazz.newInstance();
				for (int i = 0; i < columns; i++) {
					String columnName = rsmd.getColumnLabel(i + 1);
					Object value = rs.getObject(columnName);
					// 获取stu的所有字段
					Field[] fs = target.getClass().getDeclaredFields();
					for (Field field : fs) {
						// 可访问私有成员
						field.setAccessible(true);
						String name = field.getName();
						if (name.equals(columnName)) {
							field.set(target, value);
							break;
						}
					}
				}
				list.add(target);
			}
			return list;
		} catch (Exception e) {
			throw new RuntimeException(e + "處理結果集出問題");
		}
	}
}
单条查询
package com.haoyu.inter;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

//返回一个值的处理方案
public class BeanHandler implements ResultSetHandler {
	private Class clazz;
	public BeanHandler(Class clazz) {
		this.clazz = clazz;
	}
	@Override
	public Object handler(ResultSet rs) {
		try {
			// 该类需要通过结果集来获取
			//ResultSetMetaData类完成了查询结果信息和结果中的列的各种信息
			//参考连接:https://blog.csdn.net/en_joker/article/details/77844529
			ResultSetMetaData rsmd = rs.getMetaData();
			int columns = rsmd.getColumnCount();
			// 结果集的指针从第一条数据之上指向下一条,并返回true false 代表有没有值
			Object target = clazz.newInstance();
			while (rs.next()) {// 只要在循环,就意味着下一条有值
				for (int i = 0; i < columns; i++) {
					//getColumnLabel:默认的列的标题 
					String columnName = rsmd.getColumnLabel(i + 1);
					Object value = rs.getObject(columnName);
					// 获取stu的所有字段-->也就是给类的属性
					Field[] fs = target.getClass().getDeclaredFields();
					for (Field field : fs) {
						// 可访问私有成员
						field.setAccessible(true);
						String name = field.getName();
						if (name.equals(columnName)) {
							field.set(target, value);
							break;
						}
					}
				}
			}
			return target;
		} catch (Exception e) {
			throw new RuntimeException(e + "处理结果集出问题");
		}
	}
}

测试类

package com.haoyu.test;

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

import org.junit.Test;

import com.haoyu.bean.Stu;
import com.haoyu.dao.BaseDaoImpl;
import com.haoyu.dao.StuDaoImpl;
import com.haoyu.inter.BeanForListHandler;
import com.haoyu.inter.BeanHandler;
import com.haoyu.jdbc.JdbcUtilPlus;

public class JdbcTest {
	@Test
	public void testQueryOtherMethods() {
		Stu stu=new StuDaoImpl().selectOneById(1);
		System.out.println(stu);
		System.out.println("-------------------");
		List<Stu> stus=(List<Stu>) new StuDaoImpl().selectAll();
		for(Stu stu2:stus) {
			System.out.println(stu2);
		}
	}
	
	
	@Test
	public void testQueryPlus2() {
		String sql="select * from stu where id>? and id<?";
		Object[] params= {2,4};
		Stu stu=new StuDaoImpl().query(sql, params, new BeanHandler(Stu.class));
		System.out.println(stu);
	}
	
	@Test
	public void testQueryPlus() {
		String sql="select * from stu";
		List<Stu> stus=(List<Stu>) new StuDaoImpl().query(sql, null, new BeanForListHandler(Stu.class));
		for(Stu stu:stus) {
			System.out.println(stu);
		}
	}
	
	
	@Test
	public void testQuery() {
//		String sql="select * from stu where id>? and id<?";
//		Object[] params= {2,4};
//		List<Stu> stus=new StuDaoImpl().selectByConditions(sql, params);
//		for(Stu stu:stus) {
//			System.out.println(stu);
//		}
	}
	
	
	@Test
	public void testDelete() {
		String sql="delete from stu where name=? and id=?";
		Object[] params= {"龙傲天",1};
		BaseDaoImpl dao=new BaseDaoImpl(1);
		dao.delete(sql, params);
	}
	
	@Test
	public void testDaoUpdate() {
		String sql="update stu set name=? where id=?";
		Object[] params= {"龙傲天",1};
		BaseDaoImpl dao=new BaseDaoImpl(1);
		dao.update(sql, params);
	}
	
	@Test
	public void testDaoAdd() {
		String sql="insert into stu (name) values (?)";
		Object[] params= {"龙暗"};
		BaseDaoImpl dao=new BaseDaoImpl(1);
		dao.add(sql, params);
	}
	
	//将鼠标点中方法名称,然后右键执行,出现绿条即为正确,红色报错
	@Test
	public void testConnectionInit()throws SQLException{
		//com.mysql.jdbc.JDBC4Connection@2f410acf
		Connection conn=JdbcUtilPlus.getConnection();
		System.out.println(conn);
		JdbcUtilPlus.release(conn,null,null);
	}
	
}

猜你喜欢

转载自blog.csdn.net/weixin_43599377/article/details/101439008