目录
一、什么是事务?
事务就是你对数据的一次操作,这一次操作中可以是一句简单的添加语句,也可以是对多张表的多次操作
二、为什么要使用事务?
以为它安全,为什么安全?比如张三给李四转账,我们要从张三的账户扣钱,往李四的账户加钱,但是在执行时,张三扣钱的sql执行成功了,李四加钱的sql出错了,这时会出现张三的钱少了,李四的钱没加。怎么解决这种隐患呢?本次交易就是一个事务,在事务中,所有的sql要么都成功,要么都失败,这就到了事务的四个特性。
三、事务的四大属性(ACID)
- 原子性(atomicity):一个事务中有多个sql,这些sql要么都做,要么都不做;
- 一致性(consistency):一个事务中有多个sql,这些sql要么都成功,要么都失败,不存在上面的情况(张三钱少了,李四钱没变);
- 隔离性(isolation):顾名思义,就是各个事务之间相互隔离,互不影响
- 持久性(durability):事务一旦提交,数据便保留在数据库中。
四、JDBC事务
1.sql语句中
还是拿demo1表
查询:
开启事务,修改name,查看表信息
事务回滚,信息查看
总结:
开启事务:START TRANSACTION
提交事务:COMMIT;
回滚事务:ROLLBACK;
2.JDBC中
意思还是sql中的意思,只不过换了种形式
Connection connection;
try{
//创建链接
connection = JDBCUtil.getConnection();
//开启手动提交事务(关闭自动提交事务)
connection.setAutoCommit(false);
//自己的数据操作
*** ***
//提交事务
connection.commit();
}catch(Exception e) {
e.printStackTrace();
//异常回滚事务
connection.rollback();
}
提出问题:
在sql语句表达事务时发现一个问题,在开启事务后对数据进行修改,查看数据是我们修改过的,回滚后再看就有回到了修改前,那么问题来了?
问题一:
这个问题叫脏读,因为读取到了没有提交的数据,这种数据叫脏数据,所以叫脏读
问题二:
这个问题叫不可重复读 ,它与脏读的区别在于没有脏数据
问题三:
这个问题叫幻读,它与可重复读的区别是:不可重复读是数据变没变,而幻读是输出存在不存在问题
问题总结:
脏读和不可重复读的区别在于脏数据
不可重复读和幻读的区别在于一个是数据的变化问题,一个是数据的存在问题
这些问题的出现又产生了另一个知识点:事务的隔离级别
3.事务的四个隔离级别
事务的隔离级别由低到高分别是
1.Read uncommitted:读未提交
最低级,顾名思义,就是能够读到未提交事务的数据,所以上面的问题都会发生
2.Read committed :读已提交
只能读到已经提交事务的数据,可避免脏读
3.Repeatable read :可重复读
事务开启后不在允许修改操作,可避免脏读,不可重复读
4.Serializable :序列化
最高级事务,开启后事务按顺序执行,可避免以上问题(脏读、不可重复读、幻读)
Mysql 默认:可重复读
Oracle 默认:读已提交
五、spring事务
1.Spring 事务的七种传播属性
required、supports、mandatory、requires_new、not supported、never、nested
什么是Spring 事务的传播属性?
当多个事务同时存在的时候,spring对这些事务的处理叫事务的传播属性
所属接口TransactionDefinition
源码如下
说明:
名称 | 解释 |
PROPAGATION_REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。(默认且常见) |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。 |
使用:
1.spring配置
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource ">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入连接池对象 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 注解扫描 -->
<context:component-scan base-package="com.test.spring.demo4"/>
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
使用
@Transactional(propagation = Propagation.REQUIRED)
public class XxxServiceImpl implements XxxService {
@Autowired
private XxxDao xxxDao;
@Override
public void xxx(...) {
//TODO 实现业务
}
}
其他使用方式,看Spring中使用事务的常用几种方式_morningcat2018的博客-CSDN博客_spring事务使用
六、分布式事务
有空再总结... ...
不足或错误之处还望指出,定加修改,共同进步!