HikariCP 抽取方法&分页

时间 2018/6/19 23:04:41 加载中...

HikariCP 参数化查询的方法已经知道了,将demo中的sql语句和参数抽离出来就形成了公用的方法了。


新增


public static int add(String sql, List<Object> params) {
	
	int result = -1;
	
	try {
		HikariDataSource dataSource = getDataSource();
		Connection connection = dataSource.getConnection();

		PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
		if (params != null) {
			for (int i = 0; i < params.size(); i++) {
				statement.setObject(i + 1, params.get(i));
			}
		}
		statement.execute();

		ResultSet resultSet = statement.getGeneratedKeys();
		if (resultSet != null) {
			if (resultSet.next())
				result = resultSet.getInt(1);
		}
		
		if (connection != null && !connection.isClosed())
			connection.close();
		if (dataSource != null && !dataSource.isClosed())
			dataSource.close();
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	return result;
}


更新 


public static int update(String sql,List<Object> params) {
	try {

		HikariDataSource dataSource = getDataSource();
		Connection connection = dataSource.getConnection();
		
		PreparedStatement statement = connection.prepareStatement(sql);
		
		if (params != null) {
			for (int i = 0; i < params.size(); i++) {
				statement.setObject(i + 1, params.get(i));
			}
		}
		
		return statement.executeUpdate();

	} catch (Exception e) {
		e.printStackTrace();
	}
	return -1;
}


查询 


public static <T> List<T> query(String sql, List<Object> params, Class<T> type) {
	try {
		/* HikariDataSource 是需要关闭的 */
		HikariDataSource dataSource = getDataSource();
		Connection connection = dataSource.getConnection();

		PreparedStatement statement = connection.prepareStatement(sql);

		if (params != null) {
			for (int i = 0; i < params.size(); i++) {
				statement.setObject(i + 1, params.get(i));
			}
		}

		ResultSet resultSet = statement.executeQuery();
		List<T> list = ResultSetHelper.toList(resultSet, type);
		
		if (connection != null && !connection.isClosed())
			connection.close();
		if (dataSource != null && !dataSource.isClosed())
			dataSource.close();
		
		return list;

	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return null;
}


转化方法


public class ResultSetHelper {

	public static <T> List<T> toList(ResultSet resultSet, Class<T> type) throws SQLException, InstantiationException,
			IllegalAccessException, NoSuchFieldException, SecurityException {
		List<T> list = new ArrayList<T>();

		if (resultSet != null) {

			ResultSetMetaData md = resultSet.getMetaData();// 获取键名
			int columnCount = md.getColumnCount();// 获取行的数量

			while (resultSet.next()) {

				// 此类要有默认的构造函数
				T instance = type.newInstance();
				Field[] fields = type.getDeclaredFields();
				
				for (int i = 1; i <= columnCount; i++) {
					String colName = md.getColumnName(i);
					Object val = resultSet.getObject(i);
								
					for (Field field : fields) {
						if (field.getName().equalsIgnoreCase(colName)) {				
							field.setAccessible(true);
							field.set(instance, val);
						}
					}
				}
				
				list.add(instance);
				
			}
		}

		return list;
	}
}


分页


分页其实是执行了两个SQL语句,一个查询SQL,一个统计SQL,且分页返回的也不只是一个 List<T>,而且还要包含 总数量 totalCount 和 总页数 totalPage

在实现分页的过程中,要分别执行 select 语句和 count 语句,

而执行 count 语句,直接获取执行结果的方法没有,即类似于 executeScalar 这样的方法,

只能是封装一个 返回 ResultSet 的方法,把 ResultSet 的第一行的第一个格子 返回去。


我们先创建一个类来代表分页方法的返回结果 

public class PageResult<T> {
	
	private List<T> data;
	private int totalCount;
	private int totalPage;
	
	public List<T> getData() {
		return data;
	}
	public void setData(List<T> data) {
		this.data = data;
	}
	
	public int getTotalCount() {
		return totalCount;
	}
	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}
	
	public int getTotalPage() {
		return this.totalPage;
	}
	
	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}
}


而分页方法应该像这个样子

PageResult<T> queryPage(String sql, List<Object> params, int currentPage, int pageSize, Class<T> type)


其内部我们需要通过参数来构成两个SQL语句。


public static <T> PageResult<T> queryPage(String sql, List<Object> params, int currentPage, int pageSize, Class<T> type) {

	PageResult<T> result = new PageResult<T>();
	
	int startIndex = (currentPage - 1) * pageSize;

	String querySql = MessageFormat.format("{0} limit {1},{2}", sql, startIndex, pageSize);
	List<T> models = SQLHelper.query(querySql, params, type);
	result.setData(models);
	
	// 或正则,将select 和 from 中间的字符串替换成 count(0);
	String countSql = MessageFormat.format("select count(0) from ({0})t ", sql);
	String countStr = SQLHelper.executeScalar(countSql, params);
	int countVal = 0;
	if (!isBlank(countStr))
		countVal = Integer.parseInt(countStr);

	int totalPage = (int) ((countVal + pageSize - 1) / pageSize);
	
	result.setTotalCount(countVal);
	result.setTotalPage(totalPage);
	
	return result;
}

private static boolean isBlank(String str) {
	int strLen;
	if (str == null || (strLen = str.length()) == 0) {
		return true;
	}
	for (int i = 0; i < strLen; i++) {
		if (Character.isWhitespace(str.charAt(i)) == false) {
			return false;
		}
	}
	return true;
}

public static String executeScalar(String sql, List<Object> params) {
	String result = null;
	try {
		/* HikariDataSource 是需要关闭的 */
		HikariDataSource dataSource = getDataSource();
		Connection connection = dataSource.getConnection();

		PreparedStatement statement = connection.prepareStatement(sql);

		if (params != null) {
			for (int i = 0; i < params.size(); i++) {
				statement.setObject(i + 1, params.get(i));
			}
		}

		ResultSet resultSet = statement.executeQuery();
		if(resultSet!=null && resultSet.next())
			result = resultSet.getString(1);
		
		if (connection != null && !connection.isClosed())
			connection.close();
		if (dataSource != null && !dataSource.isClosed())
			dataSource.close();
				
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	return result;
}


公共的一个方法

private static HikariDataSource getDataSource() throws SQLException {

	HikariConfig config = new HikariConfig();

	config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/javablog?useUnicode=true&characterEncoding=utf8&useSSL=false");
	config.setUsername("root");
	config.setPassword("123456");
	config.addDataSourceProperty("cachePrepStmts", "true");
	config.addDataSourceProperty("prepStmtCacheSize", "250");
	config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

	return new HikariDataSource(config);
}


最终把上面所有方法放入一个 SQLHelper 类中就构成了一个简单的 数据库访问类了。



版权说明
作者:SQBER
文章来源:http://sqber.com/articles/HikariCP-method-and-page.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。