事务:
事务是指逻辑上的一组操作,组成这组操作的各个逻辑单元要么一起成功, 要么一起失败。
mysql的事务管理有两种:(在mysql数据库中直接操作[黑窗口])
1.手动开启事务:
a: start transaction;--开启事务
b: 执行多条sql语句
c: commit/rollback;--提交事务或者回滚事务
2.设置一个自动提交参数:
查看与commmit相关参数:show variables like "%commit%"
可以查看到一个名为autocommit的属性
设置autocommit属性值
set autocommit = 0;--将autocommit的值设置为off,默认是on开启状态。(0代表off,1代表on)
注意:mysql数据库事务默认是自动提交的; oralce数据库事务默认是不自动提交的。
jdbc的事务管理
java.sql.Connection API:
void setAutoCommit(boolean flag):设置此连接的自动提交状态
void commit() :提交此连接的事务
void rollback() :回滚此连接的事务
事务特性:
原子性:强调事务的不可分割性。
一致性:强调的是事务的执行前后,数据的完整性要保持一致。
隔离性:一个事务的执行不应该受到其他事务的干扰。
持久性:事务一旦结束(commit/rollback)数据就持久到了数据库中。
注意:如果不考虑事务的隔离性,引发一些安全性问题:
一类读问题:
脏读:一个事务读到另一个事务还没有提交的数据。
不可重复度:;一个事务读到了另一个事务已经提交的update的数据,导致在当前的事务中多次查询结果不一致。
虚度/欢度:一个事务读到了另一个事务已经提交的insert数据,导致在当前的事务中多次查询结果不一致。
一类写问题:
引发两类丢失更新。
解决引发的读问题:
设置事务的隔离级别:
read uncommitted: 未提交读(脏读,不可重复读,虚度都可能发生)
read committed: 已提交读(避免脏读,但是不可重复读和虚读有可能发生)
repeatable read: 可重复度(避免脏读和不可重读读,但是虚读有可能发生)
serializable: 串行化(避免脏读,不可重复读,虚读的发生)
mysql设置事务的隔离级别:
查看连接的隔离级别:select @@tx_isolation;
设置连接(黑窗口)的隔离级别为:read uncommitted:
set session transaction isolation level read uncommitted;
设置连接(黑窗口)的隔离级别为:read committed:
set session transaction isolation level read committed;
设置连接(黑窗口)的隔离级别为:repeatable read:
set session transaction isolation level repeatable read;
设置连接(黑窗口)的隔离级别为:serializable:
set session transaction isolation level serializable;
jdbc设置事务的隔离级别:
Connection API:
void setTransactionIsoLation(int level):设置事务的隔离级别。
注意:不论是通过黑窗口或者jdbc连接数据库都是仅仅建立了一条Connection连接,设置事务隔离级别也是仅仅针对该Connection进行设置。
事务管理两种实现方法:
一: 将Connection一层层向下传递,DBUtils 进行事务管理使用的就是这种方法。
二: 在业务层获得connection将这个连接绑定到当前线程中,从当前线程中获取。hibernate底层事务管理使用的是这种方法。
ThreadLocal 本地线程类
它里面维护的是map,map的key是当前线程,map的value是要绑定的东西,绑定的时候set(value),获取的时候get()获得value。
示例代码:
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcUtils {
private static final ComboPooledDataSource DATASOURCE = new ComboPooledDataSource();
private static final ThreadLocal<Connection> TL = new ThreadLocal<Connection>();
public static DataSource getDataSource() {
return DATASOURCE;
}
public static Connection getConn() throws SQLException {
if (TL.get() == null) {
TL.set(DATASOURCE.getConnection());
}
return TL.get();
}
public static void beginTranscation() throws SQLException {
if (TL.get() == null) {
TL.set(DATASOURCE.getConnection());
}
TL.get().setAutoCommit(false);
}
public static void committranscation() throws SQLException {
if (TL.get() == null) {
TL.set(DATASOURCE.getConnection());
}
TL.get().commit();
}
public static void roolbackTranscation() throws SQLException {
if (TL.get() == null) {
TL.set(DATASOURCE.getConnection());
}
TL.get().rollback();
}
}