Dao层的封装和Oracle JDBC连接数据库

一开始学习Oracle JDBC连接的时候一般都是先做一个基础类获取数据库的连接,在用Dao层的类去工作,执行SQL语句。

但是没做一个功能就要写一个执行方法,这样很麻烦,代码也不够优化。我最近参考了一些资料,把连接数据库的基础类和Dao层的方法一起封装到一个类,用到的话直接调用,实现代码优化。

先做好数据库驱动和连接及资源关闭的代码

static {
		// 加载驱动
		try {
			// 读取文件
			Properties prop = new Properties();
			prop.load(new FileInputStream(new File("config/db.properties")));
			// 获取属性
			driverName = prop.getProperty("driverName");
			url = prop.getProperty("url");
			userName = prop.getProperty("userName");
			passWord = prop.getProperty("passWord");
			// 动态加载驱动    API解释:返回与给定字符串名称的类或接口相关联的 类对象。 
			Class.forName(driverName);
		} catch (Exception e) {	
			e.printStackTrace();
		} 
	}

	public static Connection getConnection() {
		Connection conn = null;
		try {
			//获取连接数据库的方法DriverManager加载启动管理
			conn = DriverManager.getConnection(url, userName, passWord);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}

	// 提供释放资源的方法
	public static void close(Connection conn, Statement stmt, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}


下面是没有封装的Dao层方法 增加数据的方法

public boolean registerAccounts(String users, String passWord) {
		Connection conn=null;
		PreparedStatement stmt=null;
		boolean tmp=false;
		try {
			conn=getConnection();
			stmt=conn.prepareStatement(REGISTER_USER_AND_PASSWORD);
			stmt.setString(1,users);
			stmt.setString(2,passWord);
			stmt.executeUpdate();
			conn.commit();
			tmp=true;
			return tmp;
		} catch (SQLException e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
			close(conn, stmt, null);
		}
		
		return false;
	}

这个封装好的方法可以实现上面的功能,但更加优化

//封装所有dao的更新方法
	public boolean actionUpdate(String sql,List<Object> params)
	{
		//把依赖的属性放到外面 有利于代码有执行程序
		Connection conn=null;
		PreparedStatement stmt=null;
		int result=0;
		try {
			//获取连接
			conn=getConnection();
			//通过预便宜存储sql语句的参数
			stmt=conn.prepareStatement(sql);
			//如何从List集合中获取参数来给stmt中的sql语句中的问号赋值呢?
			//params通过for循环逐个放入stmt预编译里面
			if(params!=null)
			{
				for(int i=0;i<params.size();i++)
				{
					//这里Object是通用的可以变的类型(例如:String,int,char。。。)
					//i+1索引?:从0开始的。
					//params.get(i)获取那个值,看构造方法的放入位置,(重点注意(连构造方法的列名都要一样))
					stmt.setObject(i+1, params.get(i));
				}
			}
			result=stmt.executeUpdate();
			
		}catch(Exception e)
		{
			e.printStackTrace();
			
		}finally 
		{
			close(conn,stmt,null);
		}
		//三元运算符
		return result>0?true:false;
	}

使用封装好的代码

/**
	 * 增加书籍
	 */
	@Override
	public boolean insertBook(Book book) {
		List<Object> params=new ArrayList<Object>();
		params.add(book.getBook_name());
		
		return this.actionUpdate(INSERT_BOOK, params);
	}

我个人感觉查询的封装方法有点难写,涉及到String和工具类,对象,和反射的知识例如:

//封装所有dao的查询操作
	//泛型方法,语法:public <T> List<T> actionQuery(),,,返回数据前声明了一个泛型
	public <T> List<T> actionQuery(String sql,List<Object> params,Class<T> cls)
	{
		Connection conn=null;
		PreparedStatement stmt=null;
		ResultSet rs=null;
		//<T>泛型的集合用来存放各种类型的数据
		List<T> list=new ArrayList<T>();
		
		try {
			//1.把工具对象初始化
			conn=getConnection();
			stmt=conn.prepareStatement(sql);
			
			//2.给sql语句中的占位符赋值
			if(params!=null)
			{
				for(int i=0;i<params.size();i++)
				{
					//这里Object是通用的可以变的类型(例如:String,int,char。。。)
					//i+1索引?:从0开始的。
					//params.get(i)获取那个值,看构造方法的放入位置,(重点注意(连构造方法的列名都要一样))
					stmt.setObject(i+1, params.get(i));
				}
			}
			rs=stmt.executeQuery();
			
			//拿到元数据           ResultSetMetaData可用于获取有关ResultSet对象中列的类型和属性的信息的对象
			ResultSetMetaData rm=rs.getMetaData();//getMetaData用于检索此 ResultSet对象的列的数量,类型和属性。
			int columnCount=rm.getColumnCount();//获取列数
			//2.把结果集中的数据转移到list集合中
			while(rs.next())//结果集中有多少行数据就循环多少次,7次
			{
				//2.1  这里需要实例化一个对象<T>泛型,以接收每行数据  cls的值: Book.class
				T obj=cls.newInstance();//new Book();  newInstance创建由此类对象表示的类的新实例。该类被实例化为一个具有空参数列表的new表达式。 如果类尚未初始化,则初始化该类。 
				
				//2.2如何给对象的各个属性赋值呢?
				//2.3有多少列那么就循环多少次  4次
				for(int i=0;i<columnCount;i++)
				{
					String columnName=rm.getColumnName(i+1);//i+1是索引,从1开始  BOOK_ID,这里的列名和数据库列名是一样的
					//获取列名==获取属性名==就可以获取set对应的方法名==就可以拿到Method对象==然后调用给属性赋值
					String fieldName=columnName.toLowerCase();// 获取到的列名,全转小写  book_id? 原因:数据库默认传送过来的列名进行统一
					//拼出这个名字:setBook_id
					//fieldName.substring(0,1).toUpperCase():拿到名字中的首字母然后转成大写,结果是B
					//replaceFirst(1,2)用给定的2替换1,这个方法就是后面的值替换第一个值
					//substring(0,1)截取第一个字符,并变成大写
					String replaceName=fieldName.replaceFirst(fieldName, fieldName.substring(0,1).toUpperCase());
					System.out.println("replaceName:"+replaceName);
					//这下面的意思是set+B+ook_id
					String methodName="set"+replaceName+fieldName.substring(1);
					System.out.println("methodName:"+methodName);
					//获取Method对象
					//获取字段对应的数据类型
					//class.getDeclaredField返回一个Field对象,它反映此表示的类或接口的指定已声明字段类对象。 参数是一个String ,它指定了所需字段的简单名称。 
					//这里用到了反射
					Class<?> type=cls.getDeclaredField(fieldName).getType();
					//获取方法对象时,加了一个类型参数,这样更准确地定位一个方法    第一个参数是过去到的参数名,第二个是获取到的参数类型
					//Method 方法提供有关类和接口上单一方法的信息和访问权限。 反映的方法可以是类方法或实例方法(包括抽象方法)。
					//用Method去接收 cls类型的字段名和类型  也就是一个能实际实用的方法了
					Method method=cls.getDeclaredMethod(methodName,type);
					
					//method.invoke(obj, rs.getObject(i+1));这行代码不要,下面有调用
					
					
					//根据数据类型赋值
					/*isAssignableFrom确定由此类对象表示的类或接口是否与由指定的Class 类表示的类或接口相同或是超类或类接口。 如果是,则返回true ; 否则返回false 
					如果此类对象表示基本类型,则如果指定的类参数正好是类对象,则此方法返回true ; 否则返回false 。 */
					if(type.isAssignableFrom(String.class))
					{
						//在具有指定参数的方法对象上调用此方法对象表示的基础方法。
						//obj - 从中调用底层方法的对象(简单的说就是调用谁的方法用谁的对象)     rs - 用于方法调用的参数 
						method.invoke(obj, rs.getString(i+1));
					}else if(type.isAssignableFrom(int.class)||type.isAssignableFrom(Integer.class))
					{
						method.invoke(obj, rs.getInt(i+1));
					}else if(type.isAssignableFrom(boolean.class)||type.isAssignableFrom(Boolean.class))
					{
						method.invoke(obj, rs.getBoolean(i+1));
					}else if(type.isAssignableFrom(Date.class))
					{
						method.invoke(obj, rs.getDate(i+1));
					}
					
				}
				list.add(obj);
			}
		} catch (Exception e) {
			e.printStackTrace();// TODO: handle exception
		}finally {
			close(conn,stmt,rs);
		}
		return list;
	}

感觉查询封装类比较难理解,多写几次就好多。




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值