刚开始学JavaWeb时,我是调用N个setter方法将从数据库中查询出的数据封装成JavaBean的,极其繁琐。

后来了解SpringJDBC后,发现它提供的接口非常简单,然后就想自己封装一个简单的用。

原理很简单,就是使用反射代替手动调用 setter 方法,JavaBean中的属性名要和数据库查询语句中的字段名相同,一一对应。

数据库配置文件(config.properities)格式为:

db.url = xxx

db.dbname = xxx

db.user = xxx

db.password = xxx

代码:

package Utils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; /**
* 使用示例:
* (三个方法都有可能返回null,返回null则表示数据库操作异常)
* 1. 查询符号指定条件的记录数
* // 必须写成 as count
* int count = DBUtils.queryForCount("select count(1) as count from users where age = ?", age);
*
* 2. 查询出封装好的对象
* 查询出的字段要和欲封装成的对象的属性名一一对应,且需要包含setter方法,不需要加构造函数
* class User {
* private String name;
* private int age;
* public void setName(String name) { this.name = name; }
* public String getName() { return this.name; }
* public void setAge(int age) { this.age = age; }
* public int getAge() { return this.age; }
* }
* // 查询出一条记录并封装成对象,传入User.class,如果要查询出Product对象,则传入Product.class
* User user = DBUtils.queryForObject("select name, age from users where id = ?", User.class, id);
* // 查询出多条记录并封装成对象
* List<User> users = DBUtils.queryForList("select name, age from users where id < ?", User.class, id);
*
* 3. 增删改
* // 删除
* int changedCount = DBUtils.update("delete from users where id = ?", id);
* // 插入
* int changedCount = DBUtils.update("insert into users(name, age) values(?, ?)", name, age);
* // 修改
* int changedCount = DBUtils.update("update user set age = ? where id = ?", newAge, id);
*
* 4. 事务
* (多个update操作共同协同工作时使用事务)
* DBUtils.startTransaction(); // 开启事务
* if (DBUtils.update(xxx) == null) {
* DBUtils.rollback();
* return false; // 失败,返回
* }
* if (DBUtils.update(xxx) == null) {
* DBUtils.rollback();
* return false; // 失败,返回
* }
* DBUtils.commit(); // 成功,提交事务
* return true;
*/
public class DBUtils {
/**
* 线程作用域内,并发安全,可复用
*/
private final static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); /**
* 获取数据库链接对象
* @return 数据库连接对象
*/
private static Connection getConnection() {
if (threadLocal.get() == null) {
Properties properties = new Properties();
try {
properties.load(DBUtils.class.getResourceAsStream("config.properties"));
Connection conn = DriverManager.getConnection(
properties.getProperty("db.url") + "/" + properties.getProperty("db.dbname"),
properties.getProperty("db.user"),
properties.getProperty("db.password")
);
threadLocal.set(conn);
} catch (SQLException e) {
System.out.println("【连接数据库时出现异常:" + e.getMessage() + "】");
} catch (IOException e) {
System.out.println("【打开配置文件 config.properties 时出现异常:" + e.getMessage() + "】");
}
}
return threadLocal.get();
} /**
* 关闭数据库连接
*/
public static void closeConnection() {
if (threadLocal.get() != null) {
try {
threadLocal.get().close();
} catch (SQLException e) {
e.printStackTrace();
}
}
threadLocal.remove();
} /**
* 查询多条数据并封装成对应的实例
* @param sql 返回多条记录数的查询语句
* @param requireType 要封装成的类的Class对象
* @param params 要绑定到SQL语句上的参数
* @param <T> 要封装成的类的类型
* @return 返回封装好的对象列表
*/
public static <T> List<T> queryForList(String sql, Class<T> requireType, Object... params) {
List<T> ret = new ArrayList<>();
Connection conn = getConnection();
PreparedStatement ps = null;
if (conn == null)
return null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) { // 绑定参数
ps.setObject(i + 1, params[i]);
}
ResultSet result = ps.executeQuery();
while (result.next()) {
ret.add(requireType.getConstructor().newInstance()); // 创建一个实例
Field[] fields = requireType.getDeclaredFields(); // 获取所有属性
for (Field field : fields) {
// 构造 setter 方法名
String setterName = "set" + Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);
// 调用对应实例的 setter 方法给它设置属性
Method setter = requireType.getMethod(setterName, field.getType());
setter.invoke(ret.get(ret.size() - 1), result.getObject(field.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 仅需关闭 PreparedStatement,关闭它时 ResultSet 会自动关闭
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return ret;
} /**
* 查询出一条数据并封装成对象
* @param sql 返回一条记录数的查询语句
* @param requireType 要封装成的类的Class对象
* @param params 要绑定到SQL语句上的参数
* @param <T> 要封装成的类的类型
* @return 返回封装好的对象
*/
public static <T> T queryForObject(String sql, Class<T> requireType, Object... params) {
List<T> list = queryForList(sql, requireType, params);
return list == null ? null : list.get(0);
} /**
* 查询符合指定条件的记录数
* @param sql 查询记录数的SQL语句
* @param params 要绑定到SQL语句上的参数
* @return 返回符合条件的记录数
*/
public static Long queryForCount(String sql, Object... params) {
class Count {
private Long count;
public Count() {}
public void setCount(Long count) {
this.count = count;
}
public Long getCount() {
return this.count;
}
}
Count count = queryForObject(sql, Count.class, params);
return count.getCount();
} /**
* 执行增删除操作
* @param sql DML SQL语句
* @param params 要绑定到SQL语句上的参数
* @return 影响的数据库记录数目
*/
public static Integer update(String sql, Object... params) {
Connection conn = getConnection();
PreparedStatement ps = null;
Integer rowChanged = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) { // 绑定参数
ps.setObject(i + 1, params[i]);
}
rowChanged = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return null;
} finally {
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return rowChanged;
} /**
* 开启事务
*/
public static void startTransaction() {
try {
getConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 回滚事务
*/
public static void rollback() {
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
getConnection().setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 提交事务
*/
public static void commit() {
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
getConnection().setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

  

使用Java封装一个DBUtils类(反射)的更多相关文章

  1. 使用libzplay库封装一个音频类

    装载请说明原地址,谢谢~~      前两天我已经封装好一个duilib中使用的webkit内核的浏览器控件和一个基于vlc的用于播放视频的视频控件,这两个控件可以分别用在放酷狗播放器的乐库功能和MV ...

  2. 1.使用C++封装一个链表类LinkList

     使用C++封装一个链表类LinkList.写出相应一个测试用例 链表需要提供 添加 修改删除 除重 合并 排序创建 销毁等接口. 不能调用库函数或者使用STL等类库 题目延伸********** ...

  3. Swift - 简单封装一个工具类模板

    创建模板类(封装一个类) 例1:新建一个名字叫做 Product 的类 Product.swift File 的内容 class Product { var name: String var desc ...

  4. 用Java开发一个工具类,提供似于js中eval函数功能的eval方法

    今天在看到<Java疯狂讲义>中一个章节习题: 开发一个工具类,该工具类提供一个eval()方法,实现JavaScript中eval()函数的功能--可以动态运行一行或多行程序代码.例如: ...

  5. 封装一个帮助类来写文件到android外置存储器上

    项目地址:点击打开 项目简介:写文件到android外置存储器的一个帮助类,和它的demo程序 它是如何工作的呢? 1.创建 AppExternalFileWriter 对象并传递context(上下 ...

  6. java定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积

    需求如下:(1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积. (2)定义一个类PassObject,在类中定义一个方法pri ...

  7. java -封装一个类。(姓名、年龄、性别)

    //定义一个类. public class Maopao1{ //创建私有的对象. private String name; private int age; private String sex; ...

  8. Java自定义一个字典类(Dictionary)

    标准Java库只包含Dictionary的一个变种,名为:Hashtable.(散列表) Java的散列表具有与AssocArray相同的接口(因为两者都是从Dictionary继承来的).但有一个方 ...

  9. Java封装Get/Post类

    封装的类: package pers.hmi.translate; import java.io.BufferedReader; import java.io.IOException; import ...

随机推荐

  1. 运维必会之MySQL篇

    第一章 SQL语句 语言分类 1)DDL(data definition language)数据定义语言(create.alter.drop)管理基础数据例如:库.表    #<==运维要熟练, ...

  2. 「2018-11-05模拟赛」T5 传送机 解题报告

    5.传送机(sent.*) 问题描述: 黄黄同学要到清华大学上学去了.黄黄同学很喜欢清华大学的校园,每次去上课时总喜欢把校园里面的每条路都走一遍,当然,黄黄同学想每条路也只走一遍. 我们一般人很可能对 ...

  3. 「BZOJ1722」「Usaco2006 Mar」Milk Team Select产奶比赛 解题报告

    Milk Team Select 产奶比赛 Description Farmer John's N (\(1 \le N \le 500\)) cows are trying to select th ...

  4. 31.用python中的serial向串口发送和接收数据(案例一)

    代码功能说明:1.向串口助手发送十六进制数据:0X01,0X03,0X00,0X00,0X00,0X01,0X84,0X0A: 2.用串口助手向代码发送数据,并将发送过来的数据保存在数据库中,按数据和 ...

  5. Java控制台五子棋(纯算法)

    Java五子棋小游戏 本方案是基于控制台写的一个代码 没有花里胡哨的界面,只为研究算法 仅仅用了200行代码 下面是的是运行结果 游戏运行结果 这里我就很简单的复制了一个结果 第9回合,下子方:玩家2 ...

  6. 机器学习-特征工程-Missing value和Category encoding

    好了,大家现在进入到机器学习中的一块核心部分了,那就是特征工程,洋文叫做Feature Engineering.实际在机器学习的应用中,真正用于算法的结构分析和部署的工作只占很少的一部分,相反,用于特 ...

  7. 【Linux】---Linux系统下各种常用命令总结

    在Linux系统下,“万物皆文件”,之所以强调在强调这个概念,是因为很多人已经习惯了win系统下找找点点得那种方式和思维,因此总是会觉得linux系统下很多指令既复杂又难记.其实都是一样得东西,只是w ...

  8. 2018 CCPC 网络赛

    The Power Cube is used as a stash of Exotic Power. There are n cities numbered 1,2,…,n where allowed ...

  9. 大厂面试中三次握手延伸出来n连发你受得了?

    目录 一.这是一次有故事的对话 二.三次握手的客户端服务端状态 1 先画个图看看有哪些状态 2 tcp协议内容解析 3 通过工具wireshark来验证我们所述 三.说下Linux网络编程常用API ...

  10. Oracle 11g 安装过程及测试方法

    大家可以根据自己的操作系统是多少位(32位或64位)的,到官网下载相应的安装程序,如下图所示. 有一点需要注意,Oracle的安装程序分成2个文件,下载后将2个文件解压到同一目录即可.     下载完 ...