问题引出
显然这也是一个JDBC工具类-这个是一个类库,包含多个类
这个工具类库中的类不同于之前的工具类
问题
1.之前的工具类有一个问题-就是当我们的connection关闭之后
如果我们调用的是查询返回resultSet那么这个resultSet也会被关闭(无法再获取数据)
就无法调用
我们需要保证得到数据再快速释放连接来保证效率
这两者是冲突的,所以就出现了这个工具类
2.resultSet不利于数据管理(只能用一次)-就算你用完后再释放连接,可能后面也需要这些数据,但是resultSet也关闭了,就不能再次调用数据
3.就是我们只能通过getInt/String…(位置/“列名”)获取相应数据
不直观,还要自己判断类型,更希望通过方法名直观体现-getName()这种
解决方法
1.创建一个和我们表相对的简单类(列名-变量名和数据类型相对应)
2.想办法我们我们结果集取得的数据一个个赋值给对象,然后把我们的actor对象存储到ArrayList中,就得到了对应数据
土办法代码封装
这里就根据我们之前的推论自己实现一下
先写一个简单的actor类-需要无参和有参构造器,所有属性的get和set
import java.util.Date;
/**
* Actor 对象和 actor表的记录对应
*
*/
public class Actor { //Javabean, POJO, Domain对象
private Integer id;
private String name;
private String sex;
private Date borndate;
private String phone;
public Actor() { //一定要给一个无参构造器[反射需要]
}
public Actor(Integer id, String name, String sex, Date borndate, String phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.borndate = borndate;
this.phone = phone;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBorndate() {
return borndate;
}
public void setBorndate(Date borndate) {
this.borndate = borndate;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "\nActor{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", borndate=" + borndate +
", phone='" + phone + '\'' +
'}';
}
}
主程序代码
@Test
public ArrayList<Actor> testSelectToArrayList() {
System.out.println("使用 druid方式完成");
//1. 得到连接
Connection connection = null;
//2. 组织一个sql
String sql = "select * from actor where id >= ?";
PreparedStatement preparedStatement = null;
ResultSet set = null;
ArrayList<Actor> list = new ArrayList<>();//创建ArrayList对象,存放actor对象
//3. 创建PreparedStatement 对象
try {
connection = JDBCUtilsByDruid.getConnection();
System.out.println(connection.getClass());//运行类型 com.alibaba.druid.pool.DruidPooledConnection
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1);//给?号赋值
//执行, 得到结果集
set = preparedStatement.executeQuery();
//遍历该结果集
while (set.next()) {
int id = set.getInt("id");
String name = set.getString("name");//getName()
String sex = set.getString("sex");//getSex()
Date borndate = set.getDate("borndate");
String phone = set.getString("phone");
//把得到的resultset 的记录,封装到 Actor对象
//放入到list集合!!!
list.add(new Actor(id, name, sex, borndate, phone));
}
System.out.println("list集合数据=" + list);
for(Actor actor : list) {
System.out.println("id=" + actor.getId() + "\t" + actor.getName());
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtilsByDruid.close(set, preparedStatement, connection);
}
//因为ArrayList 和 connection 没有任何关联,所以该集合可以复用.
return list;
}
匹配sql和JavaBean(创建的类)属性之间的匹配问题
简单来说
int,double等基本数据类型在java对应数据类型的包装类(比如sql的int对应Java的Integer)
sql的日期形-java.utils.Date
sql的varchar,char-java的String
简介
常用的工具类
1.QueryRunner类-封装sql运行实现CRUD以及批处理
2.ResultSetHandler接口-处理ResultSet
这些是实现了ResultHandler的一些类
这里的JavaBean相当于我们之前创建的简单类
代码
首先!还是要导入jar包的!就之前那样
package yuan.hsp.JDBC.jdbcutils;
import java.sql.Connection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import yuan.hsp.JDBC.conchi.druidutils;
//用commons-dbutils也是目前最高效的工具类库-需要导入jar包
public class ThelasApacheutils {
public static void main(String[] args) throws Exception {
//1.得到连接(druid)
Connection connection = druidutils.getConnection();
//2.引入相应jar包
//3.创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
//4.执行相关的方法返回ArrayList结果集
String sql="select * from actor where id >= ?";
//解释:
//query方法就是1.执行sql语句,得到result---封装到--》ArrayList集合中,然后返回集合
//2.sql语句就是我们需要执行的语句
//3.需要先得到connection连接
//4.new BeanListHandler<>(Actor.class):在将resultSet->Actor对象-》封装到ArrayList对象中
//传class对象看具体的数据结构-决定sql哪个参数传给java类哪个参数,底层用反射机制
//5.最后的参数1,是传给我们sql语句的?的,有多个问号就写多个,按照顺序,写到最后
//6.底层得到的resultset会在query关闭,还有底层创建的prepareStatement也会关闭,我们只需要释放连接即可
List<Actor> query = queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
System.out.println("输出集合信息");
for (Actor q : query) {
System.out.println(q);
}
//5.释放资源
druidutils.close(null, null, connection);
}
}
query这个方法逆天的
底层等会我们细究
不仅帮我们自动匹配属性和sql的列
还帮我们把resultSet的属性按照我们创建的
ResultHanddler下的类按照对应形式来存储到对应的List对象中
返回,而且帮我们自动关闭了ResultSet和prepareStatement
我们需要写简单类,获取连接,写sql语句,关闭连接
其他全可以让这个工具类完成
源码分析
new BeanListHandler<>(Actor.class)
这里就和Actor已经绑定了
分析 queryRunner.query方法:
public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
PreparedStatement stmt = null;//定义PreparedStatement
ResultSet rs = null;//接收返回的 ResultSet
Object result = null;//返回ArrayList
try {
stmt = this.prepareStatement(conn, sql);
//创建PreparedStatement
this.fillStatement(stmt, params);
//对sql 进行 ? 赋值,params就是我们对应参数
rs = this.wrap(stmt.executeQuery());
//执行sql,返回resultset
result = rsh.handle(rs);//rsh是ResultSetHandler那个,返回集合
//返回的resultset --> arrayList[result] [使用到反射,对传入class对象处理]
} catch (SQLException var33) {
this.rethrow(var33, sql, params);//异常处理
} finally {
try {
this.close(rs);//关闭resultset
} finally {
this.close((Statement)stmt);//关闭preparedstatement对象
}
}
return result;
}
ResultSetHandler实现类(查询操作)
我们创建的这种类决定,query返回的数据和数据类型-到底是每一行,还是第一行,还是某一列
比如现在我们想查询一行数据只用一个对象接收即可
@Test
public void tset_cha2() throws SQLException {
//1.获取连接
Connection connection = druidutils.getConnection();
//2.创建QueryRunner对象,组织sql语句
QueryRunner queryRunner = new QueryRunner();
String sql="select * from actor where id = ?";
//3.看SQL语句要返回单个,这里用我们创建的对象接收的话,对应的ResultSetHandler的实现类为BeanHandler
Actor query = queryRunner.query(connection, sql, new BeanHandler<>(Actor.class), 1);
System.out.println(query.getName()+query.getPhone()+query.getSex());
//4.释放资源
druidutils.close(null, null, connection);
}
单列单行
这里用的是上图没写的,步骤其实都差不多
ScalarHandler
控制台输出
Apache-DML操作
挺简单的
接收换个方法从query变为update
@Test
public void tset_DML() throws SQLException {
//1.获取连接
Connection connection = druidutils.getConnection();
//2.创建QueryRunner对象,组织sql语句
QueryRunner queryRunner = new QueryRunner();
String sql="update actor set name = ? where id = ?";
//3.update执行dml语句
int update = queryRunner.update(connection, sql, "郭靖", 4);
//返回的是受影响的行数
System.out.println("受影响的行数位"+update);
//4.释放资源
druidutils.close(null, null, connection);
}