JDBC CRUD小工具 DBUtil

outline

对JDBC的CRUD操作的通用代码进行提取,封装为工具。
共4个源代码文件,其中1个为测试文件。
DBConfig.java 数据库配置接口
RowMapper.java 策略接口,读取数据时需要将ResultSet数据映射为Java Object对象。
DBUtil.java 对外提供两个工具方法:read(select)和write(insert, delete, update)。
TestDBUtil.java 测试CRUD。

keys

  • 开闭原则(Open Close Principle)
  • 单一职责原则(Single Responsibility Principle)
  • 策略模式(Strategy Pattern)
  • 泛型方法(Generic Method)

数据库配置 DBConfig.java

  • 变化的量不应该写死在工具类中,否则以后改配置还需要修改源代码。
  • 常规操作应该是写在配置文件中,用程序读取解析。
  • 此处不引入配置文件,直接将配置参数作为接口中的公有常量。
package cn.jt.util.db;

public interface DBConfig {
	String className = "com.mysql.jdbc.Driver";
	String url = "jdbc:mysql://localhost:3306/vms";
	String user = "root";
	String password = "root";
}

策略接口 RowMapper.java

package cn.jt.util.db;

import java.sql.ResultSet;

/**
 * 策略接口
 * @author wyj
 *
 * @param <T> 每行记录最终封装好的类型。
 */
public interface RowMapper<T> {
	
	/**
	 * 将一行记录封装,返回对应的一个对象。
	 * @param rs 换行后的结果集对象
	 * @return
	 */
	T mapRow(ResultSet rs);	
}

数据库读写工具 DBUtil

在这里插入图片描述

  • 数据库的四种操作CRUD(Create, Retrieve, Update, Delete),就是两种基本操作:读写。
  • 抽取公有操作,封装起来,变化的部分由参数入口传入。
  • write(sql, params),写操作,setObject()帮了大忙。
  • read(rm, sql, params),为了抽取所有读操作的共性,引入一个策略接口(strategy pattern)。
  • 策略接口帮助我们写更少的代码。动态地完成不同的需求。
package cn.jt.util.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据库操作工具,只对外显示读写通用操作。
 * @author wyj
 */
public class DBUtil implements DBConfig {
	
	/**
	 * 通用查询方法,需要传入一个实现了策略接口的匿名类的实例对象。
	 * @param rm
	 * @param sql
	 * @param params
	 * @return
	 */
	public static <T> List<T> read(RowMapper<T> rm, String sql, Object...params) {
		List<T> list = new ArrayList<T>();
		Connection con = DBUtil.getCon();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = con.prepareStatement(sql);
			if (params != null) {
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i + 1, params[i]);
				}
			}
// 			System.out.println("读SQL:" + pstmt);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				T t = rm.mapRow(rs);
				list.add(t);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			DBUtil.closeSrc(pstmt, rs, con);
		}
		return list;
	}
	
	/**
	 * 通用更新。利用setObject(xxx)方法的通用性。
	 * @param sql
	 * @param params
	 * @return
	 */
	public static int write(String sql, Object...params) {
		int rowAffect = 0;
		Connection con = DBUtil.getCon();
		PreparedStatement pstmt = null;
		try {
			con.setAutoCommit(false);	// 不自动提交。
			pstmt = con.prepareStatement(sql);
			// 客户端可能在params的位置传入null。
			if (params != null) {
				// 若params.length == 0,则不会进入此分支。
				for (int i = 0; i < params.length; i++) {
					pstmt.setObject(i + 1, params[i]);
				}
			}
//			System.out.println("写SQL:" + pstmt);
			rowAffect = pstmt.executeUpdate();	// 执行更新
			con.commit();	// 执行提交
		} catch (SQLException e) {
			e.printStackTrace();
			try {
				con.rollback();	// 出错则回滚。
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			DBUtil.closeSrc(pstmt, null, con);
		}
		return rowAffect;
	}
	
	/**
	 * 获取连接
	 * @return
	 */
	private static Connection getCon() {
		Connection con = null;
		try {
			Class.forName(className);
			con = DriverManager.getConnection(url, user, password);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return con;
	}
	
	/**
	 * 释放三种资源
	 * @param pstmt
	 * @param rs
	 * @param con
	 */
	private static void closeSrc(PreparedStatement pstmt, ResultSet rs, Connection con) {
		close(pstmt);
		close(rs);
		close(con);
	}
	
	/**
	 * 关闭单份资源
	 * @param cse
	 */
	private static void close(AutoCloseable cse) {
		if (cse != null) {
			try {
				cse.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}

测试CRUD TestDBUtil.java

用户自己新建数据库表users,自建JavaBean类User。后测试:

package cn.jt.test;

import cn.jt.pojo.User;
import cn.jt.util.db.DBUtil;
import cn.jt.util.db.RowMapper;
import org.junit.Test;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * 测试DBUtil
 *
 * @author wyj
 * @create 2019-04-22 18:31
 */
public class TestDBUtil {

    @Test
    public void testRead() {
        // 从数据库读回的数据需要用一个策略接口下的实例。
        RowMapper<User> mapper = new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs) throws SQLException {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setPhone(rs.getString("phone"));
                user.setEmail(rs.getString("email"));
                return user;
            }
        };
        // 无参数查询
//        String sql = "select id, phone, email from users";
//        Object[] params = {};
        // 带参数的查询
        String sql = "select id, phone, email from users where id = ?";
        Object[] params = {new Integer(3)};
        List<User> userList = DBUtil.read(mapper, sql, params);
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testInsert() {
        String sql = "insert into users (phone, email) values (?, ?)";
        Object[] params = {"123-456", "123@qq.com"};
        int rowAffect = DBUtil.write(sql, params);
        System.out.println(rowAffect);
    }

    @Test
    public void testUpdate() {
        String sql = "update users set email = ? where email = ?";
        Object[] params = {"666666@qq.com", "123@qq.com"};
        int rowAffect = DBUtil.write(sql, params);
        System.out.println(rowAffect);
    }

    @Test
    public void testDelete() {
        String sql = "delete from users where email = ?";
        Object[] params = {"666666@qq.com"};
        int rowAffect = DBUtil.write(sql, params);
        System.out.println(rowAffect);
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值