这周在学数据库,以及和JDBC连接数据库进行操作。首先看看JDBC如何处理事务和批处理吧。
演示事务
idea中try catch快捷键: Ctrl + win + Alt + t
事务的四大属性
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都失败。
- 一致性(Consistency):事务必须使数据库从一个一致性状态转换到另一个一致性状态。
- 隔离性(Isolation):一个事务的执行不能被另一个事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不会互相干扰。
- 持久性(Durability):一个事务一旦被提交,它对数据库中的数据的操作是持久性的,接下来的其他操作或者数据库故障都不对它产生任何影响。
事务使用步骤
-
开启新事务
取消隐式事务自动提交的功能。
编写组成事务的一组sql语句
-
结束事务
- commit();提交
- rollback();回滚
!注意:
开启事务的连接对象和获取命令的连接对象必须是同一个!否则事务无效。
使用和不用事务的区别
- 不用事务 : 异常前后的语句执行情况不同。只能执行异常前的,异常后的无效。
- 使用事务 : 可以根据有无异常自动执行提交事务或回滚。
import com.miyon.jdbc.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 演示JDBC中的事务:
*
*使用步骤:
* 1.开启新事务,取消隐式事务自动提交的功能
* setAutoCommit(false);
* 2.编写组成事务的一组sql语句
*
* 3.结束事务
* commit();提交
* rollback();回滚
*
* !注意:
* 开启事务的连接对象和获取命令的连接对象必须是同一个!否则事务无效。
*
*/
public class TestTransaction {
//不用事务 : 异常前后的语句执行情况不同。
@Test
public void testNoTransaction() throws Exception{
//1.获取连接
Connection connection = JDBCUtils.getConnection2();
//2.编写语句
PreparedStatement statement = connection.prepareStatement("UPDATE stronginfo SET height=? WHERE id=?");
//2.1 设置id为1 的身高为100
statement.setInt(1,100);
statement.setInt(2,1);
statement.executeUpdate();
int i = 1/0; //模拟异常 异常前面的身高改变,后面的没有变化。
//2.2 设置id为2 的身高为200
statement.setInt(1,200);
statement.setInt(2,2);
statement.executeUpdate();
//3.释放资源
JDBCUtils.close(null,statement,connection);
}
//使用事务 : 可以根据有无异常自动执行提交事务或回滚。
@Test
public void testTransaction() {
Connection connection = null;
PreparedStatement statement = null;
try {
//1.获取连接
connection = JDBCUtils.getConnection2();
//2.使用事务
//事务的使用步骤①:开启事务
connection.setAutoCommit(false);//取消事务自动开启,开启事务。
//事务的使用步骤②:编写sql语句并执行
statement = connection.prepareStatement("UPDATE stronginfo SET height=? WHERE id=?");
// 设置id为1 的身高为175
statement.setInt(1,100);
statement.setInt(2,1);
statement.executeUpdate();
// int i = 1/0;
//模拟异常,使用事务时,遇到异常,发生回滚,数据没有发生变化。
// int i = 1/0;
//没有异常时,正常结束事务,执行语句,数据发生变化。
// 设置id为2 的身高为205
statement.setInt(1,99);
statement.setInt(2,2);
statement.executeUpdate();
//事务的使用步骤③:结束事务
connection.commit();
} catch (SQLException throwables) {
try {
//事务回滚
connection.rollback();
} catch (SQLException e) {
}
}finally {
try {
JDBCUtils.close(null,statement,connection);
} catch (Exception e) {
}
}
}
}
批处理
- mysql默认批处理是关闭的,所以我们还需要去打开mysql的批处理:
rewriteBatchedStatements=true
我们需要将以上的参数添加到mysql的url地址中。
- 注意:低版本的mysql-jdbc驱动也不支持批处理,一般都是在修改的时候使用批处理,查询的时候不使用!
相关API:
- addBatch();
- executeBatch();
- clearBatch();
说明:
批处理往往和PreparedStatement一起搭配使用,既可以减少编译次数,又能减少运行次数,大大提高效率!
import com.miyon.jdbc.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* 演示批处理的使用
*
* 案例:
* 向admin表中插入50000行数据;
*
*
*/
public class TestBatch {
//不使用批处理
@Test
public void testNoBatch() throws Exception {
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行插入
PreparedStatement statement = connection.prepareStatement("INSERT INTO admin values(null,?,?)");
for (int i = 0; i < 50000; i++) {
statement.setString(1,"john"+i);
statement.setString(2,"0000");
//执行
statement.executeUpdate();
}
//3.关闭连接
JDBCUtils.close(null,statement,connection);
}
//使用批处理
@Test
public void testBatch() throws Exception{
//1.获取连接
Connection connection = JDBCUtils.getConnection();
//2.执行插入
PreparedStatement statement = connection.prepareStatement("INSERT INTO admin values(null,?,?)");
for (int i = 0; i <= 500000; i++) {
statement.setString(1,"john"+i);
statement.setString(2,"0000");
//执行
statement.addBatch(); //将sql语句添加到批处理包中
if(i%10000==0){ //每1000条执行一次
statement.executeBatch();//执行批处理包中的sql语句
statement.clearBatch(); //清空批处理包中的sql语句
}
}
//3.关闭连接
JDBCUtils.close(null,statement,connection);
}
}