对于数据库的增删改查等操作已经有框架实现了
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。DBUtils封装了对JDBC的操作,简化了JDBC操作。可以少写代码。
- 对于数据表的读操作,他可以把结果转换成List,Array,Set等java集合,便于程序员操作
- 对于数据表的写操作,也变得很简单(只需写sql语句)
- 可以使用数据源,使用JNDI,数据库连接池等技术来优化性能–重用已经构建好的数据库连接对象
DBUtils的三个核心对象
- QueryRunner类
- ResultSetHandler接口
- DBUtils类
一、QueryRunner类:QueryRunner中提供对sql语句操作的API.
它主要有三个方法
- query() 用于执行select
- update() 用于执行insert update delete
- batch() 批处理
二、ResultSetHandler接口:用于定义select操作后,怎样封装结果集.
三、DbUtils类:它就是一个工具类,定义了关闭资源与事务处理的方法
Dbutils快速入门
导入jar包
创建QueryRunner对象
使用query方法执行select语句
使用ResultSetHandler封装结果集
使用DbUtils类释放资源
一、导入jar包
commons-dbutils-1.4.jar,还有mysql的连接驱动,C3P0的jar包
二、创建QueryRunner对象
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
三、使用相关方法
QueryRunner对象
QueryRunnerAPI
一、构造函数:
- new QueryRunner(); 它的事务可以手动控制。
也就是说此对象调用的方法(如:query、update、batrch)参数中要有Connection对象。 - new QueryRunner(DataSource ds); 它的事务是自动控制的。一个sql一个事务。
此对象调用的方法(如:query、update、batrch)参数中无需Connection对象。
二、方法:
首先附上C3P0util.java
package com.yanglin.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Created by zeroyoung on 2016/10/29.
*/
public class C3POUtils {
public static DataSource dataSource = new ComboPooledDataSource();
public static DataSource getDataSource(){
return dataSource;
}
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("创建连接失败!");
}
}
public static void close(ResultSet rs, Statement st, Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用dbutls包测试CRUD操作:
@Test
public void testInsert(){
DataSource dataSource = C3POUtils.getDataSource();
QueryRunner qr = new QueryRunner(dataSource);
try {
int i = qr.update("insert into users(NAME,PASSWORD,email,birthday)values(?,?,?,?)", "tom", "123", "q@qq.com", new Date());
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void testupdate(){
DataSource dataSource = C3POUtils.getDataSource();
QueryRunner qr = new QueryRunner(dataSource);
try {
int i = qr.update("update users set NAME=? where id=?", "sss", 4);
System.out.println(i);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void testDelete() throws SQLException{
//创建一个QueryRunner对象
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
qr.update("delete from users where id=?", 4);
}
@Test//批处理,插入多条数据
public void testBatch() throws SQLException{
//创建一个QueryRunner对象
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
Object[][] params = new Object[10][];//高维代表执行多少次sql语句
for (int i = 0; i < params.length; i++) {
params[i] = new Object[]{"丢丢"+i,"123","c10@163.com",new Date()};//给每次执行的sql语句中的?赋值
}
qr.batch("insert into users(NAME,PASSWORD,email,birthday) values(?,?,?,?)", params );
}
ResultSetHandler接口
ResultSetHandler下的所有结果处理器
- ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
- ArrayListHandler:适合取多条记录。把每条记录的每列值封装到一个数组中Object[],把数组封装到一个List中
- ColumnListHandler:取某一列的数据。封装到List中。
- KeyedHandler:取多条记录,每一条记录封装到一个Map中,再把这个Map封装到另外一个Map中,key为指定的字段值。
- MapHandler:适合取1条记录。把当前记录的列名和列值放到一个Map中
- MapListHandler:适合取多条记录。把每条记录封装到一个Map中,再把Map封装到List中
- ScalarHandler:适合取单行单列数据
- BeanHandler:取出一条记录,封装到一个bean中
- BeanListHandler :取出多条记录,分别分装到bean当中
测试代码:
@Test//ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
public void teseArrayHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
Object[] arr = qr.query("select * from users", new ArrayHandler());
for (Object o : arr) {
System.out.println(o);
}
}
@Test//ArrayListHandler:适合取多条记录。把每条记录的每列值封装到一个数组中Object[],把数组封装到一个List中
public void testArrayListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
List<Object[]> list = qr.query("select * from users", new ArrayListHandler());
for (Object[] o : list) {
for (Object os:o) {
System.out.println(os);
}
System.out.println();
}
}
@Test//ColumnListHandler:取某一列的数据。封装到List中。
public void testColumnListHandlerr() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
List<Object> list = qr.query("select * from users", new ColumnListHandler(2));
for (Object o : list) {
System.out.println(o);
}
}
@Test//KeyedHandler:取多条记录,每一条记录封装到一个Map中,再把这个Map封装到另外一个Map中,key为指定的字段值。
public void testKeyedHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
Map<Object, Map<String, Object>> map = qr.query("select * from users", new KeyedHandler());
for (Map.Entry<Object,Map<String, Object>> m: map.entrySet()) {
System.out.println(m.getKey());
for (Map.Entry<String,Object> mm: m.getValue().entrySet()) {
System.out.println(mm.getKey()+"------"+mm.getValue());
}
System.out.println("------------------");
}
}
@Test//MapHandler:适合取1条记录。把当前记录的列名和列值放到一个Map中
public void testMapHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
Map<String, Object> map = qr.query("select * from users", new MapHandler());
for (Map.Entry<String,Object> m: map.entrySet()) {
System.out.println(m.getKey()+"--------------------"+m.getValue());
}
}
@Test//MapListHandler:适合取多条记录。把每条记录封装到一个Map中,再把Map封装到List中
public void testMapListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
List<Map<String,Object>> list = qr.query("select * from users", new MapListHandler());
for (Map<String, Object> map : list) {
for (Map.Entry<String, Object> m : map.entrySet()) {
System.out.println(m.getKey()+"\t"+m.getValue());
}
System.out.println("---------------");
}
}
@Test //ScalarHandler:适合取单行单列数据
public void testScalarHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
Object o = qr.query("select count(*) from users", new ScalarHandler(1));
System.out.println(o);//long类型的
}
@Test //BeanHandler:适合取单行数据封装到User对象当中,取不到,不会报错,会返回空
public void testBeanHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
User user = qr.query("select * from users where id=?", new BeanHandler<User>(User.class),1);
System.out.println(user);
}
@Test //BeanListHandler:取出一个多条记录封装到每一个User当中,返回list
public void testBeanListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(C3POUtils.getDataSource());
//List<User> list = qr.query("select * from users where id=?", new BeanListHandler<User>(User.class),1);
List<User> list = qr.query("select * from users ", new BeanListHandler<User>(User.class));
System.out.println(list.size());
}
DBUtils控制事务
当我们需要控制事务的时候,我们就得调用相关带有Connection的query(),update()等方法了。但是调用事务我们需要一个Connection对象,这个对象的。然而我们在dao的实现曾是这样的
DataSource dataSource = C3POUtils.getDataSource();
QueryRunner qr = new QueryRunner(dataSource);
虽然我们的C3P0utils当中有getConnection()方法可以得到一个Connection对象,但是我们事务的开启都是在service当中的。dao层的值提供数据库的增删改查等操作,不涉及业务逻辑层。
而且我们也不能在service当中调用C3POUitls,因为服务不涉及数据库相关的操作。而且也会有线程安全问题。
这个时候,我们就得需要使用ThreadLocal这个类的
ThreadLocal类简单来说就是一个线程局部变量,他可以在线程当中存放局部变量,调用该类的get方法,永远返回当前线程放入的数据。线程局部变量。
package com.yanglin.utils;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Created by zeroyoung on 2016/10/30.
*/
public class ManagerThreadLocal {
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
public static Connection getConnection(){
Connection conn = tl.get();
if(conn==null){
conn = C3POUtils.getConnection();
tl.set(conn);
}
return conn;
}
/**
* 开始事务
*/
public static void BeginTransaction(){
try {
getConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 提交事务
* */
public static void commit(){
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 回滚
* */
public static void rollback(){
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* 释放资源
* */
public static void close(){
try {
getConnection().close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
测试使用:
public class AccountDaoImpl implements AccountDao {
public void updateAccount(String fromname, String toname, double money) throws Exception {
//创建一个QueryRunner对象
QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
qr.update("update account set money=money-? where name=?",money,fromname);
qr.update("update account set money=money+? where name=?",money,toname);
}
public void updateAccout(Account account) throws Exception {
QueryRunner qr = new QueryRunner();
qr.update(ManagerThreadLocal.getConnection(),"update account set money=? where name=?",account.getMoney(),account.getName());
}
public Account findAccountByName(String name) throws Exception {
QueryRunner qr = new QueryRunner();
return qr.query(ManagerThreadLocal.getConnection(),"select * from account where name=?", new BeanHandler<Account>(Account.class),name);
}
}