在上一篇中,我们完成了JDBC的基本添加、删除操作,同时也发现了两个问题:
在使用完JDBC资源后,如果不关闭,可能会造成内存泄露的问题。
当需要添加的数据或需要修改的数据量很多时,通过pstm.setObject(, );
方法这样一个个输入显然是不现实的,效率太低了!那么,我们是否可以采用其他方式提高效率呢?
我们可不可以定义一个数组用于储存我们需要修改的数据,当进行JDBC操作时,将这个数组导入操作方法,一口气完成操作呢?
一、引入:动态参数的使用
JDK1.5之后新增了动态参数的使用方法,下边仅给出简单示例:
public class ParameterTest
{
public static void PrintStudentName(String...val)
{
int i = 0;
//在这里使用了动态参数,使用String name获取val的值,只要val还有下一个值,就依次给name赋值
for(String name:val)
{
i++;
System.out.println("第"+i+"次获取的值为:"+name);
}
}
public static void main(String[] args)
{
ParameterTest.PrintStudentName("张三","李四","王五","赵六");
}
}
可以得到输出结果
第1次获取的值为:张三
第2次获取的值为:李四
第3次获取的值为:王五
第4次获取的值为:赵六
二、优化尝试1
假设我们想要尝试执行这样一条sql语句:
INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)
VALUES(S_STU.NEXTVAL,'葫芦娃',TO_DATE('1900-9-9','YYYY-MM-DD'),0,'那时还没考试');
之前提供的方法是这样的:
StudentServices.java
package com.whm.services;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class StudentServices
{
//1.添加学生
public void addStudent()throws Exception
{
//1.定义连接串url
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
//2.通过驱动管理器匹配url,创建连接
Connection conn = DriverManager.getConnection(url, "admin", "admin1234");
//3.定义sql
StringBuilder sql = new StringBuilder()
.append("INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)")
.append(" VALUES(S_STU.NEXTVAL,?,TO_DATE(?,'YYYY-MM-DD'),?,?)");
//4.预编译sql
PreparedStatement pstm = conn.prepareStatement(sql.toString());
//5.参数赋值
pstm.setObject(1, "葫芦娃");
pstm.setObject(2, "1900-9-9");
pstm.setObject(3, "0");
pstm.setObject(4, "那时还没考试");
//6.执行sql
int tag = pstm.executeUpdate();
System.out.println(tag);
}
}
StudentServicesTest.java
package test;
import com.whm.services.StudentServices;
public class StudentServicesTest
{
public static void main(String[] args)
{
try
{
StudentServicesTest.addStudentTest();
}
catch(Exception e)
{
e.printStackTrace();
}
}
//测试添加学生
public static void addStudentTest()throws Exception
{
StudentServices services = new StudentServices();
services.addStudent();
}
}
下边通过动态参数调用,减少了pstm.setObject()
方法的使用次数,同时,使得测试方法中的调用更加便捷
//添加学生
public void addStudent(Object...val)throws Exception
{
//1.定义连接串url
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
//2.通过驱动管理器匹配url,创建连接
Connection conn = DriverManager.getConnection(url, "admin", "admin1234");
//3.定义sql
StringBuilder sql = new StringBuilder()
.append("INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)")
.append(" VALUES(S_STU.NEXTVAL,?,TO_DATE(?,'YYYY-MM-DD'),?,?)");
//4.预编译sql
PreparedStatement pstm = conn.prepareStatement(sql.toString());
//5.参数赋值
int index = 1;
for(Object param:val)
{
pstm.setObject(index++, param);
}
//6.执行sql
int tag = pstm.executeUpdate();
System.out.println(tag);
}
测试方法中:
//测试添加学生
public static void addStudentTest()throws Exception
{
StudentServices services = new StudentServices();
/**
* 创建一个Object数组,用于提供我们想要传递的值
* 带上sql语句用于参照对应:
* INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)
*/
Object val[] = {"葫芦娃","1900-9-9","0","那时还没考试"};
//将值传入方法
services.addStudent(val);
}
在addStudent()方法中得到一个参数,同时修改了步骤5
三、优化尝试2
观察我们书写的代码可知:
1.内存泄露问题依旧没有解决
2.每次进行JDBC操作时,都需要书写步骤1和步骤2
于是可以想办法对代码进行改进:
先解决内存泄露问题吧,这个简单,在程序结束后将其关闭即可,修改后的代码如下:
//添加学生
public void addStudent(Object...val)throws Exception
{
//1.定义JDBC变量
Connection conn = null;
PreparedStatement pstm = null;
try
{
//2.定义连接串url
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
//3.通过驱动管理器匹配url,创建连接
conn = DriverManager.getConnection(url, "admin", "admin1234");
//4.定义sql
StringBuilder sql = new StringBuilder()
.append("INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)")
.append(" VALUES(S_STU.NEXTVAL,?,TO_DATE(?,'YYYY-MM-DD'),?,?)");
//5.预编译sql
pstm = conn.prepareStatement(sql.toString());
//6.参数赋值
int index = 1;
for(Object param:val)
{
pstm.setObject(index++, param);
}
//7.执行sql
int tag = pstm.executeUpdate();
System.out.println(tag);
}
finally//在此处销毁资源
{
pstm.close();
conn.close();
}
}
四、优化尝试3
实际上,目前还存在大量重复代码,每个操作都需要创建连接、销毁资源,我们也想办法将其封装起来。
我在之前创建的工具目录com.whm.system.db目录下创建了一个新文件:DBUtils.java。
在此文件中书写一些必要的步骤,同时考虑异常问题
DBUtils.java
package com.whm.seystem.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
//JDBC Utils 类
public class DBUtils
{
//获取数据库连接
public static Connection getConnection()throws Exception
{
//1.定义连接url
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
//2.通过驱动管理器匹配url,创建连接
Connection conn = DriverManager.getConnection(url, "admin", "admin1234");
//3.带出连接对象
return conn;
}
public static void close(PreparedStatement pstm)
{
try
{
if( pstm!= null)
{
pstm.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void close(Connection conn)
{
try
{
if( conn!= null)
{
conn.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
那么,我们就可以调用这个DBUtils工具类
StudentServices.java
package com.whm.services;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.whm.seystem.db.DBUtils;
public class StudentServices
{
//添加学生
public void addStudent(Object...val)throws Exception
{
//1.定义JDBC变量
Connection conn = null;
PreparedStatement pstm = null;
try
{
//2.创建连接
conn = DBUtils.getConnection();
//3.定义sql
StringBuilder sql = new StringBuilder()
.append("INSERT INTO STUDENT(STUID,SNAME,SDATE,SCORE,MEMO)")
.append(" VALUES(S_STU.NEXTVAL,?,TO_DATE(?,'YYYY-MM-DD'),?,?)");
//4.预编译sql
pstm = conn.prepareStatement(sql.toString());
//5.参数赋值
int index = 1;
for(Object param:val)
{
pstm.setObject(index++, param);
}
//6.执行sql
int tag = pstm.executeUpdate();
System.out.println(tag);
}
finally//在此处销毁资源
{
DBUtils.close(pstm);
DBUtils.close(conn);
}
}
}
至此,我们已经完成了传递数据和连接的初步优化
五、新的思考,站在客户角度考虑
1、在许多公司的内部,为了保证数据的安全性,定期会修改公司的内部账号,数据库账号密码也不例外。那么,我们在给客户设计程序的时候,如果像之前这样将用户名密码直接写在代码中,是十分不利于客户使用的。并且将代码交给客户也是存在很大风险的一件事。因此,我们需要找到一个方法来解决这个问题。
2、客户对于操作后,executeUpdate()
返回影响了几行数据的这种结果可能并不买账。我们需要一个更直观的操作结果。