QueryRunner查询数据库& QueryRunner如何封装起来的 |
---|
首先 查看相关API
(一).使用类和方法
(二)在详细的解析了JDBC使用C3P0 或 DBCP获取了连接Connection 之后
进一步的需要对数据库进行数据的增删改查一系列的操作
其中大多数操作(其实可以封装在DAO里)不外乎(操作这些共同的方法)
public interface DAO {
/* 一、批量处理的方法
*
* @param connection: 数据库连接
* @param sql: SQL语句
* @param args: 填充占位符的Object []类型的可变参数
*/
void batch(Connection connection,String sql,Object[] ...args);
/* 二、返回具体的一个值 如 平均成绩 总数
*
* @param connection: 数据库连接
* @param sql: SQL语句
* @param args: 填充占位符的可变参数
*/
E getForValue(Connection connection,String sql,Object ...args);
/* 三、返回一个T的一个集合相当于查询所有记录
*
* @param connection: 数据库连接
* @param sql: SQL语句
* @param args: 填充占位符的可变参数
*/
List getForList(Connection connection,String sql,Object ...args);
/* 四、返回一个T的对象
*
* @param connection: 数据库连接
* @param sql: SQL语句
* @param args: 填充占位符的可变参数
*/
T get(Connection connection,String sql,Object ...args) throws SQLException;
/* 五、增删改操作
*
* INSERT UPDATE DELETE
* @param connection: 数据库连接
* @param sql: SQL语句
* @param args: 填充占位符的可变参数
*/
void update(Connection connection,String sql,Object ...args) throws SQLException;
}
//正如我们平时使用最流行的 方法进行操作 不多说 上代码
<1>首先导入jar包(驱动和连接池的不算)
commons-dbutils-1.3.jar
<2>封装使用C3P0获取连接和关闭连接 这两个方法封装如下:
public class JDBCUtils {
//数据库连接池值应该被初始化一次放在静态代码块中
private static DataSource datasource=null;
static{
datasource =new ComboPooledDataSource("helloc3p0");
}
public static Connection getConnection() throws SQLException{
return datasource.getConnection();
}
//用完资源后需要关闭
/*释放资源:
Connection
Statement
ResultSet
1 尽量晚创建早释放
2 后使用的先关闭*/
public static void release(ResultSet rs,Statement statement,Connection conn){
if(rs!=null){
try{
rs.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(statement!=null){
try{
statement.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
<3>步创建QueryRunner 实例对象 调用query()方法
例一、以最复杂查询所有对象的键值对为例如下:
//分析所有对象的键值对 ①键值对需要放在Map集合中 多个对象需要放在集合中 所以如下
//不同的查询方法只是返回结果需要实现的ResultSetHandler接口对象不同
//测试查询List
@Test
public void testMapList() throws Exception{
Connection conn =JDBCUtils.getConnection();
//创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//调用方法其query查询方法
try{
//下面需要根据查询方法创建ResultSetHandler对象
//将结果集中的每一行数据都封装到一个Map里,然后再存放到List
List
}
例二、查询返回某个值如(总数和 或 平均分)
实现如下:
//测试查询单个值
@Test
public void testScalar() throws Exception{
Connection conn =JDBCUtils.getConnection();
//创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//调用方法
Object query = qr.query(conn, "select count(*) from student", new ScalarHandler());
//此处测试直接打印(实际应用中返回结果)
System.out.println(query);
//关闭连接
JDBCUtils.release(conn, null, null);
}
使用的操作实现类有两个是prepareStatement和Statement
使用的结果处理有ResultSetMetaData实现类获取结果对象的对应值
★★那么prepareStatement和Statement它们有什么区别呢???
第一:
prepareStatement会先初始化SQL
先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。
createStatement不会初始化,没有预处理,没次都是从0开始执行SQL
第二:
prepareStatement可以替换变量
在SQL语句中可以包含?,可以用ps=conn.prepareStatement("select* from Cust where ID=?");
int sid=1001;
ps.setInt(1, sid);
rs = ps.executeQuery();
可以把?替换成变量。
而Statement只能用
int sid=1001;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from Cust where ID="+sid);
来实现。
第三:
prepareStatement会先初始化SQL,
先把这个SQL提交到数据库中进行预处理,多次使用可提高效率。
createStatement不会初始化,没有预处理,没次都是从0开始执行SQL
例一:
使用方式一:获取对象为statement进行查询单个对象如下
/**一、使用statement测试查询单个对象
*
* @throws Exception
*/
@Test
public void testQuery() throws Exception{
Connection connection =JDBCUtils.getConnection();
//获取执行命令对象
Statement statement = connection.createStatement();
//执行★
ResultSet set = statement.executeQuery("select sex,name from 表名");
while(set.next()){
// Object id = set.getObject(1);//得到第一列
Object name = set.getObject(2);//得到第2列
Object sex = set.getObject(1);//得到第3列
// Object email = set.getObject(4);//得到第4列
// Object borndate = set.getObject(5);//得到第5列
//输出一个就行测试
System.out.println(name+"\t"+sex);
}
//释放资源
JDBCUtils.release(set, statement,connection);
}
}
例二:
使用方式二:使用PreparedStatement 的对象prepareStatement 改进方式一
查询所有对象如:
public List query(Class clazz, String sql, Object... objects) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
List list=new ArrayList<>();
try {
//1.获取连接
connection = JDBCUtils.getConnection();
//2.获取PreparedStatement对象prepareStatement
statement = connection.prepareStatement(sql);
//为sql占位符 赋值
for (int i = 0; i < objects.length; i++) {
statement.setObject(i+1, objects[i]);
}
//3.执行sql 进行executeQuery()查询操作并处理结果
set= statement.executeQuery();
//创建ResultSetMetaData对象获取查询结果的对象对应值
ResultSetMetaData metaData = set.getMetaData();
while(set.next()){
//通过反射创建对象
T t = clazz.newInstance();//实体类必须有无参构造
//遍历结果集
for (int i = 0; i < metaData.getColumnCount(); i++) {
//得到列名
String name = metaData.getColumnLabel(i+1);
//得到列对应的值
Object value = set.getObject(name);
//通过反射设置属性
Field field = clazz.getDeclaredField(name);
//利用反射对private私有属性进行暴力破解
field.setAccessible(true);
//调用封装的实体类中的set()方法给属性赋值
field.set(t, value);
}
// 将对象放入ArrayList集合中
list.add(t);//将t添加到list
}
//返回最终结果
return list;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}finally{
//关闭连接
JDBCUtils.release(connection, statement, set);
}
}
在使用QueryRunner 之前我们的操作对象有两个
1.prepareStatement和Statement
调用其方法:
execute()进行查询 相当于 QueryRunner的query()方法
executeUpdate()进行增删改 相当于 QueryRunner的update()方法
2、使用apache下的PropertyUtils将对象赋予查询的结果
import org.apache.commons.beanutils.PropertyUtils;
PropertyUtils.setProperty(t, name, value);
2.处理结果方法有ResultSetMetaData的对象
调用其方法:
metaData.getColumnCount()获取结果集长度
//获取其列名或别名
String name = metaData.getColumnLabel(i+1);
//获取其列名或别名对应的值
Object value = set.getObject(name);
//将获取值放入对象中
PropertyUtils.setProperty(t, name, value);
相当于相当于 QueryRunner的ResultSetHandler的不同实现对象方法