这次的内容在功能上和上一篇博客是一样的,都是一个通用的Java操作数据库实现增删改查的工具类。但是不同的是这次使用了BeanUtils包作为辅助,不仅增加了代码的安全性也简化了一些代码,并且在原代码的基础上我将一些工具类内部重复的代码做了封装,增加了代码的复用性,也大大的简化了代码。
先说一下为什么原来的代码会存在一些安全问题:原来的代码在通过泛型创建对象并且赋值的时候,是通过反射来实现的,但是反射是破坏类里面的一些基本规则的,比如private,protect修饰符的限制,对属性进行了直接的赋值,这样做是不推荐的。所以这次引用了BeanUtils这个工具类,可以不通过反射来实现依据泛型创建对象并赋值,大大的增加了代码的安全性。
这次的DBtools会用到另外的两个包,一个是commons-beantuils包,另一个是它依赖的包commons-logging。所以一共需要导入这三个包工具类才可以正常的使用
话不多说,上代码
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
public class DBTools {
/**
* 这个方法是将重复替换sql语句里的?占位符为真正的值,抽生成的方法
* 这个方法是供我内部使用的,所以做成私有的就可以。也不需要外部去使用
* @return
* @throws SQLException
*/
private static PreparedStatement insteadHolder(PreparedStatement prestat, Object...args) throws SQLException {
for (int i = 0; i < args.length; i++) {
prestat.setObject(i+1, args[i]);
}
return prestat;
}
/***
* 传入类的类型获得对象的方法
* @param rs
* @param clazz
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws SQLException
* @throws InvocationTargetException
*/
@SuppressWarnings({ "unchecked" })
private static <T> T getEntity(ResultSet rs, Class<?> clazz) throws InstantiationException, IllegalAccessException, SQLException, InvocationTargetException {
T entity = (T) clazz.newInstance();//通过反射拿到这种类型的对象
//首先,不知道entity里有哪些属性,知道属性
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
//把结果集中的值取出来
for (int i = 1; i <= columnCount; i++) {
String key = rsmd.getColumnLabel(i);
Object val = rs.getObject(key);
//使用beanutils包里面的方法,非常方便。也不用通过反射来走“后门”了
BeanUtils.setProperty(entity, key, val);
}
return entity;
}
/*
* 通用的获取数据库连接的方法
*/
public static Connection getConnection() {
Connection conn = null;
try {
String driverClassName = "com.mysql.jdbc.Driver";// mysql数据库驱动
String url = "jdbc:mysql://localhost:3306/“数据库的名字”?useUnicode=true&characterEncoding=utf-8";// mysql数据库url
String username = "数据库用户名";// mysql数据库用户名
String password = "数据库的密码";// mysql数据库密码
Class.forName(driverClassName);// 注册mysql数据库驱动
conn = DriverManager.getConnection(url, username, password);// 通过url,username,password获得数据库连接
} catch (Exception e) {
System.out.println("获取数据库连接失败");
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接的通用方法,先关闭结果集,再关闭statement,再关闭connection
* @param conn
* @param stat
* @param rs
*/
public static void close(Connection conn, Statement stat, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 这个方法用来实现通用的增改删,传入对应的sql语句
* @param sql
*/
public static Boolean cud(String sql, Object... args) {
Connection conn = null;
PreparedStatement prestat = null;
int count = 0;
try {
conn = DBTools.getConnection();
prestat = conn.prepareStatement(sql);
//直接调用将参数填充到?占位符中的方法
insteadHolder(prestat, args);
count = prestat.executeUpdate();
if (count == 1) {
return true;
} else {
return false;
}
} catch (Exception e) {
System.out.println("执行增改删sql语句出现错误!");
e.printStackTrace();
return false;
} finally {
DBTools.close(conn, prestat, null);
}
}
/**
* 通用的查询某个表的一条数据的方法
* @param clazz
* @param sql
* @param args
* @return
*/
public static <T> T getData(Class<T> clazz, String sql, Object... args) {
Connection conn = null;
PreparedStatement prestat = null;
ResultSet rs = null;
T entity = null;
try {
// 1.连接数据库
conn = DBTools.getConnection();
// 2.根据sql创建PrepareStatement对象
prestat = conn.prepareStatement(sql);
// 3.替换掉stat对象里的sql语句里的“?”占位符
insteadHolder(prestat, args);
// 4.从rs中拿出数据库取出的具体数据值
// 执行查询sql语句,获得结果集
rs = prestat.executeQuery();
if (rs.next()) {
//通过clazz创建对象,并且根据rs结果集中的值进行对象赋值
entity = getEntity(rs, clazz);
}
} catch (Exception exception) {
System.out.println("执行查询一条记录sql语句出现错误!");
exception.printStackTrace();
} finally {
DBTools.close(conn, prestat, rs);
}
return entity;
}
/**
* 通用的查询多条记录的方法,返回一个记录对象的集合
* @param clazz
* @param sql
* @param args
* @return
*/
public static <T> List<T> getListData(Class<T> clazz, String sql, Object... args) {
Connection conn = null;
PreparedStatement prestat = null;
ResultSet rs = null;
T entity = null;
List<T> list = new ArrayList<T>();
try {
conn = DBTools.getConnection();
prestat = conn.prepareStatement(sql);
insteadHolder(prestat, args);
rs = prestat.executeQuery();
while (rs.next()) {
entity = getEntity(rs, clazz);
list.add(entity);
}
} catch (Exception exception) {
System.out.println("执行查询多条记录sql语句出现错误!");
exception.printStackTrace();
} finally {
DBTools.close(conn, prestat, rs);
}
return list;
}
/**
* 获取满足查询条件的某个字段的值或者某个统计字段(count(*))
* @param sql
* @param args
* @return
*/
public static Object getOneColumn(String sql, Object... args) {
Connection conn = null;
PreparedStatement prestat = null;
ResultSet rs = null;
try {
conn = DBTools.getConnection();
prestat = conn.prepareStatement(sql);
insteadHolder(prestat, args);
rs = prestat.executeQuery();
if (rs.next()) {
return rs.getObject(1);
}
} catch (Exception exception) {
System.out.println("执行查询条件的某个字段的值或者某个统计字段出现错误!");
exception.printStackTrace();
} finally {
DBTools.close(conn, prestat, rs);
}
return null;
}
}