DBUtils框架QueryRunner的 使用

本文介绍了DBUtils的开发步骤,包括复制jar包、使用核心类QueryRunner完成读写及批量操作。重点阐述了QueryRunner的查询操作,以及处理事务的三种版本,如转账业务,还探讨了不同版本的优缺点,并提及使用ThreadLocal管理事务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DBUtils 使用:

开发步骤

(1)copy jar包:
(2)核心类: QueryRunner类:
(3)使用核心类完成读写,以及批量操作:

写:
删除,
更新:
添加: 调用同一个方法: update()

package com.yidongxueyuan.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;

import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialClob;
import javax.sql.rowset.serial.SerialException;

import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;

import com.yidongxueyuan.utils.C3P0Util;

public class QueryRunnerTest {
	//修改: 添加
	@Test
	public void testUpdate() throws Exception {
		//不考虑事务: 
		
		QueryRunner qr = new QueryRunner(C3P0Util.getDataSource()); 
		
		int num = qr.update("insert into account (id, name, money) values(?,?,?)",new Object[]{1001,"王导演",250} );
		System.out.println(num);
	}
	//删除操作: 
	@Test
	public void testdelete() throws Exception {
		//不考虑事务: 
		
		QueryRunner qr = new QueryRunner(C3P0Util.getDataSource()); 
		
		int num = qr.update("delete from account where id=?",new Object[]{1001} );
		System.out.println(num);
	}
	
	//修改:   自己完成: 
	
	
	//操作大数据: 大文本, 大字节:
	
	//写入: 大文本
	@Test
	public void testBigText()throws IOException, SerialException, SQLException{
		
		
		QueryRunner qr = new QueryRunner(C3P0Util.getDataSource()); 
		
		String sql ="insert into t3 values(?,?)"; 
		
		//使用流进行读取外部的文件; 
		File file = new File("C:\\Users\\Mrzhang\\Desktop\\分页.txt");
		Reader reader = new FileReader(file); 
		
		//读取: 
		char chs []= new char[(int)file.length()];
		 
		reader.read(chs);//数据在字符数组当中: 
		
		
		//clob这是java当中提供的字符对象: SerialClob clob的是一个实现类:  
		Clob  clob = new SerialClob(chs); 
		
		Object [] params = {2,clob};
		qr.update(sql, params); 
	}
	
	//写入大字节: 
	@Test
	public void testBigBlob()throws IOException, SerialException, SQLException{
		
		
		QueryRunner qr = new QueryRunner(C3P0Util.getDataSource()); 
		
		String sql ="insert into t4 values(?,?)"; 
		
		//使用流进行读取外部的文件; 
		File file = new File("C:\\Users\\Mrzhang\\Desktop\\01.png");
		
		//字节流读取图片数据: 
		InputStream in = new FileInputStream(file); 
		
		byte b[]= new byte[(int)file.length()];
		
		
		//clob这是java当中提供的字符对象: SerialClob clob的是一个实现类:  
		Blob blob = new SerialBlob(b); 
		
		Object [] params = {2,blob};
		qr.update(sql, params); 
	}
	
	
	
	//批量操作: 
	@Test
	public void testbatch()throws IOException, SerialException, SQLException{
		
		
		QueryRunner qr = new QueryRunner(C3P0Util.getDataSource()); 
		
		String sql ="insert into account values(?,?,?)"; 
		
		Object params [][]= new Object[10][];// 二维数组前面的【】: 记录的条数:  后面的【】是负责: ? 每条记录需要的参数的值: 
		
		for(int i=0 ; i< params.length ;i++){
			params[i]= new Object[]{i+10,"王导演"+i,i+100.0};
		}
		//执行批量
		qr.batch(sql, params); ///二维数组:
	}
	
}

二: QueryRunner的查询操作:

query方法:

各种结果集处理器的使用:
关于处理器是个什么东西,就是各种集合或者javabean的处理器,哪种处理器就封装哪种类型的数据吧。我的理解

package com.yidongxueyuan.test;

import java.sql.Connection;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.KeyedHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

import com.yidongxueyuan.domain.Account;
import com.yidongxueyuan.utils.C3P0Util;

/*
 * 测试结果处理器: 
 */
