数据库连接工具类与查询结果格式化器

数据库连接工具类与查询结果格式化器

首先,我们先复习以下数据库编程的步骤:

  1. 加载数据库驱动:使用Class类的forName(String className)方法加载数据库对应的驱动类.(不同的数据库驱动写法不同,这里不再赘述)
  2. 通过Drivermanager获取数据库连接: 使用Drivermanager类的getConnection()方法获取数据库连接.
  3. 通过Connection对象创建Statement对象:
1.createStatement(): 创建Statement对象
2.prepareStatement(String sql) :根据传入的sql语句创建预编译的PreparedStatement对象
3.prepareCall(String sql): 根据传入的sql语句创建CallableStatement对象
  1. 使用Statement执行SQL语句,所有的statement都有如下三个方法:
1.execute(String sql):可以执行任何SQL语句,但比较麻烦
2.executeUpdate(String sql):可以执行DDL语句和DML语句
  1. 操作结果集:如果执行的SQL语句是查询语句,则结果将会返回一个ResultSet对象,该对象里保存了SQL语句查询的结果.我们可以通过操作ResultSet对象来获取查询结果:
1.移动指针的方法:next(),previous(),first() 等等
2,获取记录指针指向行、特定列的值:getXXX(int cioumn)或者getXXX(String columnName)
  1. 回收数据库资源,包括关闭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  |
+----------+----------+
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值