データベーストランザクション:トランザクション
- いくつかのSQL文からなる一連の操作
- どちらのすべて正常に実行さ
- すべての実行に失敗したのいずれか
データベースのトランザクションは、ACID特性を有します:
原子性:アトミックそれ自体はアトミック操作ですが、いくつかのSQL文にもかかわらず、トランザクションを、どちらかのすべてが成功するか、すべて失敗します
一貫性:一貫性のデータベース内のデータの終了前または後に取引完了し、一貫性のないデータや紛争の不在
単離:分離された複数のトランザクションの同時実行は、トランザクションが分離の間にあるとき、トランザクションが実行されている他のサービスの結果には影響しません。
耐久性:耐久性のトランザクションは、一度正常に完了し、トランザクションは、永続的にデータベースに残り、ロールバックされませんデータベースに変更されます。
なぜあなたは、データベーストランザクションが必要なのでしょうか?
例:転送操作100に元ボブ赤から転送されたアカウント。
update accounts set balance = balance - 100 while id = 1;
update accounts set balance = balance + 100 while id = 2;
最初の更新文の実行万人の後に、様々な理由のために、2回目の更新が行われていない場合は、どのような結果が起こるのだろうか?
暁明金は控除されている、プラス赤お金は、この時点でアプリケーション・ロジックは、矛盾が登場していません。
データベーストランザクションの使用は、完全にその複数のSQL文またはキャンセルを確保するために実装することができます。それは2つだけの結果である:
成功した赤に転送1.暁明のお金
2.暁明は暁明がアカウントを返す、赤、成功せずにお金を移しました。ボブとアリスのお金は変わりません。
トランザクションの独立したレベル:データベースは執行部のために、同時に多くの接続で構成されています。
スレッドは、データベース接続を動作している場合、Javaプログラムでは、別のスレッドは、データベースを介して更新データに接続することができます。分離レベルは、それらの間に問題が発生します。
トランザクションの分離は、3つの問題が発生します:
1.ダーティ・リード
2.非繰り返し繰り返しを
3魔法の読書
package com.feiyangedu.sample.pop3;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class JdbcTx {
static final String JDBC_URL = "jdbc:mysql://localhost:13306/test0828?characterEncoding=utf8&useSSL=false&serverTimeZone=UTC";
static final String JDBC_USER = "root";
static final String JDBC_PASSWORD = "123456";
public static void main(String[] args) throws SQLException{
List<Student> students = getAllStudents();
for(Student student:students){
System.out.println(student);
}
Connection conn = null;
try{
conn = getConnection();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
updateName(conn, students.get(0).id, "Bob");
updateName(conn, students.get(1).id, "Alice");
conn.commit();
System.out.println("commit ok");
}catch (Exception e){
e.printStackTrace();
conn.rollback();
}finally {
if(conn != null){
try{
conn.setAutoCommit(true);
conn.close();
}catch (SQLException e){
System.err.println(e);
}
}
}
System.out.println("第一次事务结束后");
students = getAllStudents();
for(Student student:students){
System.out.println(student);
}
try{
conn = getConnection();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
updateName(conn, students.get(0).id,"张三");
updateName(conn, students.get(1).id,"李四");
throw new RuntimeException("第二次事务出错");
}catch (Exception e){
conn.rollback();
}finally {
if(conn != null){
try{
conn.setAutoCommit(true);
conn.close();
}catch (Exception e){
System.err.println(e);
}
}
}
System.out.println("第二次事务结束");
students = getAllStudents();
for(Student student:students){
System.out.println(student);
}
}
static void updateName(Connection conn, long id, String name) throws SQLException{
try(PreparedStatement ps = conn.prepareStatement("update students set name=? where id=?")){
ps.setObject(1, name);
ps.setObject(2, id);
ps.executeUpdate();
}
}
static List<Student> getAllStudents() throws SQLException{
try(Connection conn = getConnection()){
try(PreparedStatement ps = conn.prepareStatement("select * from students")){
ResultSet rs = ps.executeQuery();
List<Student> list = new ArrayList<>();
while(rs.next()){
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
list.add(new Student(id,classId,name,gender));
}
return list;
}
}
}
static Connection getConnection() throws SQLException {
return DriverManager.getConnection(JDBC_URL,JDBC_USER,JDBC_PASSWORD);
}
}