1. 程式人生 > >自制Mysql資料庫連線工具(含使用說明)

自制Mysql資料庫連線工具(含使用說明)

我們在對mysql資料庫進行操作時,就要使用JDBC去連線資料庫,所以程式碼不免要出現大量的冗餘,比如連線,關閉等等實現其實都是一樣的,所以聰明的程式設計師就會將這些重複的功能封裝,簡化使用過程,提高程式碼複用性。

1.BaseDao原始碼

package com.xintoucloud.jdbcutil;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.xintoucloud.jdbcutil.exception.NoEntityClassException;
import com.xintoucloud.jdbcutil.exception.NoIdException;

public class BaseDao <E,P extends Serializable> {
	//例項類Class物件
	private Class<?> entityClass;
	//實體類對應的表名
	private String tableName;
	//主鍵列名(為了根據id查詢和刪除)
	private String idColumn;
	//實體類屬性和表的欄位對映關係的集合(為了拼接SQL語句),save(E entity),update(E endity)
	private List<PropertyColumnMapper> propertyColumnMappers;
	//列名和屬性名對映Map(為了通過列名找到屬性名,進行對映一個列值到屬性),為了查詢
	private Map<String,String> columnPropertyMap;
	//Id屬性
	private Field idField;
	protected BaseDao() {
		//獲取父類的泛型class
		Type type = this.getClass().getGenericSuperclass();
		ParameterizedType parameterizedType = (ParameterizedType)type;
		entityClass =(Class<?>) (parameterizedType.getActualTypeArguments()[0]);
		if(entityClass==null){
			throw new NoEntityClassException("沒有使用泛型指定實體類");
		}
		columnPropertyMap = new HashMap<>();
		
		scanTableAnnotation();
		scanIdProperty();
		scanNormalProperty();
	}
	
	/**
	 * 掃描Table註解:得到表名
	 */
	private void scanTableAnnotation() {
		Table table = entityClass.getAnnotation(Table.class);
		if(table != null) {
			tableName = table.value();
		} else {
			tableName = entityClass.getSimpleName();
		}
	}
	
	/**
	 * 掃描Id屬性:為了得到主鍵列和屬性
	 */
	private void scanIdProperty() {
		boolean hasId = false;
		Field[] fields = entityClass.getDeclaredFields();
		for(int i=0;i<fields.length;i++) {
			Field field = fields[i];
			Id idAnnotation = field.getAnnotation(Id.class);
			//如果有Id註解
			if(idAnnotation != null) {
				//預設屬性名稱作為主鍵名稱
				idColumn = field.getName();
				//如果Id註解有value值,那麼主鍵名稱就變成value值
				String value = idAnnotation.value();
				if(!value.isEmpty()) {
					idColumn = value;
				}
				//賦值idField,(找到了Id屬性)
				idField = field;
				
				columnPropertyMap.put(idColumn, field.getName());
				//(找到了Id屬性)
				hasId = true;
			} 
		}
		
		if(!hasId) {
			throw new NoIdException("請設定Id標示");
		}
	}
	
	/**
	 * 掃描普通屬性
	 */
	private void scanNormalProperty() {
		Field[] fields = entityClass.getDeclaredFields();
		propertyColumnMappers = new ArrayList<>();
		for(int i=0;i<fields.length;i++) {
			Field field = fields[i];
			//不管Id屬性
			if(field.equals(idField)) {
				continue;
			}
			//判斷是否需要忽略
			Transient transientAnnotation = field.getAnnotation(Transient.class);
			//如果不需要忽略
			if(transientAnnotation == null) {
				Column column = field.getAnnotation(Column.class);
				
				String columnName=null;
				//有Column註解
				if(column != null) {
					//列名就是註解的value
					columnName = column.value();
					
				} else {
					//否則是屬性的名稱
					columnName = field.getName();
				}
				
				PropertyColumnMapper propertyColumnMapper = new PropertyColumnMapper(field.getName(),columnName,field.getType());
				propertyColumnMappers.add(propertyColumnMapper);
				
				columnPropertyMap.put(columnName, field.getName());
			}
			
		}
		
	}
	