public class TestResultSet {
	private QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());//构造的时候,需要指定一个数据源:
	@Test
	
	//ArrayHandler 处理器, 只适应于一条结果的的情况, 将表当中的第一条数据封装到了一个Object[] 数组当中: 
	public void testDemo01() throws Exception {
		Connection conn= null;
		try {
			
//			 conn = C3P0Util.getConnection();
			 
			 String sql = "select * from account"; //没有参数: 
			 //查询操作: 
			 Object[] objs = qr.query(sql, new ArrayHandler() );
			 
			 System.out.println(Arrays.toString(objs));// [1, aaa, 800.0]
			 
		} catch (Exception e) {
			// TODO: handle exception
		} 
	}
	
	//  ArrayListHandler 适用于有多行的记录, 把每一条记录都封装到了不同的Object[]数组当中。 然后将Object数组放在list集合当中:
	@Test
	public void testDemo02() throws Exception {
		Connection conn= null;
		try {
			
			 
			 String sql = "select * from account"; //没有参数: 
			 //查询操作: 
			  List<Object[]> list = qr.query(sql, new  ArrayListHandler() );
			 
			 System.out.println(list.size());//
			 
		} catch (Exception e) {
		} 
	}
	
	// BeanHandler, 适应于一条记录,将结果集封装了一个JavaBean当中: 没有指定查询具体的某一条记录, 查询表当中的第一条记录:   
	@Test
	public void testDemo03() throws Exception {
		Connection conn= null;
		try {
			
			 
			 String sql = "select * from account where id=? "; //没有参数: 
			 //查询操作: 
			  Account account =(Account) qr.query(sql, new  BeanHandler(Account.class) ,10);
			  System.out.println(account);//
			 
		} catch (Exception e) {
		} 
	}
	
	//  BeanListHandler 将每一条记录封装到了实体Bean,把这个实体bean存放在list 集合当中:   List<Account> 
	@Test
	public void testDemo04() throws Exception {
		Connection conn= null;
		try {
			
			 
			 String sql = "select * from account "; //没有参数: 
			 //查询操作: 
			  List<Account> list = qr.query(sql, new  BeanListHandler(Account.class));
			  System.out.println(list);//
			  
			  for (Account account : list) {
				System.out.println(account);
			}
			 
		} catch (Exception e) {
		} 
	}
	
	
	@Test //ColumnListHandler 适合封装具体的某一列: List<Object > 
	public void testDemo05() throws Exception {
		Connection conn= null;
		try {
			
			 
			 String sql = "select name from account  "; //没有参数: 
			 //查询操作: 
			 List<Object> list = qr.query(sql, new  ColumnListHandler("name"));
			  
			  for (Object name : list) {
				System.out.println(name);
			}
			 
		} catch (Exception e) {
		} 
	}
	
	
	@Test //KeyedHandler  将查询的结构封装到了一个map集合当中: Map<keyName,  Map<id, idvalue> >
	public void testDemo06() throws Exception {
		Connection conn= null;
		try {
			 
			 String sql = "select id,name from account  "; //没有参数: 
			 //查询操作: 
			 Map<Object, Map<String, Object>> query = qr.query(sql, new  KeyedHandler("name"));
			  
			//遍历: 
			 for(Map.Entry<Object, Map<String, Object> > bme:   query.entrySet() ){
				 System.out.println("====");
				 for (Map.Entry<String,Object> lme: bme.getValue().entrySet()) {
					System.out.println(lme.getKey()+":::"+lme.getValue());
				}
			 }
			 
		} catch (Exception e) {
		} 
	}
	
	//MapHandler 只适应于一条记录:  Map<String, Object> stirng:列的名称: Object: 列的值: 默认值值查询第一条记录:
	@Test 
	public void testDemo07() throws Exception {
		Connection conn= null;
		try {
			 
			 String sql = "select * from account where id=?"; //没有参数: 
			 //查询操作: 
			 //列名  列的值:
			  Map<String, Object> query = qr.query(sql, new  MapHandler(),10);
			  
			//遍历: 
				 for (Map.Entry<String,Object> lme: query.entrySet()) {
					System.out.println(lme.getKey()+":::"+lme.getValue());
				}
			 
		} catch (Exception e) {
		} 
	}
	
	// MapListHandler 适合多条记录:  List<Map<String, Object>>
	@Test 
	public void testDemo08() throws Exception {
		try {
			 
			 String sql = "select * from account"; //没有参数: 
			 //查询操作: 
			 //列名  列的值:
			  List<Map<String, Object>> list = qr.query(sql, new  MapListHandler());
			  
			//遍历: 
			  for(Map<String,Object> map: list){
				  for (Map.Entry<String,Object> lme: map.entrySet()) {
					  System.out.println(lme.getKey()+":::"+lme.getValue());
				  }
			  }
		} catch (Exception e) {
		} 
	}
	
	
	//ScalarHandler 适应于当行单列的结果集; select count(*) from tableName;
	@Test 
	public void testDemo09() throws Exception {
		try {
			 
			 String sql = "select count(*) from account"; //没有参数: 
			 //查询操作: 
			 //列名  列的值:
		     Object count = qr.query(sql, new  ScalarHandler());
			  
			System.out.println(count);
		} catch (Exception e) {
		} 
	}
	
	
	
	
}

