[注解、反射、业务级事务支持] java jdbc Dao类的实现
2013-12-20 15:17 阅读(167)

1.注解

package com.seesource.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	/**
	 * 映射在数据表中的字段名
	 * @return
	 */
	 public String value() default "";

}
package com.seesource.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 主键标识
 * @author Administrator
 *
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {

}
package com.seesource.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 主键生成策略
 * @author Administrator
 *
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Strategy {
	int value() default StrategyType.INCREMENT;
}
package com.seesource.annotation;

public interface StrategyType {
	int ASSIGNED = 0;  //由程序提供
	int INCREMENT = 1; //自增(不需要提供)
}
package com.seesource.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	
	/**
	 * 映射到数据库中的数据表名
	 * @return
	 */
	public String value() default "";

}

dao实现

package com.seesource.dao;

import java.sql.SQLException;

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


public interface DataSourceFactory {
    
    public DataSource createDataSource();
}
package com.seesource.dao;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.naming.NamingException;

import com.seesource.annotation.Column;
import com.seesource.annotation.Id;
import com.seesource.annotation.Strategy;
import com.seesource.annotation.StrategyType;
import com.seesource.annotation.Table;
import com.seesource.exception.NotDefineColumnException;
import com.seesource.exception.NotDefinePrimaryKeyException;
import com.seesource.exception.NotDefineTableException;

public class GenericDao<T> {
	private Class clazz;
	private String table;//数据库表名
	private ColumnItem id;//主键字段名
	private int strategy = StrategyType.INCREMENT;//主键生成策略
	
	//String:字段名  Field:相应的实体get方法
	private List<ColumnItem> columns = new ArrayList<ColumnItem>();
	
