本文没有任何新的内容,只是设置一个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 UTF8
String 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的场合。