自制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 yccn@163.com
 *
 */
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);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值