	private static ThreadLocal tansaction_connecton_map = new ThreadLocal();
	private DataSourceFactory dataSourceFactory;

	
    /**
     * 获得参数T的实际类型
     * @return
     */
	private Class getGenericType() {
	    Class clazz = getClass();
	    Type genType = clazz.getGenericSuperclass();		
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();		
		return (Class) params[0];
	}
	/**
	 * 初始化
	 */
	public void init()throws NotDefineTableException,NotDefineColumnException,NotDefinePrimaryKeyException,Exception{		
		Class clazz = getGenericType();
		this.clazz = clazz;
		Table ta = (Table)clazz.getAnnotation(Table.class);
		if(ta == null || ta.value().trim().equals(""))
			throw new NotDefineTableException(this.clazz.toString() + "----未设置表名!");
		this.table = ta.value();
		
		for (Field f : clazz.getDeclaredFields()) {
			Column anno = f.getAnnotation(Column.class);
			if (anno != null) {
				String columnName = anno.value();
				if(columnName == null || columnName.trim().equals(""))
					throw new NotDefineColumnException(f.getName() + "----未设置字段名!");
				ColumnItem column = new ColumnItem(columnName, f, new PropertyDescriptor(f.getName(), this.clazz));
				//判断是否是主键
				Id idAnno = f.getAnnotation(Id.class);
				if(idAnno != null){
					this.id = column; //获得主键
					Strategy strategyAnno = f.getAnnotation(Strategy.class);
					if(strategyAnno != null)//获得主键生成策略
						this.strategy = strategyAnno.value();
					continue;
				}
				columns.add(column);				
			}else{
				throw new NotDefineColumnException(f.getName() + "----未设置字段名!");
			}
		}
		if(this.id == null)
			throw new NotDefinePrimaryKeyException(this.clazz.toString() + "----未设置主键!");
	}
	/**
	 * 添加记录
	 * @param rec
	 * @return
	 * @throws SQLException
	 */
	public int save(T entity) throws Exception {
		List<Object> params = new ArrayList<Object>();
		StringBuffer sb = new StringBuffer("INSERT INTO ");
		StringBuffer sb_values = new StringBuffer();
		sb.append(this.table);
		sb.append(" (");
		if(this.strategy == StrategyType.ASSIGNED){
			PropertyDescriptor pd = this.id.propertyDescriptor;
			Method getMethod = pd.getReadMethod();
			Object value = getMethod.invoke(entity);
			sb.append(this.id.columnName);
			sb.append(",");
			sb_values.append("?,");
			params.add(value);
		}
		
		for (ColumnItem entry : columns) {
			PropertyDescriptor pd = entry.propertyDescriptor;
			Method getMethod = pd.getReadMethod();
			Object value = getMethod.invoke(entity);
			if(value == null)//不对空值进行操作
				continue;			
			
			sb.append(entry.columnName);
			sb.append(",");
			
			params.add(value);
			sb_values.append("?,");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb_values.deleteCharAt(sb_values.length() - 1);
		sb.append(") VALUES (");
		sb.append(sb_values.toString());
		sb.append(')');		
		
		Connection con = null;
    	PreparedStatement stmt = null;
    	con = getConnection();
		stmt = con.prepareStatement(sb.toString());
		setParams(stmt, params.toArray());    	 
		int nums = stmt.executeUpdate(); //返回受影响的行数
		closeStatement(stmt);
		closeConnection(con);
		return nums;
	}
	/**
	 * 修改
	 * @param sql
	 * @param params
	 * @return
	 */
    public int update(T entity) throws Exception {
    	StringBuilder sb = new StringBuilder("UPDATE ");
		sb.append(this.table);
		sb.append(" SET ");
		
		List<Object> paramList = new ArrayList<Object>();
		for (ColumnItem entry : columns) {
			Field field = entry.theField;
			PropertyDescriptor pd = entry.propertyDescriptor;
			Method getMethod = pd.getReadMethod();
			Object value = getMethod.invoke(entity);
			sb.append(entry.columnName);
			sb.append(" = ?,");
			paramList.add(value);			
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append(" WHERE ");
		sb.append(this.id.columnName);
		sb.append(" = ?");	
		PropertyDescriptor pd = this.id.propertyDescriptor;
		Method getMethod = pd.getReadMethod();
		Object value = getMethod.invoke(entity);
		paramList.add(value);
		
   	    Connection con = null;
   	    PreparedStatement stmt = null;
    	con = getConnection();
	    stmt = con.prepareStatement(sb.toString());
	    setParams(stmt, paramList.toArray());
	    int nums = stmt.executeUpdate(); //返回受影响的行数
	    closeStatement(stmt);
		closeConnection(con);
	    return nums;
    } 
    /**
	 * 删除
	 * @param sql
	 * @param params
	 * @return
	 */
    public int delete(T entity) throws Exception {
    	StringBuilder sb = new StringBuilder("delete from  ");
		sb.append(this.table);
		sb.append(" where ");		
		sb.append(this.id.columnName);
		sb.append(" = ?");	
		PropertyDescriptor pd = this.id.propertyDescriptor;
		Method getMethod = pd.getReadMethod();
		Object value = getMethod.invoke(entity);
		Object[] params = new Object[1];
		params[0] = value;
		
   	    Connection con = null;
   	    PreparedStatement stmt = null;
    	con = getConnection();
	    stmt = con.prepareStatement(sb.toString());
	    setParams(stmt, params);
	    int nums = stmt.executeUpdate(); //返回受影响的行数
	    closeStatement(stmt);
		closeConnection(con);
	    return nums;
    } 
    /**
     * 查询
     * @param sql
     * @param params
     * @return
     */
	public List<T> find(String sql, Object[] params){
		List<T> list = new ArrayList<T>();
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			con = this.getConnection();
			stmt = con.prepareStatement(sql);
			setParams(stmt, params);
			rs = stmt.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			int columnCount = rsmd.getColumnCount();
			while(rs != null && rs.next()){
				T entity = (T)this.clazz.newInstance();
				for(int i = 0; i<columnCount; i++){
					String columnName = rsmd.getColumnName(i+1);
					ColumnItem columnItem = getColumnItem(columnName);
					if(columnItem != null){
						PropertyDescriptor pd = columnItem.propertyDescriptor;
						Method setMethod = pd.getWriteMethod();
						Object value = rs.getObject(columnName);
						setMethod.invoke(entity, value);
					}
				}	
				
				list.add(entity);
			}
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally{
			closeResultSet(rs);
			closeStatement(stmt);
			closeConnection(con);
		}
		return list;
	}
	/**
	 * 通过主键获得单个实例
	 * 如果库中无此实例,则返回null
	 * @param entity
	 * @return
	 */
	public T get(T entity)throws Exception{
		StringBuffer sb = new StringBuffer("select * from ");
		sb.append(this.table);
		sb.append(" where ");		
		sb.append(this.id.columnName);
		sb.append(" = ?");	
		PropertyDescriptor pd = this.id.propertyDescriptor;
		Method getMethod = pd.getReadMethod();
		Object id_value = getMethod.invoke(entity);
		Object[] params = new Object[1];
		params[0] = id_value;
		
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			con = this.getConnection();
			stmt = con.prepareStatement(sb.toString());
			setParams(stmt, params);
			rs = stmt.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			int columnCount = rsmd.getColumnCount();
			if(rs != null && rs.next()){
				for(int i = 0; i<columnCount; i++){
					String columnName = rsmd.getColumnName(i+1);
					ColumnItem columnItem = getColumnItem(columnName);
					if(columnItem != null){
						pd = columnItem.propertyDescriptor;
						Method setMethod = pd.getWriteMethod();
						Object value = rs.getObject(columnName);
						setMethod.invoke(entity, value);
					}
				}
				return entity;
			}
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally{
			closeResultSet(rs);
			closeStatement(stmt);
			closeConnection(con);
		}
		return null;
	}
	/**
	 * 统计数量
	 * @param sql
	 * @param params
	 * @return
	 */
	public long count(String sql, Object[] params){
		long count = 0;
 		Connection con = null;
 		PreparedStatement stmt = null;
 		ResultSet rs = null;
 		try {
 			con = this.getConnection();
 			stmt = con.prepareStatement(sql);
 			setParams(stmt, params);
 			rs = stmt.executeQuery();
 			if(rs != null && rs.next()){
 				count = rs.getLong(1);
 			}
 		}catch (Exception e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
 		finally{
 			closeResultSet(rs);
 			closeStatement(stmt);
 			closeConnection(con);
 		}
 		return count;
	}
	/**
	 * 判断实体注解配置中是否有此字段
	 * @param columnName
	 * @return
	 */
	private ColumnItem getColumnItem(String columnName){
		if(this.id.columnName.equals(columnName))
			return this.id;
		for(int i = 0; i<this.columns.size(); i++){
			ColumnItem item = this.columns.get(i);
			if(columnName.equals(item.columnName))
				return item;
		}
		return null;
	}
	/**
	 * 关闭ResultSet
	 * @param rs
	 */
    protected void closeResultSet(ResultSet rs){
   	 try {
			if(rs != null){
				 rs.close();
			 }
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    /**
     * 关闭Statement
     * @param stmt
     */
    protected 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 {
       	 Object obj = tansaction_connecton_map.get(); 
   		 if(obj == null && con != null){ //不在事务控制中时直接关闭
   			 con.close();
   		 }
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    /**
 	 * 开启事务
 	 * @return
 	 */
 	public void startTransaction()throws SQLException,NamingException{
 		Connection con = createConnection();
 		con.setAutoCommit(false);
 		tansaction_connecton_map.set(con);
 	}
 	/**
 	 * 提交事务
 	 * @return
 	 */
 	public void commit()throws SQLException{
 		Object obj = tansaction_connecton_map.get();
 		if(obj != null){
 			Connection con = (Connection)obj;
 			con.commit();
 		}
 	}
 	
 	/**
 	 * 回滚事务
 	 * @return
 	 */
 	public void rollback(){
 		try {
			Object obj = tansaction_connecton_map.get();
			if(obj != null){
				Connection con = (Connection)obj;
				con.rollback();
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
 	}
 	
 	/**
 	 * 销毁事务,释放连接
 	 * @return
 	 * @throws SQLException
 	 * @throws NamingException
 	 */
 	public void distroyTransaction(){
 		try {
 			Object obj = tansaction_connecton_map.get();
 			if(obj != null){
 				Connection con = (Connection)obj;
 				con.setAutoCommit(true);
 				con.close();
 			}
 		} catch (Exception e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}finally{
 			tansaction_connecton_map.set(null);
 		}
 	}
 	
 	private Connection createConnection() throws SQLException, NamingException{
 		Connection con = this.dataSourceFactory.createDataSource().getConnection();
        return con;
 	}

 	/**
 	 * 获得数据库连接
 	 * @return
 	 * @throws SQLException
 	 * @throws NamingException
 	 */
      public  Connection getConnection() throws SQLException, NamingException{
     	 Connection con = null;
     	 Object obj = tansaction_connecton_map.get(); 
 		 if(obj != null){
 			con = (Connection)obj;
 		 }else{
 			 con = createConnection(); 
 		 }
          return con;
      }
      
	
	
	
	/**
	 * 设置参数
	 * @param stmt
	 * @param params
	 * @throws SQLException
	 */
    protected void setParams(PreparedStatement stmt, Object[] params) throws SQLException{
   	    for(int i = 0; i<params.length;){//int, short, long, float, double,  boolean, byte, char, List
   	    	if(params[i] == null){
   	    		stmt.setObject(i+1, null);
   	    		i++;
   	    		continue;
   	    	}
   	    	if(params[i]  instanceof String){
   	    		stmt.setString(i+1, (String)params[i]);
             	i++;
  				continue;
  			}
      		 if(params[i] instanceof Integer){
      			stmt.setInt(i+1, (Integer)params[i]);
             	i++;
  				continue;
  			 }
  			 if(params[i] instanceof Short){
  				 stmt.setShort(i+1, (Short)params[i]);
             	 i++;
  				 continue;
  			 }
  			 if(params[i] instanceof Long){
  				 stmt.setLong(i+1, (Long)params[i]);
             	 i++;
  				 continue;
  			 }
  			 if(params[i] instanceof Float){
  				 stmt.setFloat(i+1, (Float)params[i]);
             	 i++;
  				 continue;
  			 }
  			 if(params[i] instanceof Double){
  				 stmt.setDouble(i+1, (Double)params[i]);
             	 i++;
  				 continue;
  			 }
  			 if(params[i] instanceof Date){
 				 stmt.setDate(i+1, (Date)params[i]);
            	 i++;
 				 continue;
 			 }
  			if(params[i] instanceof Timestamp){
				 stmt.setTimestamp(i+1, (Timestamp)params[i]);
           	     i++;
				 continue;
			 }
  			 if(params[i] instanceof Boolean){
  				 stmt.setBoolean(i+1, (Boolean)params[i]);
             	 i++;
  				 continue;
  			 }
  			 if(params[i] instanceof Byte){
  				 stmt.setByte(i+1, (Byte)params[i]);
             	 i++;
  				 continue;
  			 }
	    }
    }
    
    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
		this.dataSourceFactory = dataSourceFactory;
	}
    
    class ColumnItem{
    	public ColumnItem(String columnName, Field  theField, PropertyDescriptor propertyDescriptor){
    		this.columnName = columnName;
    		this.theField = theField;
    		this.propertyDescriptor = propertyDescriptor;
    	}
    	String columnName;
    	Field  theField;
    	PropertyDescriptor propertyDescriptor;
    }
}

exception实现
package com.seesource.exception;

public class NotDefineColumnException  extends Exception{
	public NotDefineColumnException(){
        super("未设置字段名!");
    }
    public NotDefineColumnException(String msg){
        super(msg);
    }
}
package com.seesource.exception;

/**
 * 未定义主键异常
 * @author Administrator
 *
 */
public class NotDefinePrimaryKeyException extends Exception{
	public NotDefinePrimaryKeyException(){
        super("未定义主键");
    }
    public NotDefinePrimaryKeyException(String msg){
        super(msg);
    }
}
package com.seesource.exception;

public class NotDefineTableException  extends Exception{
	public NotDefineTableException(){
        super("未设置表名!");
    }
    public NotDefineTableException(String msg){
        super(msg);
    }
}

如何使用:


package com.seesource.persist;

import java.sql.Date;
import java.sql.Timestamp;

import com.seesource.annotation.Column;
import com.seesource.annotation.Id;
import com.seesource.annotation.Strategy;
import com.seesource.annotation.StrategyType;
import com.seesource.annotation.Table;

@Table("user")
public class User {
	@Column("id_")
	@Id
	@Strategy(StrategyType.INCREMENT)
    private int id;
	@Column("name_")
    private String name;
	@Column("date_")
    private Timestamp date;
    
    
    
	public Timestamp getDate() {
		return date;
	}
	public void setDate(Timestamp date) {
		this.date = date;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
package com.seesource.dao;

import com.seesource.persist.User;

public class UserDao extends GenericDao<User>{

}
import java.sql.SQLException;

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

import com.seesource.dao.DataSourceFactory;


public class MyDataSourceFactory implements DataSourceFactory{
    private DataSource dataSource;
    
    public MyDataSourceFactory()throws SQLException, NamingException{
    	Context initContext = new InitialContext(); 
		Context envContext  = (Context)initContext.lookup("java:/comp/env"); 
		DataSource ds = (DataSource)envContext.lookup("jdbc/xinwei"); 
		this.dataSource = ds;
		System.out.println("------------------------------已经创建了dataSource-----------------------------------------");
    }
    
    public DataSource createDataSource(){
    	return this.dataSource;
    }
}

场景1(增加记录)
public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		try {
			UserDao dao = new UserDao();
			DataSourceFactory dataSource = new MyDataSourceFactory();
			dao.setDataSourceFactory(dataSource);
			dao.init();
			User entity = new User();
			entity.setName("张三");
			entity.setDate(new java.sql.Timestamp(new java.util.Date().getTime()));
			dao.save(entity);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

场景2(查询)
public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		try {
			UserDao dao = new UserDao();
			DataSourceFactory dataSource = new MyDataSourceFactory();
			dao.setDataSourceFactory(dataSource);
			dao.init();
			String sql = "select * from user";
			List<User> users = dao.find(sql, new Object[0]);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


场景3(业务级事务)

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		UserDao dao = new UserDao();
		try {
			
			DataSourceFactory dataSource = new MyDataSourceFactory();
			dao.setDataSourceFactory(dataSource);
			dao.init();
			dao.startTransaction();//开始事务
			
			User entity = new User();
			entity.setId(8);
			entity.setName("张三");
			entity.setDate(new java.sql.Timestamp(new java.util.Date().getTime()));
			
			int rat = dao.update(entity);
			if(rat == 0){
				dao.rollback();
			}else{
				rat = dao.delete(entity);
				if(rat == 0){
					dao.rollback();
				}else{
					dao.commit();//提交事务
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			dao.rollback();
		}finally{
			dao.distroyTransaction();//销毁事务
		}
	}


完整实例:http://pan.baidu.com/s/1mg9avwO