	/**
	 * 通用的更新方法
	 * 
	 * @param sql
	 *            要執行的SQL語句,引數使用?佔位符
	 * @param parameters
	 *            佔位符的值,順序和SQL佔位符對應
	 * @return 更新影響的行數
	 */
	public int update(String sql, Object[] parameters) {
		Connection conn = JdbcUtil.getConnection();
		int affectedRow = 0;
		try (PreparedStatement st = conn.prepareStatement(sql)) {
			// 給佔位符賦值
			setParameters(st, parameters);

			affectedRow = st.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return affectedRow;
	}
	
	/**
	 * 往那張表中填?
	 * 往哪些欄位填(這個表一共有多少欄位?哪些不需要填?)
	 * 主鍵如果是自增不需要填
	 * 
	 * 儲存一個物件
	 * @param entity 要儲存的物件
	 * @return 資料表中受影響的行數
	 * 
	 * 
	 */
	public int save(E entity) {
		//需要設定的引數數量賦值成需要儲存的普通列的數量 6
		int parameterCount = propertyColumnMappers.size();
		
		StringBuilder sb = new StringBuilder("insert into ");
		sb.append(tableName);
		
		sb.append("(");
		//迴圈實體類屬性和表的欄位對映關係的集合,拼接要新增的列名(除了Id列)
		//insert into Student(sname,
		for(int index=0;index<propertyColumnMappers.size();index++) {
			PropertyColumnMapper propertyMapper = propertyColumnMappers.get(index);
			sb.append(propertyMapper.getColumnName());
			//一個列名後加,分割,最後一個列名後不加
			if(index<propertyColumnMappers.size()-1) {
				sb.append(",");
			}
		}
		
		//判斷id列是否需要加入
		Id idAnnotation = idField.getAnnotation(Id.class);
		GenarateType genarate = idAnnotation.genarate();
		//如果Id是手工設定,拼接Id列名(參與儲存操作)
		if(genarate == GenarateType.ASSIGNED) {
			sb.append(",");
			sb.append(idColumn);
		}
		
		sb.append(") ");
		sb.append("values ");
		sb.append("(");
		//拼接普通列對應的佔位符?
		for(int index=0;index<propertyColumnMappers.size();index++) {
			sb.append("?");
			if(index<propertyColumnMappers.size()-1) {
				sb.append(",");
			}
		}
		//如果Id是手工設定,拼接Id列名對應的佔位符
		if(genarate == GenarateType.ASSIGNED) {
			sb.append(",?");
			//需要設定的引數數量+1 7
			parameterCount++;
		}
		//insert into Student(sname,ssex,sage,sdept,leftMoney,birthday,sno) values (?,?,?,?,?,?,?)
		sb.append(")");
		System.out.println(sb.toString());
		//引數陣列 7
		Object[] parameters = new Object[parameterCount];
		//給引數陣列賦值
		for(int index=0;index<propertyColumnMappers.size();index++) {
			PropertyColumnMapper propertyMapper = propertyColumnMappers.get(index);
			//從實體物件中取值
			String propertyName = propertyMapper.getPropertyName();
			String getMethodName = null;
			//如果是boolean
			if(propertyMapper.getPropertyType().equals(boolean.class)) {
				getMethodName = "is"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
			} else {
				//getNo
				getMethodName = "get"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
				
			}
			try {
				//呼叫方法取值放入引數Object陣列
				parameters[index] = entityClass.getDeclaredMethod(getMethodName).invoke(entity);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		//如果Id列要儲存,獲取Id列對應屬性的值加到引數值陣列中
		if(parameterCount > propertyColumnMappers.size()) {
			try {
				String getMethodName = "get"+idField.getName().substring(0,1).toUpperCase()+idField.getName().substring(1);
				//Id列永遠在最後
				parameters[propertyColumnMappers.size()] = entityClass.getDeclaredMethod(getMethodName).invoke(entity);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		for(Object o : parameters) {
			System.out.println(o);
		}
		return update(sb.toString(), parameters);
	}
	/**
	 * update student set sname=?,sage=? where sno=?
	 * 根據Id更新:資料表字段對應的屬性都必須全部賦值,否則將置成屬性預設值
	 * @param entity 要更新的實體
	 * @return 受影響的資料行數
	 */
	public int update(E entity) {
		StringBuilder sb = new StringBuilder("update ");
		sb.append(tableName);
		sb.append(" ");
		sb.append("set ");
		for(int index=0;index<propertyColumnMappers.size();index++) {
			PropertyColumnMapper propertyMapper = propertyColumnMappers.get(index);
			
			
			sb.append(propertyMapper.getColumnName());
			sb.append("=?");
			if(index<propertyColumnMappers.size()-1) {
				sb.append(",");
			}
			
		}
		sb.append(" ");
		sb.append("where ");
		sb.append(idColumn);
		sb.append("=?");
		//update student set sname=?,ssex=?... where sno=?
		System.out.println(sb.toString());
		/*for(int i=0;i<values.length;i++) {
			System.out.println(values[i]);
		}*/
		//return update(sb.toString(), values);
		Object[] parameters = new Object[propertyColumnMappers.size()+1];
		for(int index=0;index<propertyColumnMappers.size();index++) {
			PropertyColumnMapper propertyMapper = propertyColumnMappers.get(index);
			//從實體物件中取值
			String propertyName = propertyMapper.getPropertyName();
			String getMethodName = null;
			//如果是boolean
			if(propertyMapper.getPropertyType().equals(boolean.class)) {
				getMethodName = "is"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
			} else {
				getMethodName = "get"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
				
			}
			try {
				//呼叫方法取值放入引數Object陣列
				parameters[index] = entityClass.getDeclaredMethod(getMethodName).invoke(entity);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		
		
		try {
			String getMethodName = "get"+idField.getName().substring(0,1).toUpperCase()+idField.getName().substring(1);
			parameters[propertyColumnMappers.size()] = entityClass.getDeclaredMethod(getMethodName).invoke(entity);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		for(Object o : parameters) {
			System.out.println(o);
		}
		
		return update(sb.toString(),parameters);
	
	}
	
	/**
	 * ?刪除的是哪張表的資料?
	 * ?怎麼確定主鍵的名稱?
	 * 根據主鍵查詢一條記錄並封裝為實體物件
	 * @param idValue id值
	 */
	public E get(P idValue) {
		String sql = "select * from "+tableName+" where "+idColumn+"=?";
		System.out.println("get(sql)="+sql);
		return get(sql,new Object[] {idValue});
	}
	
	/**
	 * 根據主鍵刪除一條記錄並封裝為實體物件
	 * @param idValue id值
	 * @return 受影響的資料行數
	 */
	public int delete(P idValue) {
		String sql = "delete from "+tableName+" where "+idColumn+"=?";
		System.out.println("delete(sql)="+sql);
		return update(sql,new Object[] {idValue});
	}
	
	
	/**
	 * 統計一個表中的全部記錄行數
	 * @return 全部記錄行數
	 */
	public int count() {
		String sql = "select count(*) from "+tableName;
		return count(sql, null);
	}
	
	/**
	 * 根據傳入的SQL語句統計結果集行數
	 * @param sql SQL語句
	 * @param parameters 引數值陣列
	 * @return 結果集行數
	 */
	public int count(String sql,Object[] parameters) {
		Connection conn = JdbcUtil.getConnection();
		PreparedStatement st = null;
		ResultSet rs = null;
		int rowCount = 0;
		try {
			st = conn.prepareStatement(sql);
			// 給佔位符賦值
			setParameters(st, parameters);
			rs = st.executeQuery();
			if(rs.next()) {
				rowCount = rs.getInt(1);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResultSet(rs);
			JdbcUtil.closeStatement(st);
		}
		return rowCount;
	}
	
	/**
	 * 根據查詢SQL語句查詢一條記錄並封裝為實體物件
	 * @param sql 查詢SQL語句
	 * @param parameters 佔位符的值,順序和SQL佔位符對應
	 * @return 返回封裝好的實體物件,如果記錄不存在返回null
	 */
	public E get(String sql, Object ... parameters) {
		
		Connection conn = JdbcUtil.getConnection();
		PreparedStatement st = null;
		ResultSet rs = null;
		E obj = null;
		try {
			st = conn.prepareStatement(sql);
			// 給佔位符賦值
			setParameters(st, parameters);
			rs = st.executeQuery();
			//String sql = "select bid,bname from board";
			if(rs.next()) {
				//把一行記錄封裝到一個實體物件裡
				obj = oneRowToObject(rs);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResultSet(rs);
			JdbcUtil.closeStatement(st);
		}
		return obj;
	}
	
	


	
	
	
	
	/**
	 * 根據查詢SQL語句查詢一條記錄並封裝為實體物件
	 * @param sql 查詢SQL語句
	 * @param parameters 佔位符的值,順序和SQL佔位符對應
	 * @param rowMapper 行對映物件
	 * @return 返回封裝好的實體物件,如果記錄不存在返回null
	 */
	public  <V> V get(String sql,RowMapper<V> rowMapper, Object...parameters) {
		
		Connection conn = JdbcUtil.getConnection();
		PreparedStatement st = null;
		ResultSet rs = null;
		V obj = null;
		try {
			st = conn.prepareStatement(sql);
			// 給佔位符賦值
			setParameters(st, parameters);
			rs = st.executeQuery();
			//String sql = "select bid,bname from board";
			if(rs.next()) {
				//把一行記錄封裝到一個實體物件裡
				obj = rowMapper.mapRow(rs);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResultSet(rs);
			JdbcUtil.closeStatement(st);
		}
		return obj;
	}
	

	
	
	/**
	 * 根據查詢SQL語句查詢多條記錄並封裝為實體物件集合
	 * @param sql 查詢SQL語句
	 * @param parameters 佔位符的值,順序和SQL佔位符對應
	 * @return 返回封裝好的實體物件集合,如果記錄不存在返回一個空集合
	 */
	public List<E> list(String sql, Object...parameters) {
		
		Connection conn = JdbcUtil.getConnection();
		PreparedStatement st = null;
		ResultSet rs = null;
		List<E> list = new ArrayList<>();
		try {
			st = conn.prepareStatement(sql);
			// 給佔位符賦值
			setParameters(st, parameters);
			
			rs = st.executeQuery();
			while(rs.next()) {
				//把一行記錄封裝到一個實體物件裡
				E obj = oneRowToObject(rs);
				list.add(obj);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResultSet(rs);
			JdbcUtil.closeStatement(st);
		}
		return list;
	}
	
	
	
	
	/**
	 * 單表分頁查詢
	 * @param start 開始位置
	 * @param limit 限定行數
	 * @return 返回封裝好的實體物件集合,如果記錄不存在返回一個空集合
	 */
	public List<E> list(int start,int limit) {
		String sql = "select * from "+tableName+" limit ?,?";
		return list(sql,new Object[] {start,limit});
	}
	/**
	 * 單表分頁查詢
	 * @param start 開始位置
	 * @param limit 限定行數
	 * @return 返回封裝好的實體物件集合,如果記錄不存在返回一個空集合
	 */
	public void list(Page<E> page) {
		if(page.autoCount) {
			int totalCount = count();
			page.setTotalCount(totalCount);
		}
		List<E> data = list(page.start,page.limit);
		page.setResult(data);
	}
	
	
	/**
	 * 多表連線查詢
	 * 根據查詢SQL語句查詢多條記錄並封裝為實體物件集合
	 * @param sql 查詢SQL語句
	 * @param parameters 佔位符的值,順序和SQL佔位符對應
	 * @param rowMapper 行的對映器
	 * @return 返回封裝好的實體物件集合,如果記錄不存在返回一個空集合
	 */
	public <V> List<V> listJoin(String sql,RowMapper<V> rowMapper, Object...parameters) {
		
		Connection conn = JdbcUtil.getConnection();
		PreparedStatement st = null;
		ResultSet rs = null;
		List<V> list = new ArrayList<>();
		try {
			st = conn.prepareStatement(sql);
			// 給佔位符賦值
			setParameters(st, parameters);
			
			rs = st.executeQuery();
			while(rs.next()) {
				//把一行記錄封裝到一個實體物件裡
				//回撥介面
				V obj = rowMapper.mapRow(rs);
				list.add(obj);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResultSet(rs);
			JdbcUtil.closeStatement(st);
		}
		
		return list;
	}
	
	
	
	
	
	
	/**
	 * 一行到一個物件的對映
	 * @param rs 結果集
	 * @return 設定好資料的一個物件
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws SQLException
	 */
	@SuppressWarnings("unchecked")
	private E oneRowToObject(ResultSet rs) throws InstantiationException,
			IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException {
		E obj = (E) entityClass.getConstructor().newInstance();
		//獲取結果集元資料
		ResultSetMetaData rsmd = rs.getMetaData();
		
		for(int i=0;i<rsmd.getColumnCount();i++) {
			//獲取一列的列名和資料型別
			String columnName = rsmd.getColumnName(i+1);
			Integer columnType = rsmd.getColumnType(i+1);
			//拼實體物件裡對應的set方法名
			//String methodName = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1);
			//sno -> no
			String fieldName = columnPropertyMap.get(columnName);
			if(fieldName!=null) {
			String methodName = "set"+columnPropertyMap.get(columnName).substring(0,1).toUpperCase()+columnPropertyMap.get(columnName).substring(1);
			//System.out.println(methodName);
			switch(columnType) {
				case java.sql.Types.INTEGER:
				case java.sql.Types.SMALLINT:
				case java.sql.Types.TINYINT:
					Method method = null;
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, int.class);
						if(method != null) {
							method.invoke(obj, rs.getInt(columnName));
						}
					} catch (Exception e) {
						//再試使用Integer型別對映
						method = entityClass.getMethod(methodName, Integer.class);
						if(method != null) {
							method.invoke(obj, rs.getInt(columnName));
						}
					}
					
					
					
				break;
				
				case java.sql.Types.BIGINT:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, long.class);
						if(method != null) {
							method.invoke(obj, rs.getLong(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, Long.class);
						if(method != null) {
							method.invoke(obj, rs.getLong(columnName));
						}
					}
					
				break;
				
				case java.sql.Types.BIT:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, boolean.class);
						if(method != null) {
							method.invoke(obj, rs.getBoolean(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, int.class);
						if(method != null) {
							method.invoke(obj, rs.getInt(columnName));
						}
					}
					
				break;
				
				case java.sql.Types.CHAR:
				case java.sql.Types.VARCHAR:
				case java.sql.Types.LONGVARCHAR:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					} catch (NoSuchMethodException e) {
						
					}
				break;
				case java.sql.Types.DATE:
				
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, Date.class);
						if(method != null) {
							method.invoke(obj, rs.getDate(columnName));
						}
					}
				break;
				case java.sql.Types.TIMESTAMP:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, Date.class);
						if(method != null) {
							method.invoke(obj, rs.getTimestamp(columnName));
						}
					}
				break;
				case java.sql.Types.TIME:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, Date.class);
						if(method != null) {
							method.invoke(obj, rs.getTime(columnName));
						}
					}
				break;
				case java.sql.Types.FLOAT:
				case java.sql.Types.REAL:
				case java.sql.Types.DOUBLE:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, double.class);
						if(method != null) {
							method.invoke(obj, rs.getDouble(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					}
				break;
				case java.sql.Types.DECIMAL:
					try {
						//先嚐試使用int型別對映
						method = entityClass.getMethod(methodName, BigDecimal.class);
						if(method != null) {
							method.invoke(obj, rs.getBigDecimal(columnName));
						}
					} catch (Exception e) {
						//先嚐試使用Integer型別對映
						method = entityClass.getMethod(methodName, String.class);
						if(method != null) {
							method.invoke(obj, rs.getString(columnName));
						}
					}
				break;
				default:
				break;
			}
			}
		}
		return obj;
	}
	
	
	
	/**
	 * 私有方法:給SQL語句佔位符賦值
	 * @param st PreparedStatement物件
	 * @param parameters 引數陣列
	 * @throws SQLException SQL異常
	 */
	private void setParameters(PreparedStatement st, Object[] parameters) throws SQLException {
		if (parameters != null && parameters.length > 0) {
			for (int i = 0; i < parameters.length; i++) {
				st.setObject(i + 1, parameters[i]);
			}
		}
	}
}

2.column

package com.xintoucloud.jdbcutil;

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 Column {
	/**
	 * 對映的列名,預設和屬性名一樣
	 * @return
	 */
	String value();
}

3.generateType

package com.xintoucloud.jdbcutil;

public enum GenarateType {
	AUTO_INCREMENT,
	ASSIGNED
}

4.id

package com.xintoucloud.jdbcutil;

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 {
	/**
	 * 對應的列名,預設為""和屬性名一樣
	 * @return
	 */
	String value() default "";
	/**
	 * 主鍵生成型別,預設自動增長
	 * @return
	 */
	GenarateType genarate() default GenarateType.AUTO_INCREMENT;
}

5.JdbcUtil

package com.xintoucloud.jdbcutil;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
 * 資料庫連線工具類
 * @author [email protected]
 *
 */
public class JdbcUtil {
	
	private static String DRIVER;
	private static String URL;
	private static String USER;
	private static String PASSWORD;
	
	private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
	
	static {
		InputStream is = JdbcUtil.class.getResourceAsStream("/db-config.properties");
		Properties properties = new Properties();
		
		try {
			properties.load(is);
			DRIVER = properties.getProperty("DRIVER_CLASS");
			URL = properties.getProperty("URL");
			USER = properties.getProperty("USER");
			PASSWORD = properties.getProperty("PASSWORD");
			Class.forName(DRIVER);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 獲取資料庫連線
	 * @return 資料庫連線,如果有異常返回null
	 */
	public static Connection getConnection() {
		//System.out.println("getConnection");
		//嘗試從本地執行緒變數中獲取連線
		Connection conn = THREAD_LOCAL.get();
		//如果本地執行緒變數中沒有連線
		if(conn == null) {
			try {
				//從資料庫獲取連線
				conn = DriverManager.getConnection(URL,USER,PASSWORD);
				//放入本地執行緒變數
				THREAD_LOCAL.set(conn);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return conn;
	}
	/**
	 * 開啟事務
	 */
	public static void beginTransaction() {
		Connection conn = getConnection();
		if(conn != null) {
			try {
				conn.setAutoCommit(false);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * 提交事務
	 */
	public static void commit() {
		Connection conn = getConnection();
		if(conn != null) {
			try {
				conn.commit();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * 回滾事務
	 */
	public static void rollback() {
		Connection conn = getConnection();
		if(conn != null) {
			try {
				conn.rollback();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 關閉結果集
	 * @param rs
	 */
	public static void closeResultSet(ResultSet rs) {
		try {
			if(rs != null) {
				rs.close();
				rs = null;
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 關閉Statement
	 * @param st
	 */
	public static void closeStatement(Statement st) {
		try {
			
			if(st != null) {
				st.close();
				st = null;
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 關閉連線
	 */
	public static void closeConnection() {
		Connection conn = THREAD_LOCAL.get();
		if(conn != null) {
			try {
				conn.close();
				//從執行緒本地變數中移除
				THREAD_LOCAL.remove();
				conn = null;
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 釋放資源
	 * @param conn 連線物件
	 * @param st Statement物件
	 * @param rs ResultSet物件
	 */
	public static void closeAll(Connection conn,Statement st,ResultSet rs) {
		try {
			if(rs != null) {
				rs.close();
			}
			if(st != null) {
				st.close();
			}
			if(conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

6.Page

package com.xintoucloud.jdbcutil;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @param <T>
 *            Page中記錄的型別.
 * 
 * @author YCCN
 */
public class Page<T> {

	// -- 分頁引數 --//
	protected int start;
	protected int limit;

	// 是否自動查詢總條數
	protected boolean autoCount = true;

	// -- 返回結果 --//

	protected List<T> result = new ArrayList<T>();
	// 儲存資料總條數
	protected int totalCount;

	// -- 建構函式 --//
	public Page() {
	}

	public Page(int start, int limit) {
		this.start = start;
		this.limit = limit;
	}

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public int getLimit() {
		return limit;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

	/**
	 * 獲得查詢物件時是否先自動執行count查詢獲取總記錄數, 預設為false.
	 */
	public boolean isAutoCount() {
		return autoCount;
	}

	/**
	 * 設定查詢物件時是否自動先執行count查詢獲取總記錄數.
	 */
	public void setAutoCount(final boolean autoCount) {
		this.autoCount = autoCount;
	}

	/**
	 * 獲得頁內的記錄列表.
	 */
	public List<T> getResult() {
		return result;
	}

	/**
	 * 設定頁內的記錄列表.
	 */
	public void setResult(final List<T> result) {
		this.result = result;
	}

	/**
	 * 獲得總記錄數, 預設值為0.
	 */
	public long getTotalCount() {
		return totalCount;
	}

	/**
	 * 設定總記錄數.
	 */
	public void setTotalCount(final int totalCount) {
		this.totalCount = totalCount;
	}

	/**
	 * 獲得總頁數
	 * 
	 * @return 總頁數
	 */
	public int getTotalPages() {
		if (autoCount && totalCount != -1 && limit != -1) {
			return totalCount % limit == 0 ? totalCount / limit : totalCount / limit + 1;
		}
		return 0;
	}

	/**
	 * 獲得當前頁
	 * 
	 * @return 當前頁
	 */
	public int getPageIndex() {
		if (getTotalPages() > 0) {
			return start / limit + 1;
		}
		return 0;
	}

	/**
	 * 是否有下一頁
	 * 
	 * @return
	 */
	public boolean isNextPage() {
		if (getPageIndex() < getTotalPages()) {
			return true;
		}
		return false;
	}

	/**
	 * 是否有上一頁
	 * 
	 * @return
	 */
	public boolean isPrePage() {
		if (getPageIndex() > 1) {
			return true;
		}
		return false;
	}

}

7.PropertyColumnMapper

package com.xintoucloud.jdbcutil;
/**
 * 實體屬性和列名和屬性型別的對映
 * @author Administrator
 *
 */
class PropertyColumnMapper {
	private String propertyName;
	private String columnName;
	private Class<?> propertyType;
	public PropertyColumnMapper() {}
	public PropertyColumnMapper(String propertyName, String columnName,Class<?> propertyType) {
		super();
		this.propertyName = propertyName;
		this.columnName = columnName;
		this.propertyType = propertyType;
	}
	public String getColumnName() {
		return columnName;
	}
	public String getPropertyName() {
		return propertyName;
	}
	public Class<?> getPropertyType() {
		return propertyType;
	}
	public void setColumnName(String columnName) {
		this.columnName = columnName;
	}
	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}
	public void setPropertyType(Class<?> propertyType) {
		this.propertyType = propertyType;
	}
	
}

8.RowMapper

package com.xintoucloud.jdbcutil;

import java.sql.ResultSet;

/**
 * 結果集行的對映(主要對應多表連線查詢)
 * @author Administrator
 *
 */
public interface RowMapper<V> {
	/**
	 * 結果集一行對映為一個物件
	 * @param rs 結果集
	 * @return 對映好的物件
	 */
	V mapRow(ResultSet rs);
}

9.Table

package com.xintoucloud.jdbcutil;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 設定一個實體對應的表名,如果沒有設定則和實體類名一樣
 * @author Administrator
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	String value() ;
}

10.Transient

package com.xintoucloud.jdbcutil;

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 Transient {

}

11.NoEntityClassException

package com.xintoucloud.jdbcutil.exception;

public class NoEntityClassException extends RuntimeException {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6894334255503447296L;

	public NoEntityClassException(String message) {
		super(message);
	}
}

12.NoIdException

package com.xintoucloud.jdbcutil.exception;

public class NoIdException extends RuntimeException{
	/**
	 * 
	 */
	private static final long serialVersionUID = -981438111240259266L;

	public NoIdException(String message) {
		super(message);
	}
}