JDBC中的批处理
-
批处理:
即批量处理,通过对数据库的一次调用提交相关的SQL语句 -
作用:
一次向数据库发送多个SQL语句,可以减少连接数据库的开销,提高性能
以teacher表为例
Statement批处理
步骤:
序号 | 使用方法 | 描述 |
---|---|---|
1 | createStatement() | 创建Statement对象 |
2 | setAutoCommit() | 将auto-commit设置为false |
3 | addBatch() | 在创建的语句对象上添加SQL语句到批处理中 |
4 | executeBatch | 在创建的语句对象上使用该方法执行所有SQL语句 |
5 | commit() | 提交所有更改 |
代码示例:
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
connection.setAutoCommit(false);//关闭自动提交事务
//3定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
//4定义sql
String sql1 = "insert into teacher(tname) values('张三1')";
statement.addBatch(sql1);
String sql2 = "insert into teacher(tname) values('张三2')";
statement.addBatch(sql2);
String sql3 = "insert into teacher(tname) values('张三3')";
statement.addBatch(sql3);
String sql4 = "insert into teacher(tname) values('张三4')";
statement.addBatch(sql4);
String sql5 = "insert into teacher(tname) values('张三5')";
statement.addBatch(sql5);
int[] ints = statement.executeBatch();//执行所有SQL语句
connection.commit();//手动提交事务
for (int anInt : ints) {
System.out.println("anInt = "+anInt);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
//5关闭资源
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
运行结果以及sql数据变化:
PreparedStatement批处理
步骤:
序号 | 使用方法 | 描述 |
---|---|---|
1 | 使用占位符 | 创建SQL语句 |
2 | prepareStatement() | 创建PrepareStatement对象 |
3 | setAutoCommit() | 将auto-commit设置为false |
4 | addBatch() | 在创建的语句对象上添加SQL语句到批处理中 |
5 | executeBatch() | 在创建的语句对象上使用该方法执行所有SQL语句 |
6 | commit() | 提交所有更改 |
代码示例:
public static void main(String[] args) {
Connection connection = null;
PreparedStatement pps = null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
connection.setAutoCommit(false);//关闭自动提交事务
//3定义sql,创建状态通道(进行sql语句的发送)
pps = connection.prepareStatement("insert into teacher(tname) values(?)");
//4赋值
pps.setString(1,"李四1");
pps.addBatch();
pps.setString(1,"李四2");
pps.addBatch();
pps.setString(1,"李四3");
pps.addBatch();
pps.setString(1,"李四4");
pps.addBatch();
pps.setString(1,"李四5");
pps.addBatch();
int[] ints = pps.executeBatch();//执行所有SQL语句
connection.commit();//手动提交事务
for (int anInt : ints) {
System.out.println("anInt = "+anInt);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
//5关闭资源
if(pps != null){
pps.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}//end finally
}//end main
运行结果以及sql数据变化:
通过反射处理结果集
以学生表student为例
根据sql创建对应的类Student:
类名=表名
列名=属性名
public class Student {
private int stuid;
private String stuname;
private int teacherid;
public int getStuId() {
return stuid;
}
public void setStuId(int stuid) {
this.stuid = stuid;
}
public String getStuName() {
return stuname;
}
public void setStuName(String stuname) {
this.stuname = stuname;
}
public int getTeacherid() {
return teacherid;
}
public void setTeacherid(int teacherid) {
this.teacherid = teacherid;
}
}
新建数据处理的接口Dao,定义抽象操作方法:
public interface Dao {
//定义操作方法
//查询全部学生,非反射处理
List<Student> getAllStudent();
}
DaoImplements类实现Dao接口,编写具体方法:
@Override
public List<Student> getAllStudent() {
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
//3定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from student ";
pps = connection.prepareStatement(sql);
//执行sql
resultSet = pps.executeQuery();
List<Student> students = new ArrayList<>();//创建学生集合
//取值
while(resultSet.next()){
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
student.setTeacherid(resultSet.getInt("teacherid"));
students.add(student);
}
return students;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
//5关闭资源
if(resultSet != null){
resultSet.close();
}
if(pps != null){
pps.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}//end finally
return null;
}
编写操作实现类Test:
public class Test{
public static void main(String[] args) {
List<Student> allStudent =dao.getAllStudent();
for (Student student : allStudent) {
System.out.println(student.getStuId()+","+student.getStuName()+","+student.getTeacherid());
}
}
}
输出结果:
1,张三,3
2,李四,1
3,王五,3
4,赵六,1
5,花花,1
6,潇潇,2
实际开发过程中,当表的列很多时,上述写法获取列效率低,通过反射能够简化结果集的处理
还是以student表为例
在数据处理的接口Dao,定义抽象操作方法:
public interface Dao {
//定义操作方法
/*
//查询全部学生,非反射处理
List<Student> getAllStudent();
*/
//查询全部学生,反射处理
List<Student> getAllStudent(Class cla);
}
在实现TeacherDao接口的DaoImplements类中,编写具体方法:
@Override
public List<Student> getAllStudent(Class cla) {
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
connection = DriverManager.getConnection(url, userName, passWord);
//3定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from student ";
pps = connection.prepareStatement(sql);
//执行sql
resultSet = pps.executeQuery();
List students = new ArrayList();//创建学生集合
/*
//取值
while(resultSet.next()){
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
student.setTeacherid(resultSet.getInt("teacherid"));
students.add(student);
}
*/
//!!!!!!!以下通过反射,让结果集自动匹配set方法
//得到当前数据库查询结果的列信息
ResultSetMetaData metaData = resultSet.getMetaData();//存储结果集信息
int columnCount = metaData.getColumnCount();//得到列数
String[] columnNames = new String[columnCount];//数组长度为列的数量
//获取列名
for(int i = 0;i < columnCount;i++){
columnNames[i] = metaData.getColumnName(i+1);//列从1开始
System.out.println("columnName = "+columnNames[i]);
}
//获取类中所有的方法
Method[] declaredMethods = cla.getDeclaredMethods();
//取值
while(resultSet.next()){
try {
Object stu = cla.newInstance();//得到一个学生对象
//从对应列取出值,赋给对应的属性
/*
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname")
比如"stuid"应该通过setStuId
*/
for (String columnName : columnNames) {//遍历列名
String methodName = "set" + columnName;//装饰,set某一属性
for (Method declaredMethod : declaredMethods) {//遍历所有方法
//忽略大小写,通过反射获得的方法名,如果相等,则该方法为对此属性进行赋值的方法
if(declaredMethod.getName().equalsIgnoreCase(methodName)){
//不确定类为什么类型,因此为object
//给某一对象赋值,值为某一列中取出的值
declaredMethod.invoke(stu,resultSet.getObject(columnName));
break;
}//end if
}//end for method
}//end for columnname
students.add(stu);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}//end while
return students;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
//5关闭资源
if(resultSet != null){
resultSet.close();
}
if(pps != null){
pps.close();
}
if(connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}//end finally
return null;
}
编写操作实现类Test:
public class Test{
public static void main(String[] args) {
/*
List<Student> allStudent =dao.getAllStudent();
for (Student student : allStudent) {
System.out.println(student.getStuId()+","+student.getStuName()+","+student.getTeacherid());
}
*/
List<Student> allStudent =dao.getAllStudent(Student.class);
for (Student student : allStudent) {
System.out.println(student.getStuId()+","+student.getStuName()+","+student.getTeacherid());
}//end for
}//end main
}//end class
输出结果:
columnName = stuid
columnName = stuname
columnName = teacherid
1,张三,3
2,李四,1
3,王五,3
4,赵六,1
5,花花,1
6,潇潇,2
通过观察反射处理结果集的两个代码示例,可以发现重复步骤的代码大同小异,因此我们可以自定义一个工具类DBUtil,在类中将上述操作的重复代码以方法的形式进行封装,提高代码的简洁性
程序中重复代码的封装及运用可阅读文章:JDBC中自定义工具类