java Jdbc 编程之编写Jdbc工具类,事务和批处理
目录
编写Jdbc工具类
由于每个Jdbc程序都需要连接数据库和关闭资源,因此可以将它们封装中一个工具类方便调用
代码
package com.thinknet.jdbc;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String user;
private static String password;
private static String driver;
private static String url;
static {
try {
//读取配置文件建立连接
Properties properties = new Properties();
properties.load(new FileReader("src/mysql.properties"));
user = properties.getProperty("user");
password=properties.getProperty("password");
driver=properties.getProperty("driver");
url=properties.getProperty("url");
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
//最好将编译异常转成运行时异常,调用者可以选择捕获异常进行处理,也可默认处理
throw new RuntimeException(e);
}
}
public static Connection getConnection(){
//返回连接
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
//转换成运行时异常
throw new RuntimeException(e);
}
}
public static void close(ResultSet resultSet, Statement statement ,Connection connection){
//如果不为null就关闭连接
try {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if(connection!=null){
connection.close();
}
} catch (SQLException e) {
//转成运行时异常
throw new RuntimeException(e);
}
}
}
应用:
用Jdbc工具类连接数据库,查询,更新数据库
package com.thinknet.jdbc;
import java.sql.*;
/**
* 使用Jdbc工具类
*/
public class JdbcUtilsUse {
public static void main(String[] args) {
//更新数据库
// update();
//查询数据库
select();
}
public static void update(){
String sql="update actor set `name`=? where `id`=?";
//获取连接
Connection connection=null;
PreparedStatement preparedStatement=null;
try {
connection = JdbcUtils.getConnection();//调用工具类获取连接
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"king");
preparedStatement.setInt(2,1);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(null,preparedStatement,connection);//调用工具类关闭资源
}
}
public static void select(){
String sql="select `id`,`name`,`sex`,`borndate`,`phone` from `actor`";
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
try {
connection=JdbcUtils.getConnection();//调用工具类获取连接
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
Date borndate = resultSet.getDate("borndate");
String phone = resultSet.getString("phone");
System.out.println("\t"+id+"\t"+name+"\t"+sex+"\t"+borndate+"\t"+phone+"\t");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(resultSet,preparedStatement,connection);//调用工具类关闭资源
}
}
}
事务处理
基本介绍:
- 在jdbc程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一条sql语句,如果执行成功,就会向mysql数据库自动提交 而不能回滚.
- Jdbc程序为了让多条sql语句作为一个整体执行,需要使用事务.
- 调用Connection对象的setAutoCommit(false)可以取消自动提交事务.
- 在所有SQL语句成功执行后调用Connection对象的commit()方法提交事务.
- 在某个sql语句执行失败或出现异常时,调用rollback()方法回滚事务
案例:
public static void transferAccounts() {
String sql1 ="update `account` set balance = balance-1000 where id= ?";
String sql2="update `account` set balance=balance+1000 where id=?";
double money=1000;
Connection connection=null;
PreparedStatement preparedStatement=null;
try {
connection=JdbcUtils.getConnection();
connection.setAutoCommit(false); //开启了事务
preparedStatement=connection.prepareStatement(sql1);
preparedStatement.setInt(1,1);
preparedStatement.executeUpdate();
preparedStatement=connection.prepareStatement(sql2);
preparedStatement.setInt(1,2);
preparedStatement.executeUpdate();
connection.commit(); //当所有任务执行完后提交事务
} catch (SQLException e) {
try {
connection.rollback(); //如果在执行sql语句的过程中出现了异常,回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtils.close(null,preparedStatement,connection); //关闭资源
}
}
上面的代码模拟了转账操作,转账的过程应该视为一个整体,一个人的账户金额少了多少,令一个人就应该多多少,不能一个人的账户金额少了,另一个人的账户金额却不增加,这就要求出账的sql语句和进账的SQL语句应该同时成功,或同时失败,不能一个成功,一个失败.所以要用到事务,只有都成功了,才真正改变数据库,否则就回滚事务
批处理
基本介绍:
- 当需要成批插入或更新记录时,可使用java的批量更新机制,该机制允许多条语句一次提交给数据库批量处理,通常情况下,比单独提交更有效率
- Jdbc批处理包含下面方法:
addBatch():添加需要批处理的SQL语句或参数
executeBatch(): 执行批量处理语句
clearBatch(): 情况批处理包的语句 - Jdbc连接mysql时,向要用批处理,要在url加上参数?rewriteBatchedStatements=true
- 批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高
案例:
不进行批处理:
public static void noBatch() {
String sql="insert into admin2 values(?,?)";
Connection connection=null;
PreparedStatement preparedStatement=null;
//获取连接
try {
connection = JdbcUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
long state=System.currentTimeMillis();
for (int i=1;i<=5000;i++){
preparedStatement.setString(1,"jack"+i);
preparedStatement.setString(2,"666");
preparedStatement.executeUpdate();
}
long end=System.currentTimeMillis();
System.out.println("耗时: " + (end-state)+ " ms");//耗时: 3340 ms
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(null,preparedStatement,connection);
}
}
输出:
耗时: 3340 ms
批处理:
public static void Batch() {
//注意:要在url上加参数?rewriteBatchedStatements=true
String sql="insert into admin2 values(?,?)";
Connection connection=null;
PreparedStatement preparedStatement=null;
//获取连接
try {
connection = JdbcUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
long state=System.currentTimeMillis();
for (int i=1;i<=5000;i++){
preparedStatement.setString(1,"jack"+i);
preparedStatement.setString(2,"666");
//添加需要批处理的SQL语句或参数
//1. 第一次进入后创建ArrayList() ->elementData->Object[]
//2. 接着将预处理后的SQL语句放入Object[]中
//3. 如果满了,就按1.5倍扩容
//4. 到达指定的数就executeBatch
//5. 批处理会大大减少发送sql语句的网络开销,减少编译次数,效率提高
/*源码:
public void addBatch() throws SQLException {
synchronized(this.checkClosed().getConnectionMutex()) {
if (this.batchedArgs == null) {
this.batchedArgs = new ArrayList();
}
for(int i = 0; i < this.parameterValues.length; ++i) {
this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);
}
this.batchedArgs.add(new com.mysql.jdbc.PreparedStatement.BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));
}
}
*/
preparedStatement.addBatch();
if(i%1000==0){ //没以前条处理一次
//执行批量处理语句
preparedStatement.executeBatch();
//清空批处理包的语句
preparedStatement.clearBatch();
}
else if (5000-i<1000){ //处理不足sql语句1000条的情况
//执行批量处理语句
preparedStatement.executeBatch();
//清空批处理包的语句
preparedStatement.clearBatch();
}
}
long end=System.currentTimeMillis();
System.out.println("耗时: " + (end-state)+ " ms");//耗时: 924 ms
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(null,preparedStatement,connection);
}
}
输出:
耗时: 924 ms
上面的代码是向表中插入5000条数据,不进行批处理和批处理的情况下的时间消耗,可以开到批处理比不进行批处理要快一些.