Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。
QueryRunner
对象,执行方法时需要传入Connection
对象,且该Connection对象需要手动释放new QueryRunner().update(
conn,
...
);
QueryRunner
对象,执行方法时,不需要传入Connection
对象 , QueryRunner对象内部会自动释放Connectionnew QueryRunner(dataSource).update(
...
);
update()
:执行增删改的dml语句query()
:执行查询的dql语句public class Demo1 {
public static void main(String[] args) {
// add() ;
// delete() ;
// update() ;
// queryOne() ;
// queryOne1() ;
// queryAll() ;
queryAll1() ;
}
// 查全部,使用BeanListHandler保存结果集
private static void queryAll1() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
List<User> list = new QueryRunner().query(
conn,
"select * from t_user",
new BeanListHandler<User>(User.class)
) ;
System.out.println(list);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , null);
}
}
// 查全部
private static void queryAll() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
List<User> list = new QueryRunner().query(
conn,
"select * from t_user",
new ResultSetHandler<List<User>>() {
@Override
public List<User> handle(ResultSet resultSet) throws SQLException {
ArrayList<User> users = new ArrayList<>();
while (resultSet.next()) {
User user = new User(resultSet.getInt("id") , resultSet.getString("name") , resultSet.getInt("age"));
users.add(user) ;
}
return users;
}
}
) ;
System.out.println(list);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , null);
}
}
// 查单条,使用BeanHandler保存结果集
private static void queryOne1() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
User user = new QueryRunner().query(
conn,
"select * from t_user where name = ?",
new BeanHandler<User>(User.class),
"张三"
);
System.out.println(user);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , null);
}
}
private static void queryOne() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
User user = new QueryRunner().query(
conn,
"select * from t_user where name = ?",
new ResultSetHandler<User>() {
@Override
public User handle(ResultSet resultSet) throws SQLException {
User user = new User();
if (resultSet.next()) {
user.setId(resultSet.getInt(1));
user.setName(resultSet.getString(2));
user.setAge(resultSet.getInt(3));
}
return user;
}
} ,
"张三"
);
System.out.println(user);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 更新
private static void update() {
try {
new QueryRunner(JDBCUtils3.getDataSource()).update(
"update t_user set name = ? where name = ?" ,
"晁盖",
"宋江"
);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 删除
private static void delete() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
new QueryRunner().update(
conn ,
"delete from t_user where name= ?" ,
"李白"
);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , null);
}
}
// 添加
private static void add() {
Connection conn = null ;
try {
conn = JDBCUtils.getConnection() ;
new QueryRunner().update(
conn , // 连接
"insert into t_user values(null , ? , ?) ;" , // sql语句
"宋江" ,
30
) ;
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , null);
}
}
}
- 注意事项:使用
BeanHandler
、BeanListHandler
保证查询结果的字段名称
必须和Java实体类的属性名称
要一样,否则属性赋值失败,为null。可以通过取别名的方式避免这一问题
// 修改的方法
private static void update() {
Connection conn = null ;
PreparedStatement ps = null ;
try {
conn = JDBCUtils.getConnection() ;
String sql = "update t_user set t_name = ? where t_name = ?;" ;
ps = conn.prepareStatement(sql);
ps.setString(1 ,"宋江");
ps.setString(2 ,"晁盖");
int insert = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps);
}
}
// 删除的方法
private static void delete() {
Connection conn = null ;
PreparedStatement ps = null ;
try {
conn = JDBCUtils.getConnection() ;
String sql = "delete from t_user where t_name = ? ;" ;
ps = conn.prepareStatement(sql);
ps.setString(1 ,"杜甫");
int insert = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps);
}
}
// 新增的方法
private static void add() {
Connection conn = null ;
PreparedStatement ps = null ;
try {
conn = JDBCUtils.getConnection() ;
String sql = "insert into t_user values(null , ? , ?) ;" ;
ps = conn.prepareStatement(sql);
ps.setString(1 ,"杜甫");
ps.setInt(2 , 40);
int insert = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps);
}
}
- 对于上面的代码来说,大部分都是相同的,只有
sql语句
和参数列表
不同,所以我们可以先抽取出公共的部分
private static void add/delete/update() {
Connection conn = null ;
PreparedStatement ps = null ;
try {
conn = JDBCUtils.getConnection() ;
/*
sql语句不同
所传入的参数不同
*/
int update = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps);
}
}
- 对于
sql语句
,我们使用传参的方式获取,而对于参数的不同(类型不同、数量不同),可以使用可变参
来解决
/**
* 类似于DbUtils的update方法
* @param sql sql语句
* @param param 参数列表
*/
private static void update(String sql , Object... param) {
Connection conn = null ;
PreparedStatement ps = null ;
try {
conn = JDBCUtils.getConnection() ;
ps = conn.prepareStatement(sql);
// 获取sql语句中参数的个数
int parameterCount = ps.getParameterMetaData().getParameterCount();
// 使用for循环设置对应的参数
for (int i = 0; i < parameterCount; i++) {
ps.setObject(i + 1 , param[i]);
}
// 执行sql语句
int insert = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps);
}
}
JDBC查询数据的代码
// 查询一条数据
private static void queryOne() {
Connection conn = null ;
PreparedStatement ps = null ;
ResultSet rs = null ;
try {
conn = JDBCUtils.getConnection() ;
String sql = "select id , t_name name , age from t_user where t_name = ?" ;
ps = conn.prepareStatement(sql) ;
ps.setString(1 , "张三");
rs = ps.executeQuery() ;
User user = null ;
if (rs.next()) {
user = new User() ;
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
}
System.out.println(user);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps , rs);
}
}
// 查询多条数据
private static void queryAll() {
Connection conn = null ;
PreparedStatement ps = null ;
ResultSet rs = null ;
try {
conn = JDBCUtils3.getConnection() ;
String sql = "select id , t_name name , age from t_user ;" ;
ps = conn.prepareStatement(sql) ;
rs = ps.executeQuery() ;
ArrayList<User> list = new ArrayList<>();
while (rs.next()) {
User user = new User() ;
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
list.add(user) ;
}
System.out.println(list);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps , rs);
}
}
对于查询方法,查询一条和查询多条之间的区别有:
sql语句不同
参数列表不同
对结果集的封装不同
sql语句
和参数列表
都可以通过传参的形式解决,而对结果集的处理让人无从下手,但是又必须要处理,这个时候就需要用到接口
,接口就是为了处理那些必须要处理但是当前情况下又不知道会如何处理的问题的。MyResultSetHandler
,定义抽象方法handler(ResultSet rs)
,但是对于将来要处理的结果的类型并不知道,所以还需要使用到泛型
。public interface MyResultSetHandler<T> {
T handler(ResultSet rs) throws Exception;
}
/**
* 类似于DbUtils的查询方法
* @param sql sql语句
* @param handler 接口对象,用于处理结果集
* @param param 参数列表
* @param 泛型,对应未知类型的结果集对象
* @return 返回值是t
* @throws Exception 抛出可能出现的异常
*/
public static<T> T query(String sql , MyResultSetHandler<T> handler , Object... param) throws Exception{
Connection conn = null ;
PreparedStatement ps = null ;
ResultSet rs = null ;
try {
conn = JDBCUtils.getConnection() ;
ps = conn.prepareStatement(sql) ;
int parameterCount = ps.getParameterMetaData().getParameterCount();
for (int i = 0; i < parameterCount; i++) {
ps.setObject(i + 1 , param[i]);
}
// 执行查询方法获取到结果集对象
rs = ps.executeQuery() ;
// MyResultSetHandler接口调用handler()方法,交给调用该方法的对象去实现抽象方法处理结果集
T t = handler.handler(rs);
return t;
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(conn , ps , rs);
}
return null ;
}
// 查询一条数据
private static void queryOne() throws Exception {
User u = MyDbUtils.query(
"select * from t_user where id = ? ;" ,
// 实现接口中的handler()方法来处理结果集
new MyResultSetHandler<User>() {
@Override
public User handler(ResultSet rs) throws Exception {
User user = new User();
if (rs.next()) {
user.setId(rs.getInt("id"));
user.setName(rs.getString("t_name"));
user.setAge(rs.getInt("age"));
}
return user;
}
},
1
) ;
System.out.println(u);
}
// 查询多条数据
private static void queryAll() throws Exception {
List<User> list = MyDbUtils.query(
"select * from t_user",
// 实现接口中的handler()方法处理结果及
new MyResultSetHandler<List<User>>() {
@Override
public List<User> handler(ResultSet rs) throws Exception {
ArrayList<User> users = new ArrayList<>();
while (rs.next()) {
int id = rs.getInt("id") ;
String name = rs.getString("t_name") ;
int age = rs.getInt("age") ;
User user = new User(id, name, age);
users.add(user) ;
}
return users;
}
}
) ;
System.out.println(list);
}
MyBeanHandler
和MyBeanListHandler
类来对单条记录的结果集和多条记录的结果集进行封装PropertyDescriptor
描述 JavaBean
通过一对存储器方法导出的一个属性。
构造方法
PropertyDescriptor(String propertyName, Class> beanClass)
:通过调用getFoo
和setFoo
存取方法,为符合标准 Java 约定的属性构造一个PropertyDescriptor
。常用方法
Class>getPropertyType()
:获得属性的 Class 对象。MethodgetReadMethod()
:获得应该用于读取属性值的方法。MethodgetWriteMethod()
:获得应该用于写入属性值的方法。
MyBeanHandler
,实现MyResultSetHandler
接口,需要有一个字节码对象类型的属性,定义其构造方法,在创建MyBeanHandler
对象时传入结果集对象的字节码对象。通过传入的字节码对象创建一个实例对象t、获取到类的属性的数组。MyBeanHandler
类
public class MyBeanHander<T> implements MyResultSetHandler<T> {
// 字节码对象
private Class<T> clazz ;
public MyBeanHander(Class<T> clazz) {
this.clazz = clazz;
}
@Override
public T handler(ResultSet rs) throws Exception {
// 根据字节码对象创建类的实例
T t = clazz.newInstance();
// 利用反射获取到类中的属性
Field[] fields = clazz.getDeclaredFields();
if (rs.next()) {
for (Field field : fields) {
// 根据对应的属性名获取属性的set方法
// 获取属性名
String fieldName = field.getName();
// 根据属性名获取属性描述对象
PropertyDescriptor descriptor = new PropertyDescriptor(fieldName , clazz);
// 根据描述器对象获取写入属性值的方法(set方法)
Method writeMethod = descriptor.getWriteMethod();
// 通过反射调用方法
writeMethod.invoke(t , rs.getObject(fieldName)) ;
}
}
return t;
}
}
MyBeanListHandler
类
public class MyBeanListHandler<T> implements MyResultSetHandler<List<T>>{
private Class<T> clazz ;
public MyBeanListHandler(Class<T> clazz) {
this.clazz = clazz;
}
@Override
public List<T> handler(ResultSet rs) throws Exception {
List<T> list = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
while (rs.next()) {
// 根据字节码对象创建实例
T t = clazz.newInstance();
for (Field field : fields) {
String fieldName = field.getName();
PropertyDescriptor descriptor = new PropertyDescriptor(fieldName , clazz);
Method writeMethod = descriptor.getWriteMethod();
writeMethod.invoke(t , rs.getObject(fieldName)) ;
}
list.add(t) ;
}
return list;
}
}