這周在學(xué)數(shù)據(jù)庫(kù),以及和JDBC連接數(shù)據(jù)庫(kù)進(jìn)行操作。首先看看JDBC如何處理事務(wù)和批處理吧。
演示事務(wù)
idea中try catch快捷鍵: Ctrl + win + Alt + t
事務(wù)的四大屬性
- 原子性(Atomicity):事務(wù)是一個(gè)不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都失敗。
- 一致性(Consistency):事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)轉(zhuǎn)換到另一個(gè)一致性狀態(tài)。
- 隔離性(Isolation):一個(gè)事務(wù)的執(zhí)行不能被另一個(gè)事務(wù)干擾,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不會(huì)互相干擾。
- 持久性(Durability):一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫(kù)中的數(shù)據(jù)的操作是持久性的,接下來(lái)的其他操作或者數(shù)據(jù)庫(kù)故障都不對(duì)它產(chǎn)生任何影響。
事務(wù)使用步驟
-
開啟新事務(wù)
取消隱式事務(wù)自動(dòng)提交的功能。
編寫組成事務(wù)的一組sql語(yǔ)句
-
結(jié)束事務(wù)
- commit();提交
- rollback();回滾
!注意:
開啟事務(wù)的連接對(duì)象和獲取命令的連接對(duì)象必須是同一個(gè)!否則事務(wù)無(wú)效。
使用和不用事務(wù)的區(qū)別
- 不用事務(wù) : 異常前后的語(yǔ)句執(zhí)行情況不同。只能執(zhí)行異常前的,異常后的無(wú)效。
- 使用事務(wù) : 可以根據(jù)有無(wú)異常自動(dòng)執(zhí)行提交事務(wù)或回滾。
import com.miyon.jdbc.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 演示JDBC中的事務(wù):
*
*使用步驟:
* 1.開啟新事務(wù),取消隱式事務(wù)自動(dòng)提交的功能
* setAutoCommit(false);
* 2.編寫組成事務(wù)的一組sql語(yǔ)句
*
* 3.結(jié)束事務(wù)
* commit();提交
* rollback();回滾
*
* !注意:
* 開啟事務(wù)的連接對(duì)象和獲取命令的連接對(duì)象必須是同一個(gè)!否則事務(wù)無(wú)效。
*
*/
public class TestTransaction {
//不用事務(wù) : 異常前后的語(yǔ)句執(zhí)行情況不同。
@Test
public void testNoTransaction() throws Exception{
//1.獲取連接
Connection connection = JDBCUtils.getConnection2();
//2.編寫語(yǔ)句
PreparedStatement statement = connection.prepareStatement("UPDATE stronginfo SET height=? WHERE id=?");
//2.1 設(shè)置id為1 的身高為100
statement.setInt(1,100);
statement.setInt(2,1);
statement.executeUpdate();
int i = 1/0; //模擬異常 異常前面的身高改變,后面的沒(méi)有變化。
//2.2 設(shè)置id為2 的身高為200
statement.setInt(1,200);
statement.setInt(2,2);
statement.executeUpdate();
//3.釋放資源
JDBCUtils.close(null,statement,connection);
}
//使用事務(wù) : 可以根據(jù)有無(wú)異常自動(dòng)執(zhí)行提交事務(wù)或回滾。
@Test
public void testTransaction() {
Connection connection = null;
PreparedStatement statement = null;
try {
//1.獲取連接
connection = JDBCUtils.getConnection2();
//2.使用事務(wù)
//事務(wù)的使用步驟①:開啟事務(wù)
connection.setAutoCommit(false);//取消事務(wù)自動(dòng)開啟,開啟事務(wù)。
//事務(wù)的使用步驟②:編寫sql語(yǔ)句并執(zhí)行
statement = connection.prepareStatement("UPDATE stronginfo SET height=? WHERE id=?");
// 設(shè)置id為1 的身高為175
statement.setInt(1,100);
statement.setInt(2,1);
statement.executeUpdate();
// int i = 1/0;
//模擬異常,使用事務(wù)時(shí),遇到異常,發(fā)生回滾,數(shù)據(jù)沒(méi)有發(fā)生變化。
// int i = 1/0;
//沒(méi)有異常時(shí),正常結(jié)束事務(wù),執(zhí)行語(yǔ)句,數(shù)據(jù)發(fā)生變化。
// 設(shè)置id為2 的身高為205
statement.setInt(1,99);
statement.setInt(2,2);
statement.executeUpdate();
//事務(wù)的使用步驟③:結(jié)束事務(wù)
connection.commit();
} catch (SQLException throwables) {
try {
//事務(wù)回滾
connection.rollback();
} catch (SQLException e) {
}
}finally {
try {
JDBCUtils.close(null,statement,connection);
} catch (Exception e) {
}
}
}
}
批處理
- mysql默認(rèn)批處理是關(guān)閉的,所以我們還需要去打開mysql的批處理:
rewriteBatchedStatements=true
我們需要將以上的參數(shù)添加到mysql的url地址中。
- 注意:低版本的mysql-jdbc驅(qū)動(dòng)也不支持批處理,一般都是在修改的時(shí)候使用批處理,查詢的時(shí)候不使用!
相關(guān)API:
- addBatch();
- executeBatch();
- clearBatch();
說(shuō)明:
批處理往往和PreparedStatement一起搭配使用,既可以減少編譯次數(shù),又能減少運(yùn)行次數(shù),大大提高效率!
import com.miyon.jdbc.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* 演示批處理的使用
*
* 案例:
* 向admin表中插入50000行數(shù)據(jù);
*
*
*/
public class TestBatch {
//不使用批處理
@Test
public void testNoBatch() throws Exception {
//1.獲取連接
Connection connection = JDBCUtils.getConnection();
//2.執(zhí)行插入
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");
//執(zhí)行
statement.executeUpdate();
}
//3.關(guān)閉連接
JDBCUtils.close(null,statement,connection);
}
//使用批處理
@Test
public void testBatch() throws Exception{
//1.獲取連接
Connection connection = JDBCUtils.getConnection();
//2.執(zhí)行插入
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");
//執(zhí)行
statement.addBatch(); //將sql語(yǔ)句添加到批處理包中
if(i%10000==0){ //每1000條執(zhí)行一次
statement.executeBatch();//執(zhí)行批處理包中的sql語(yǔ)句
statement.clearBatch(); //清空批處理包中的sql語(yǔ)句
}
}
//3.關(guān)閉連接
JDBCUtils.close(null,statement,connection);
}
}