【Java】利用单例模式、可变参数优化Java操作Mysql数据库、JDBC代码的写作

来源:互联网 发布:d3 js 流程图 编辑:程序博客网 时间:2024/06/06 05:44

本文没有任何新的内容,只是设置一个Java操作Mysql数据库,让代码写得更好而已。

如同《【Java】Java中对Mysql数据库的增删改查、Java的System类》(点击打开链接)一样,工程极其简单,引入操作Mysql数据库相应的jar之后就一个DB类,


下文将对test数据库中的一张usertable表进行操作,usertable表的结构如下:


这张表用来做例子都用烂了,就ID、用户名、密码3个字段,里面的结构如下:


之后,我们建立如下的Db.java:

import java.sql.*;import java.util.*;public class Db {// 一、单例初始化连接private Connection con;// 以下代码,保证该类只能有一个实例private Db() {try {Class.forName("com.mysql.jdbc.Driver");// 其中test是我们要链接的数据库,user是数据库用户名,password是数据库密码。// 3306是mysql的端口号,一般是这个// 后面那串长长的参数是为了防止乱码,免去每次都需要在任何语句都加入一条SET NAMES UTF8String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useOldAliasMetadataBehavior=true";String user = "pc";String password = "admin";con = DriverManager.getConnection(url, user, password);} catch (Exception e) {e.printStackTrace();}} // 私有无参构造方法// 在自己内部定义自己的一个实例,只供内部调用private static Db db = null;// 这个类必须自动向整个系统提供这个实例对象// 这里提供了一个供外部访问本class的静态方法,可以直接访问public static Db getInstance() {if (db == null) {db = new Db();}return db;}// 二、查询// 使用SQL查询,查询的结果是一个结果集(视图)public List<Object[]> getBySql(String sql) {List<Object[]> result_list = new ArrayList<Object[]>();try {PreparedStatement ps = con.prepareStatement(sql);ResultSet rs = ps.executeQuery();while (rs.next()) {ResultSetMetaData md = rs.getMetaData();int columnCount = md.getColumnCount();Object[] row_data_set = new Object[columnCount];for (int i = 1; i <= columnCount; i++) {row_data_set[i - 1] = rs.getObject(i);}result_list.add(row_data_set);}return result_list;} catch (SQLException e) {e.printStackTrace();return null;}}// 查询sql语句带参数的情况public List<Object[]> getBySql(String sql, Object[] param) {List<Object[]> result_list = new ArrayList<Object[]>();try {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < param.length; i++) {ps.setObject(i + 1, param[i]);}ResultSet rs = ps.executeQuery();while (rs.next()) {ResultSetMetaData md = rs.getMetaData();int columnCount = md.getColumnCount();Object[] row_data_set = new Object[columnCount];for (int i = 1; i <= columnCount; i++) {row_data_set[i - 1] = rs.getObject(i);}result_list.add(row_data_set);}return result_list;} catch (SQLException e) {e.printStackTrace();return null;}}// 使用SQL查询,查询的结果是唯一private Object getBySql_result_unique(String sql) {try {PreparedStatement ps = con.prepareStatement(sql);ResultSet rs = ps.executeQuery();rs.next();return rs.getLong(1);} catch (SQLException e) {e.printStackTrace();return null;}}// 查询sql语句带参数的情况public Object getBySql_result_unique(String sql, Object[] param) {try {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < param.length; i++) {ps.setObject(i + 1, param[i]);}ResultSet rs = ps.executeQuery();rs.next();return rs.getLong(1);} catch (SQLException e) {e.printStackTrace();return null;}}// 三、增删改// insert、update、delete等修改数据库的语句public void setBySql(String sql) {try {PreparedStatement ps = con.prepareStatement(sql);ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}}// sql语句带参数的情况public void setBySql(String sql, Object[] param) {try {PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < param.length; i++) {ps.setObject(i + 1, param[i]);}ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}}// 析构函数,中断数据库的连接protected void finalize() throws Exception {if (!con.isClosed() || con != null) {con.close();}}public static void main(String[] args) {Db db = Db.getInstance();System.out.println("id大于1的结果集:");List<Object[]> result_list = db.getBySql("select * from usertable where id>?", new Object[] { 1 });for (int i = 0; i < result_list.size(); i++) {Object[] row = result_list.get(i);for (int j = 0; j < row.length; j++) {System.out.print(row[j] + ",");}System.out.println();}System.out.println();long result = (long) db.getBySql_result_unique("select count(*) from usertable");System.out.println("usertable表所含有的项数:"+result);// 插入示例:db.setBySql("insert into usertable(username,password) values(?,?)",new Object[]{"username","password"});}}

此程序首先利用《【Java】单例模式》(点击打开链接)让数据库连接的单例化,不至于调用一次数据库连接类就多一次数据库连接,增加不必要的压力。

之后,利用《【Java】JDK1.5以后新型的泛型参数传递方法Object...args》(点击打开链接)中可变参数为数据库的增删改查新建开辟可变参数查询。

注意的主函数中的对增删改查的实施,无论这个查询是带参数,还不是不带参数同样能够应付。

利用到JDBC自带的PreparedStatement旗下的setObject组织语句,这样一来可以应付各种传过来的SQL语句,带有不同参数的情况,二来最关键的事情,可以应付绝大多数情况的SQL注入的情况,不用自己再写相应的SQL注入过滤方法。

PreparedStatement ps = con.prepareStatement(sql);for (int i = 0; i < param.length; i++) {ps.setObject(i + 1, param[i]);}ResultSet rs = ps.executeQuery();
其后,由于查询出来的结果集是一样几乘于几的表,我们同样是未知的。

因此,在组织数据的时候,先利用ResultSetMetaData md = rs.getMetaData();int columnCount = md.getColumnCount();获取查询得到的列数,对于每一行的处理,先新建相应列长的Object数组,再利用for循环对于每一行,管它是字符串还是数字,将每一列的结果放入这个Object数组,注意到ResultSet的getObject方法索引是从1开始的,而Java中的任何数组索引都是从0开始的,因此i请自行控制好。之后再把这个Object数组输入,压入一个存Object的List中。

最后这个方法返回这个List给调用者,就OK。

while (rs.next()) {ResultSetMetaData md = rs.getMetaData();int columnCount = md.getColumnCount();Object[] row_data_set = new Object[columnCount];for (int i = 1; i <= columnCount; i++) {row_data_set[i - 1] = rs.getObject(i);}result_list.add(row_data_set);}

对于查询仅一个数字,没有返回结果的处理非常简单,这里就不再赘述。

因此上述的整个程序的运行结果如下:


本类还可以配合《【Servlet】根据MVC思想设计用户登陆、用户注册、修改密码系统》(点击打开链接)应用到Javaweb中Jsp+Servlet+JDBC的场合。

0 0
原创粉丝点击