三: QueryRunner 处理事务:

这里只放最后一个代码~
其他代码放在github上 ~ ~
https://gitee.com/wohaocai/query.
1: 事务: 操作单元:

2: 处理事务:

需求: 转账: 有事务的支持:
三个版本:

转账版本一:
QueryRunner 处理事务:
query(conn, sql, param);
query(conn, sql, param);

处理事务:
(1)构建QueryRunner对象的时候,没有必要指定数据源:
(2)执行具体方法的时候, 动态的传递一个conn对象:
这样保证了不同的方法使用的conn 对象是同一个对象。
既然是同一个conn 对象, 就可以保证多个操作处于同一个事务当中。

总结:
现在将业务方法定义在dao层: dao层定义数据库的访问方法, 不应该定义业务方法。
将业务方法定义在业务层,dao只定义增删改查的方法:

转账的 版本二:
优点: 将业务方法定义了业务service层:
dao层只定义了和数据库相关的增删改查的方法:

具体的操作:
dao层: 保证conn 的唯一: 采用注入的 方式: 有service层给dao层传递conn, 这样就保证了conn 的唯一:
弊端: service 层: 出现了Connection连接对象。 Connection对象是负责连接数据库的, 只能出现dao层, 不应该出现在service层。

版本三: 对象: 本地线程局部变量对象: ThreadLocal 本质上一个是一个map 集合:

原理:

public class ThreadLocal{
//存:
Map<Runnable,Object> map = new HashMap<Runnerable,Object>();

public Object put(Object obj){
      map.set( obj);
      return null; 
}
//取 : 
  public Object get(Object obj){
     return  map.get()
}

//移除:
  public Object remore(){
     return map.remove();
  }

}
总结: ThreadLocal这个类: 存放和取值的时候, key 都是本地线程:

案例: 测试ThreadLocal类:

版本三: 使用ThreadLocal 管理事务:

代码如下:dao层:

package com.yidongxueyuan.dao3;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import com.yidongxueyuan.domain.Account;

public class DaoImpl implements Dao{

	private Connection conn;
	public DaoImpl (Connection conn){//注入:
		this.conn = conn; 
	}
	//依赖QueryRunner 
	private QueryRunner  qr = new QueryRunner (); //不需要给出数据源:  
	@Override
	public Account findByName(String name) {
		
		String sql ="select * from account where name=?";
		try {
			Account account = qr.query(conn, sql, new BeanHandler<Account>(Account.class),name);
			return account; 
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void updateAccount(Account account) {
		
		String sql="update account set money = ? where name=?";
		try {
			qr.update(conn, sql, account.getMoney(),account.getName());
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
	}
	
}

事务:

package com.yidongxueyuan.dao3;

import java.sql.Connection;

import javax.ejb.TransactionManagement;

import com.yidongxueyuan.dao2.Dao;
import com.yidongxueyuan.dao2.DaoImpl;
import com.yidongxueyuan.domain.Account;
import com.yidongxueyuan.utils.C3P0Util;
import com.yidongxueyuan.utils.TransactionManager;

/*
 * 业务层: 定义具体的业务方法: 
 */
public class TransFormer {
	
	//定义业务方法: 
	public  void transFormer(String SourceAccount,String targetAccount,float money) throws Exception{
		Connection conn = TransactionManager.getConnection();
		try {
			Dao dao = new DaoImpl(conn);
			TransactionManager.startTransaction();
			//查询操作: 
			//来源账户: 
			Account sourceAcc = dao.findByName(SourceAccount);
			sourceAcc.setMoney(sourceAcc.getMoney()-money);
			//更新获取: 
			dao.updateAccount(sourceAcc); 
			
			//模拟异常的发生: 
			int num = 1/0; 
			
			//目标账户修改:更新回去:  
			Account targetAcc = dao.findByName(targetAccount);
			targetAcc.setMoney(targetAcc.getMoney()+money); 
			dao.updateAccount(targetAcc);
		} catch (Exception e) {
			//异常发生: 
			TransactionManager.rollback();
		} finally{
			TransactionManager.commit();
			//关闭资源: 
			TransactionManager.release();
		}
		
	}
}

测试:

package com.yidongxueyuan.dao3;

import org.apache.commons.dbutils.QueryRunner;
import org.junit.Before;
import org.junit.Test;
import com.yidongxueyuan.utils.C3P0Util;

public class TestTran {
	private QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
	@Before
	public void before() throws Exception {
	//  把数据还原: 
		qr.update("update  account set money =1000 ");
	}
	
	@Test
	public void testname() throws Exception {
		TransFormer tf = new TransFormer();
		
		tf.transFormer("aaa", "bbb", 100);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方-教育技术博主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值