一, 先熟悉DBUtils的API:
简介:DbUtils是一个为简化JDBC操作的小类库。
以下使用的是最新版的commons-dbutils-1.4,先给个简介,以便迅速掌握API的使用。
整个dbutils总共才3个包:
1、包org.apache.commons.dbutils
接口摘要
ResultSetHandler 将ResultSet转换为别的对象的工具。
RowProcessor 将ResultSet行转换为别的对象的工具。
类摘要
BasicRowProcessor RowProcessor接口的基本实现类。
BeanProcessor BeanProcessor匹配列明到Bean属性名,并转换结果集列到Bean对象的属性中。
DbUtils 一个JDBC辅助工具集合。
ProxyFactory 产生JDBC接口的代理实现。
QueryLoader 属性文件加载器,主要用于加载属性文件中的 SQL 到内存中。
QueryRunner 使用可插拔的策略执行SQL查询并处理结果集。
ResultSetIterator 包装结果集为一个迭代器。
2、包org.apache.commons.dbutils.handlers
ResultSetHandler接口的实现类
类摘要
AbstractListHandler 将ResultSet转为List的抽象类
ArrayHandler 将ResultSet转为一个Object[]的ResultSetHandler实现类
ArrayListHandler 将ResultSet转换为List<Object[]>的ResultSetHandler实现类
BeanHandler 将ResultSet行转换为一个JavaBean的ResultSetHandler实现类
BeanListHandler 将ResultSet转换为List<JavaBean>的ResultSetHandler实现类
ColumnListHandler 将ResultSet的一个列转换为List<Object>的ResultSetHandler实现类
KeyedHandler 将ResultSet转换为Map<Map>的ResultSetHandler实现类
MapHandler 将ResultSet的首行转换为一个Map的ResultSetHandler实现类
MapListHandler 将ResultSet转换为List<Map>的ResultSetHandler实现类
ScalarHandler 将ResultSet的一个列到一个对象。
3、包org.apache.commons.dbutils.wrappers
添加java.sql类中功能包装类。
类摘要
SqlNullCheckedResultSet 在每个getXXX方法上检查SQL NULL值的ResultSet包装类。
StringTrimmedResultSet 取出结果集中字符串左右空格的ResultSet包装类。
二,使用DBUtils
其实只是使用的话,只看两个类(DbUtils 和QueryRunner)和一个接口(ResultSethandler)就可以了。
1,DbUtils
DbUtils是一个为做一些诸如关闭连接、装载JDBC驱动程序之类的常规工作提供有用方法的类,它里面所有的方法都是静态的。
这个类里的重要方法有:
close():
DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,
如果不是的话,它们就关闭连接、声明和结果集(ResultSet)。
CloseQuietly:
CloseQuietly这一方法不仅能在连接、声明或者结果集(ResultSet)为NULL情况下避免关闭,
还能隐藏一些在程序中抛出的SQLEeception。如果你不想捕捉这些异常的话,这对你是非常有用的。
在重载CloseQuietly方法时,特别有用的一个方法是closeQuietly(Connection conn,Statement stmt,ResultSet rs),
这是因为在大多数情况下,连接、声明和结果集(ResultSet)是你要用的三样东西,而且在最后的块你必须关闭它们。
使用这一方法,你最后的块就可以只需要调用这一方法即可。
CommitAndCloseQuietly(Connection conn):
这一方法用来提交连接,然后关闭连接,并且在关闭连接时不向上抛出在关闭时发生的一些SQL异常。
LoadDriver(String driveClassName):这一方法装载并注册JDBC驱动程序,如果成功就返回TRUE。
使用这种方法,你不需要去捕捉这个异常ClassNotFoundException。使用loadDrive方法,编码就变得更容易理解,
你也就得到了一个很好的Boolean返回值,这个返回值会告诉你驱动类是不是已经加载成功了。
2,ResultSetHandler
这一接口执行处理一个jaca.sql.ResultSet,将数据转变并处理为任何一种形式,这样有益于其应用而且使用起来更容易。
这一组件提供了ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, MapHandler, MapListHandler, and ScalarHandler等执行程序。
ResultSetHandler接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。
因此任何ResultSetHandler 的执行需要一个结果集(ResultSet)作为参数传入,然后才能处理这个结果集,再返回一个对象。
因为返回类型是java.lang.Object,所以除了不能返回一个原始的Java类型之外,其它的返回类型并没有什么限制。
如果你发现这七个执行程序中没有任何一个提供了你想要的服务,你可以自己写执行程序并使用它。
3,QreryRunner
这个类使执行SQL查询简单化了,它与ResultSetHandler串联在一起有效地履行着一些平常的任务,它能够大大减少你所要写的编码。
QueryRunner类提供了两个构造器:其中一个是一个空构造器,另一个则拿一个 javax.sql.DataSource 来作为参数。
因此,在你不用为一个方法提供一个数据库连接来作为参数的情况下,提供给构造器的数据源(DataSource) 被用来获得一个新的连接并将继续进行下去。
这一类中的重要方法包括以下这些:
query(Connection conn, String sql, Object[] params, ResultSetHandler rsh):
这一方法执行一个选择查询,在这个查询中,对象阵列的值被用来作为查询的置换参数。
这一方法内在地处理PreparedStatement 和ResultSet 的创建和关闭。
ResultSetHandler对把从 ResultSet得来的数据转变成一个更容易的或是应用程序特定的格式来使用。
query(String sql, Object[] params, ResultSetHandler rsh):
这几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,
并且它是从提供给构造器的数据源(DataSource) 或使用的setDAtaSource 方法中重新获得的。
query(Connection conn, String sql, ResultSetHandler rsh):
这执行一个不要参数的选择查询。
update(Connection conn, String sql, Object[] params):
这一方法被用来执行一个插入、更新或删除操作。对象阵列为声明保存着置换参数。
到此为止,说明工作就差不多了,下面就实战一下,进入DBUtils使用详解二。
一,使用遵从以下步骤:
- 1.导入jar包:commons-dbcp2-2.6.0.jar 、commons-dbutils-1.7.jar、commons-pool2-2.6.2.jar、commons-logging-1.2.jar
- 2. 获取数据源dataSoucrce(通过dbcp2 采用单例模式)
- 3. 实例化 QueryRunner,得到实例化对象qr。
- 4 执行 qr.query(String sql, ResultSetHandler rsh).得到结果集
二,实战(使用DBUtils+ DBCP2)
1,获取数据源dataSource 通过dbcp2 读取db.properties配置文件
db.properties
url=jdbc:oracle:thin:@localhost:1521:orcl
username=mwb
password=oracle
driverClassName=oracle.jdbc.OracleDriver
DBCPDataSource.java
package com.mwb.db.dbutils;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
/**
* 使用dbcp作为数据源 (采用单例模式)
*
* @author meng
*
*/
public class DBCPDataSource {
// 1.定义一个单例模式的静态实例对象
private static DataSource ds = null;
// 使用静态语句块初始化变量ds变量
static {
try {
// 加载数据库属性配置文件
// 使用Properties工具类加载db.properties配置文件的内容
Properties prop = new Properties();
prop.load(DBCPDataSource.class.getClassLoader().getResourceAsStream("db.properties"));
// 通过指定的数据库配置信息获取数据源对象
ds = BasicDataSourceFactory.createDataSource(prop);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 2.构造方法私有化
private DBCPDataSource() {
}
// 3、提供一个统一的单例模式对象的获取方法接口
public static DataSource getDataSource() {
return ds;
}
}
数据库表:
create table emps(
emp_id number(10) constraint emps_emp_id_pk primary key not null,
emp_name nvarchar2(10),
emp_birthday date
--表级约束
-- constraint emps_emp_id_pk primary key(emp_id)
);
--创建自增主键的序列
create sequence seq_emps_emp_id
start with 1604240701
increment by 1;
--创建主键自增触发器
create or replace trigger trigger_emps_emp_id
before insert on emps
for each row
begin
select seq_emps_emp_id.nextval into :new.emp_id from dual;
end;
JavaBean:
package com.mwb.domain;
import java.util.Date;
public class Emp {
private Integer emp_id;
private String emp_name;
private Date emp_birthday;
public Emp() {
}
public Emp(Integer emp_id, String emp_name, Date emp_birthday) {
super();
this.emp_id = emp_id;
this.emp_name = emp_name;
this.emp_birthday = emp_birthday;
}
public Integer getEmp_id() {
return emp_id;
}
public void setEmp_id(Integer emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public Date getEmp_birthday() {
return emp_birthday;
}
public void setEmp_birthday(Date emp_birthday) {
this.emp_birthday = emp_birthday;
}
@Override
public String toString() {
return "Emp [emp_id=" + emp_id + ", emp_name=" + emp_name +
", emp_birthday=" + emp_birthday + "]";
}
}
2. 测试类 BUtilsTestDriver.java
package com.mwb.db.dbutils;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.jupiter.api.Test;
import com.mwb.domain.Emp;
/**
* 测试 DBCPDataSource
* @author meng
*
*/
public class DBUtilsTestDriver {
@Test
public void testDBUtils() {
//获取数据源对象
DataSource ds = DBCPDataSource.getDataSource();
//DBUtils 需要使用QueryRunner查询器对象进行sql语句执行(等价于statment)
QueryRunner qr = new QueryRunner(ds);
String strSql = "select * from emps";
//执行查询 获取结果集(List<JavaBean>)
try {
List<Emp> list = qr.query(strSql, new BeanListHandler<Emp>(Emp.class));
System.out.println(list);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
https://blog.csdn.net/dawiebazhanlang/article/details/80320996
DbUtils 是一个jdbc的工具,使用的范围内非常广,主要是为了简化jdbc的代码。
核心类:QueryRunner; ResultSetHandler(是一个接口,主要是完成ORM映射,把结果街转化成
我们需要的java对象)
核心方法:
* update();用来执行DML(DML:insert update delete;);
* query();用来执行DQL(DQL: select);
* batch(); 用来执行批处理;
调用本方法之前,需要先创建对象,代码如下:
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
//当使用的是无参的构造器时,可以不提供连接池对象,但是在接下来的调用方法是,必须为方法提供Connection
对象。
对于结果集的处理有以下几个结果集处理器:
*BenaHandler //把单行结果集的数据封装成javaBean对象,返回值是ResultSetHandler
ResultSetHandler <javaBean类型> rsh = new BeanHandler<javaBean类型>(javaBean.class);
本方法多用于在 处理把单行结果集封装成JavaBean对象。(对象时通过反射完成创建的)
*BeanListHandler
List<javaBean类型> list = <List<javaBean类型>> new BeanListHandler<javaBean类型>(javaBean.class);
本方法多用于把多行结果集封装成对象,并且把对象添加到集合中,新版本中可能不需要进行类型的转换,
的到集合可以通过foreach循环来进行遍历。
*MapHandler
Map <String,Object> map = new MapHandler();
本方法是用来吧单行结果集封装到一个Map中其中map的键是表中的列名称,值对应表的列值。
*MapListHandler
List<Map<String,Object>> listmap = new MapListHandler();
本方法是用来多行结果集的处理,把每行的结果封装成一个map,最后把所有的,安排都装刀片一个集合中
返回值是一个集合,但是集合中存放的是map,
*ColumnHandler
List<Object> nameList = new ColumnHandler();
本方法是用来出来单列,单行 或者多行的数据
*ScalarHandler
本方法是用于处理单行单列的数据,多用于聚合函数的查询,但是以一个点需要注意,就是当聚合函数是涉及到
数字类型的时候,一定要注意返回值类型的转换。有的人会选用Integer,long等类型,这些严格来说都是不合法
的,例如,long类型最大只能容纳20的阶乘,21的阶乘就会包异常,所以我们要选用Number(这个是所有数据类型)
的父类,并且对外提供的有Number.intValue(),和Number.LongValue(),等方法。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
持久层框架ORM底层通过反射实现
通用代码
package com.mwb.db;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.mwb.domain.Emp;
public class DBDriver520 {
/**
* 获取数据库连接 conn
*
* @return 数据库连接对象
*/
public Connection getConn() {
Connection conn = null;
// 一、加载数据库驱动
// 加载数据库驱动类的实例 需要传入的参数有
// 1.数据库的连接串(URL)
// 2.数据库用户名
// 3.数据库访问密码
// Oracle数据库url jdbc:oracle:thin:@host:1521:SID
String strURL = "jdbc:oracle:thin:@localhost:1521:orcl";
String strUsername = "mwb";
String strPsw = "oracle";
// 使用反射的方式创建数据库驱动类的实例
try {
Class.forName("oracle.jdbc.OracleDriver");
// 二、建立数据库链接
conn = DriverManager.getConnection(strURL, strUsername, strPsw);
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
public ResultSet query(String strSql) {
Statement st;
ResultSet executeQuery = null;
try {
st = getConn().createStatement();
executeQuery = st.executeQuery(strSql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return executeQuery;
}
/**
* 可以提前关闭数据库资源 将结果集转换为ListMap集合
*
* @param strSql
* @return
*/
public List<Map<String, Object>> queryList(String strSql) {
List<Map<String, Object>> lst = new ArrayList<>();
try (
Connection conn = getConn();
Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = st.executeQuery(strSql);
// conn.createStatement(
// ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.TYPE_FORWARD_ONLY)
) {
rs.beforeFirst();
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
for (int i = 1; i <= count; i++) {
map.put(metaData.getColumnLabel(i), rs.getObject(metaData.getColumnLabel(i)));
}
lst.add(map);
}
} catch (Exception e) {
// TODO: handle exception
}
return lst;
}
/**
* JavaBean
* 代码写死的笨拙方法
* @param strSql
* @return
*/
public List<Emp> queryBean(String strSql) {
List<Emp> list = new ArrayList<Emp>();
try {
Connection conn = getConn();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(strSql);
// ResultSetMetaData rsmd = rs.getMetaData();
// int count = rsmd.getColumnCount();
// System.out.println(count);
while (rs.next()) {
Emp emp = new Emp();
//代码写死
emp.setEmp_id(Integer.parseInt(rs.getObject(1).toString()));
emp.setEmp_name(rs.getObject(2).toString());
// String date = rs.getObject(3).toString();
emp.setEmp_birthday(rs.getDate(3));
list.add(emp);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
/**
* 通过泛型+反射的方式 获取结果集存放如list集合中(通用方法)
*
* @param strSql 查询sql语句
* @param clazz 实体类的Class对象
* @return List+Bean 的查询结果集
*/
public <T> List<T> queryListBean(String strSql, Class<T> clazz) {
List<T> list = new ArrayList<T>();
try (
Connection conn = getConn();
Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = st.executeQuery(strSql);) {
rs.beforeFirst();
while (rs.next()) {
T emp = clazz.newInstance();
// 方法一 使用filed的set方法设置
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 获取属性名
String fieldName = field.getName();
// 通过属性名 在结果集中得到相对应的值
// 下面代码数值转换异常,在Oracle数据库中 Number类型映射到Java中是BigDecimal类型,无法直接转换
// Object object = rs.getObject(fieldName);
//就需要用到类型转换函数
Object obj = change(field.getType(), rs, fieldName);
field.setAccessible(true);
field.set(emp, obj);
System.err.println("obj:" + obj);
}
list.add(emp);
// 方法二 使用方法对象的setXXX获取方法对象 然后调用invoke进行设置
// 方法三:使用apache提供的BeanUtils的反射巩工具类
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return list;
}
/**
* 类型转换函数
* @param type
* @param rs
* @param fieldName
* @return
* @throws SQLException
*/
private Object change(Class<?> type, ResultSet rs, String fieldName) throws SQLException {
// TODO Auto-generated method stub
Object obj = null;
switch (type.getTypeName()) {
case "java.lang.String":
obj = rs.getString(fieldName);
break;
case "java.lang.Integer":
obj = rs.getInt(fieldName);
break;
case "java.util.Date":
obj = rs.getDate(fieldName);
break;
}
return obj;
}
}