DBUtils工具的使用和详解

一, 先熟悉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;
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值