利用回調函數+匿名類解決jdbc數據封裝問題

最近因爲公司要開發個報表系統,因爲涉及到超大數據量的統計,頻繁的sql語句,就沒有在用hibernate,又重拾起了jdbc,在寫jdbc助手類時自我感受有個不錯的建議和你們分享下: java


上面的代碼是個查詢單個實例方法中的片斷,能夠看到除了填充bean(Admin類)外其餘代碼都是公用代碼,能夠放到jdbc助手類中,這就要解決不一樣bean的填充問題。 web

採用回調函數代替上面填充bean的部分是個可行的選擇。 sql

下面是具體的實現: 數據庫


數據庫中有個簡單的users表,用於存放客戶信息: 函數


com.persist.User類是個實體類對應Users表: 大數據

package com.persist;

import java.io.Serializable;
import java.util.Date;


public class User{
	private int  dbid;
	private String userName;//暱稱
	private String password;//登陸密碼
	private String email;//郵箱
	
	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
	
	public int getDbid() {
		return dbid;
	}

	public void setDbid(int dbid) {
		this.dbid = dbid;
	}
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}


com.dao.GenericDao類是數據訪問層(dao)定義的jdbc助手類,用於完成數據訪問的基本操做。find方法是得到單個實例的查詢方法,其中會調用回調函數call()。代碼最底端定義了內部接口PopulateCallable,用於完成回調操做,call是回調函數。 this

package com.dao;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;


public class GenericDao<T> {
	
	/**
	 * 查詢單個實例
	 * @param sql
	 * @param params
	 * @param callback
	 * @return
	 * @throws SQLException
	 * @throws NamingException
	 */
	protected T find(String sql, Object[] params, PopulateCallable<T> callback) throws SQLException, NamingException{
		T entity = null;
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			con = this.getConnection();
			stmt = con.prepareStatement(sql);
			setParams(stmt, params);
			rs = stmt.executeQuery();
			while(rs.next()){
				entity = callback.call(rs);	
			}
		}finally{
			closeResultSet(rs);
			closeStatement(stmt);
			closeConnection(con);
		}
		return entity;
	}
	/**
	 * 得到數據庫connection
	 * @return
	 * @throws SQLException
	 * @throws NamingException
	 */
	protected Connection getConnection() throws SQLException, NamingException{
		Context initContext = new InitialContext(); 
		Context envContext  = (Context)initContext.lookup("java:/comp/env"); 
		DataSource ds = (DataSource)envContext.lookup("jdbc/myweb"); 
		Connection con = ds.getConnection();
        return con;
	}	
	/**
	 * 關閉ResultSet 
	 * @param rs
	 */
    public void closeResultSet(ResultSet rs){
   	 try {
			if(rs != null){
				 rs.close();
			 }
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }    
    /**
     * 關閉Statement
     * @param stmt
     */
    public void closeStatement(Statement stmt){
   	 try {
			if(stmt != null){
				 stmt.close();
			 }
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    /**
     * 歸還鏈接到鏈接池
     * @param con
     */
    public void closeConnection(Connection con){
   	 try {
   		 if(con != null && !con.isClosed()){ 
   			 con.close();
   		 }
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    /**
     * 設置參數
     * @param stmt
     * @param params
     * @throws SQLException
     */
    public void setParams(PreparedStatement stmt, Object[] params) throws SQLException{
   	 for(int i = 0; i<params.length;){//int, short, long, float, double,  boolean, byte, char, List
   		 stmt.setObject(i+1, params[i]);
			 i++;
		 }
    }
    
    protected interface PopulateCallable<T>  extends Serializable {
    	T call(ResultSet rs)throws SQLException, NamingException;
    }
}



com.dao.UserDao類負責User的的數據訪問,繼承自助手類com.dao.GenericDao spa

package com.dao;

import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.NamingException;

import com.persist.User;

public class UserDao extends GenericDao<User>{

	public User find(int dbid) throws SQLException, NamingException{
		String sql = "select * from users t where t.dbid=?";
		Object[] params  = new Object[]{dbid};
		User entity = super.find(sql, params, new GenericDao.PopulateCallable<User>(){			  
		      public User call(ResultSet rs) throws SQLException, NamingException{
		    	  User item = new User();
		    	  item.setDbid(rs.getInt("dbid"));
	    		  item.setUserName(rs.getString("username"));
	    		  item.setPassword(rs.getString("password"));
	    		  item.setEmail(rs.getString("email"));	
		          return item;
		      }
		});
		return entity;
	}
}

find方法負責從數據庫中得到單個實例。這個方法是核心方法。其中在調用super.find()方法時,生成了PopulateCallable接口的匿名類,做爲參數傳入。回調函數call負責具體的封裝bean的操做,由助手類com.dao.GenericDao類調用。 hibernate



package com.service;

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

import javax.naming.NamingException;

import com.dao.GenericDao;
import com.dao.UserDao;
import com.persist.User;

public class UserService {
	
	public User get(int dbid) throws SQLException, NamingException{
		User entity = null;
		UserDao dao = new UserDao();
		entity = dao.find(dbid);
		return entity;
	}

}
com.service.UserService類是個簡單的業務類。


除了回調函數外,也能夠使用反射,利用java.beans.BeanInfo類得到bean的全部屬性,而後利用寫屬性進行填充。相比於採用回調而言,反射很難控制讀取的數據庫字段的數量,因此靈活性不如回調。 code

相關文章
相關標籤/搜索