数据库连接工具类与查询结果格式化器
首先,我们先复习以下数据库编程的步骤:
- 加载数据库驱动:使用Class类的forName(String className)方法加载数据库对应的驱动类.(不同的数据库驱动写法不同,这里不再赘述)
- 通过Drivermanager获取数据库连接: 使用Drivermanager类的getConnection()方法获取数据库连接.
- 通过Connection对象创建Statement对象:
1.createStatement(): 创建Statement对象
2.prepareStatement(String sql) :根据传入的sql语句创建预编译的PreparedStatement对象
3.prepareCall(String sql): 根据传入的sql语句创建CallableStatement对象
- 使用Statement执行SQL语句,所有的statement都有如下三个方法:
1.execute(String sql):可以执行任何SQL语句,但比较麻烦
2.executeUpdate(String sql):可以执行DDL语句和DML语句
- 操作结果集:如果执行的SQL语句是查询语句,则结果将会返回一个ResultSet对象,该对象里保存了SQL语句查询的结果.我们可以通过操作ResultSet对象来获取查询结果:
1.移动指针的方法:next(),previous(),first() 等等
2,获取记录指针指向行、特定列的值:getXXX(int cioumn)或者getXXX(String columnName)
- 回收数据库资源,包括关闭ResultSet,Statement,Connection等资源.
下面进入正题,我们每次进行数据库连接的时候都需要这些步骤,这就比较繁琐,因此我写了一个连接数据库的工具类来简化操作.代码如下:
public class DriverTool {
/**
* 属性文件的地址
*/
private String paramFile="D:\\Java\\Java\\src\\chacpter_XI\\homeWork\\driverTool\\mysql.ini";
/**
* 属性文件对象
*/
private Properties properties;
/**
* 用于缓存单例对象
*/
private static DriverTool driverTool;
/**
* 由于是工具类,封装其构造器
*/
private DriverTool() {
}
/**
* 设置属性文件的地址
* @param paramFile 要设置的属性文件的地址
*/
public void setParamFile(String paramFile) {
//如果属性文件的地址不为null并且不为空,则将此地址设置为新的地址
if (paramFile!=null&&!paramFile.isEmpty()) {
this.paramFile=paramFile;
}
}
public String getParamFile() {
return paramFile;
}
/**
* 获取单例
* @return 返回单例对象
*/
public static DriverTool getInstance() {
if (driverTool!=null) {
return driverTool;
}else {
return new DriverTool();
}
}
/**
* 加载属性文件的方法
* 如果属性对象加载失败,会产生一个空的属性对象
*/
private void loadProperties() {
//创建一个属性对象
properties = new Properties();
//加载缓存的配置文件
try {
properties.load(new FileInputStream(paramFile));
} catch (FileNotFoundException e) {
// TODO: handle exception
System.out.println("没有找到配置文件,请检查配置文件是否存在");
//测试用(打印异常的跟踪栈信息便于查找错误)
e.printStackTrace();
}catch (IOException e) {
// TODO: handle exception
System.out.println("配置文件读取失败,请检查配置文件内容...");
//测试用(便于检查错误)
e.printStackTrace();
}
}
/**
* 加载驱动的方法
* @return 返回驱动是否加载成功
*/
public boolean loadDriver() {
try {
Class.forName(getDriver());
//驱动加载成功
return true;
} catch (ClassNotFoundException e) {
// TODO: handle exception
System.out.println("没有找到驱动,请检查项目的classPath中是否有此驱动...");
}
//驱动加载失败
return false;
}
/**
* 获取属性文件对象的方法
* @return 返回加载好的属性对象
*/
public Properties getProperties() {
//加载属性文件
loadProperties();
return properties;
}
/**
* 获取数据库连接地址的方法
* @return 返回数据库的连接地址
*/
public String getURL() {
return getProperties().getProperty("url");
}
/**
* 获取数据库驱动名的方法
* @return 返回数据库的驱动名称
*/
public String getDriver() {
return getProperties().getProperty("driver");
}
/**
* 获取数据库账号的方法
* @return 返回此数据库连接的账号
*/
public String getUser() {
return getProperties().getProperty("user");
}
/**
* 获取数据库密码的方法
* @return 返回该数据库账号的密码
*/
public String getPassword() {
return getProperties().getProperty("password");
}
/**
* 获取数据库连接对象的方法
* @return 返回数据库连接对象
*/
public Connection getConnection() {
//先加载驱动,如果驱动加载成功,获取数据库连接对象
Connection con=null;
if (loadDriver()) {
try{
con= DriverManager.getConnection(getURL(),getProperties());
} catch (SQLException e) {
// TODO: handle exception
System.out.println("数据库连接失败,请检查属性文件内容...");
e.printStackTrace();
}
}
return con;
}
/**
* 获取Statement对象
* @return 返回Statement对象
*/
public Statement getStatement() {
//先获取数据库连接对象
Connection con=getConnection();
//定义Statement对象
Statement statement=null;
if (con!=null) {
try {
statement= con.createStatement();
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
return statement;
}
/**
* 通过SQL语句获取PreparedStatement对象的方法
* @param sql 要执行的SQL语句
* @return 返回SQL语句对应的PreparedStatement对象
*/
public PreparedStatement getPreparedStatement(String sql) {
//先定义一个PreparedStatement对象
PreparedStatement ps=null;
//获取连接对象
Connection con=getConnection();
if (con!=null) {
try {
ps=con.prepareStatement(sql);
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
return ps;
}
/**
* 直接获取执行存储过程的CallableStatement对象的方法
* @param sql 调用存储过程的SQL语句
* @return 返回CallableStatement对象
*/
public CallableStatement getCallableStatement(String sql) {
//先定义一个CallableStatement对象
CallableStatement cs=null;
//获取数据库连接对象
Connection connection=getConnection();
try {
//通过connection对象创建CallableStatement对象
cs=connection.prepareCall(sql);
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
return cs;
}
}
现在测试一下:
public class ToolTest {
/**
* 程序入口
* @param args 运行参数(null)
*/
public static void main(String[] args) {
ToolTest tt = new ToolTest();
//建表
tt.execute("create table if not exists te ( id int, name varchar(225))");
// 清空之前的数据
tt.execute("truncate te");
//插入数据
tt.execute("insert into te values(1,'小明'),(2,'小花'),(3,'小杨')");
//查询数据
tt.query("select * from te");
}
/**
* 执行SQL查询语句的方法
*/
public void query(String sql) {
//先通过工具类获取statement对象
try (
Statement statement=DriverTool.getInstance().getStatement();
){
//执行查询语句
ResultSet rs=statement.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getInt(1)+"\t"+rs.getString(2));
}
} catch (Exception e) {
// TODO: handle exception
System.out.println("执行查询语句失败");
e.printStackTrace();
}
}
/**
* 执行DDL语句和DML语句
* @param sql SQL语句
*/
public void execute(String sql) {
try (
Statement statement=DriverTool.getInstance().getStatement();
){
int result=statement.executeUpdate(sql);
System.out.println("受影响的记录的条数:"+result);
} catch (Exception e) {
// TODO: handle exception
System.out.println("执行SQL语句失败");
e.printStackTrace();
}
}
}
运行结果如下:
受影响的记录的条数:0
受影响的记录的条数:0
受影响的记录的条数:3
1 小明
2 小花
3 小杨
运行成功.
在上面的结果中可以看出查询显示的结果并不美观,如果想要显示为表格的形式,还需需要其他复杂的逻辑,因此我又写了一个将查询结果格式化成表格的格式化器,代码如下:
public class TableFormatter {
/**
* 定义每列的宽度
*/
private int width;
/**
* 定义列数
*/
private int columns;
/**
* 要格式化的结果集对象
*/
private ResultSet resultSet;
/**
* 操作结果集的接口
*/
private ResultSetMetaData reMetaData;
/**
* 无参构造器
*/
public TableFormatter() {
}
/**
* 创建格式化对象 每列的宽度默认是10
* @param resultset 要格式化的结果集对象
*/
public TableFormatter(ResultSet resultSet) {
this.resultSet = resultSet;
this.width = 10;
setcolumns();
}
/**
* 设置每列的宽度
* @param width 要设置的宽度
*/
public void setWidth(int width) {
this.width = width;
}
/**
* 设置列的数量的方法
*/
private void setcolumns() {
// 先通过结果集获取操作结果集的对象
try {
reMetaData= resultSet.getMetaData();
columns = reMetaData.getColumnCount();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 打印第一行或最后一行符号的方法
*/
private void printMark() {
for (int i = 0; i < columns; i++) {
// 先打印一个加号
System.out.print("+");
// 然后循环打印"-"
for (int j = 0; j < width; j++) {
System.out.print("-");
}
}
System.out.println("+");
}
/**
* 打印列名或者查询的值的方法
* @param 要打印的内容
*/
private void printcontent(String content) {
//先打印一个"|"
System.out.print("|");
//如果打印内容不为null
if (content!=null) {
int length=content.length();
//如果列名的长度大于列宽,则截取列宽长度的列名打印
if (length>width) {
content=content.substring(0, width);
System.out.print(content);
}else {
//如果列名的长度小于或等于列宽
//先求列名和列宽之间的差的一半
//如果过列宽和列名之间的长度为奇数,则左边的空格比右边少一个
int sub=(width-length)/2-1;
//打印左边空格
for (int j = 0; j <=sub; j++) {
System.out.print(" ");
}
//打印列名
System.out.print(content);
//打印右边空格
for (int k = 0; k <width-sub-length-1; k++) {
System.out.print(" ");
}
}
}
}
/**
* 打印列名的方法
*/
private void printColumnName() {
for (int i = 1; i <= columns; i++) {
//获取每列的列名
String columnName=null;
//如果操作结果集的对象不为null
if (reMetaData!=null) {
try {
columnName=reMetaData.getColumnName(i);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
printcontent(columnName);
}else {
System.out.println("操作结果集的对象为null");
}
}
System.out.println("|");
}
/**
* 打印内容的方法
*/
private void printconnection() {
//如果结果集不为空
if (resultSet!=null) {
try {
while (resultSet.next()) {
for (int i = 1; i <= columns; i++) {
String content=resultSet.getString(i);
printcontent(content);
}
System.out.println("|");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
System.out.println("结果集为null");
}
}
/**
* 打印格式化后的内容的方法
*/
public void showResult() {
//先打印一行符号
printMark();
//打印列名
printColumnName();
//大印一行符号
printMark();
//打印内容
printconnection();
//打印最后一行符号
printMark();
}
}
测试代码只需将上面的代码的执行SQL查询语句的代码改为如下代码即可:
public void query(String sql) {
//先通过工具类获取statement对象
try (
Statement statement=DriverTool.getInstance().getStatement();
){
//执行查询语句
ResultSet rs=statement.executeQuery(sql);
TableFormatter tf = new TableFormatter(rs);
tf.showResult();
// while (rs.next()) {
// System.out.println(rs.getInt(1)+"\t"+rs.getString(2));
// }
} catch (Exception e) {
// TODO: handle exception
System.out.println("执行查询语句失败");
e.printStackTrace();
}
}
运行结果如下:
受影响的记录的条数:0
受影响的记录的条数:0
受影响的记录的条数:3
+----------+----------+
| id | name |
+----------+----------+
| 1 | ab |
| 2 | ac |
| 3 | asdfas |
+----------+----------+