【Spring】数据库事务

7 篇文章 0 订阅

事务ACID特性

名词解释实现
原子性(Atomicity)整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。事务开始时,设置begin;完成后,执行commit;失败时,执行rollback;注意:commit和rollback只会执行其一。
一致性(Consistency)一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
隔离性(Isolation)隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。隔离级别:read-uncommitted;read-committed;repeatable-read;Serializable
持久性(Durability)在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中(写硬盘了),并不会被回滚。WAL

隔离级别

查找数据当前隔离级别:show variables like "%isolation%";

MySQL 默认的隔离级别是:REPEATABLE-READ

Oracle、SQL Server,它们的默认隔离级别也是REPEATABLE-READ吗?
Oracle 默认使用的是READ-COMMITTED
READ-UNCOMMITTED:未提交读
READ-COMMITTED:提交读
REPEATABLE-READ:可重复读
Serializable:串行化

事务并发执行时,到底会有哪些影响?

脏读,读取了其他事务未提交的值,而这些未提交的值可能是无效的值(例如被回滚了)
不可重复读,即两次读取的数据发生了变化;
幻读,即两次读取数据时,产生了之前不存在的数据;

数据读写

写锁
在事务内,对该行的写操作会加写锁,此时其他事务,无法对该行做修改,除非当前事务提交/回滚,锁被释放。

写锁可以解决:

临界资源写冲突;
修改丢失;

读会加锁吗?
读到底发生了什么?

快照读
快照读:

数据拥有很多的版本;

MVCC:多版本并发控制协议;

读取了其中的某一个版本,版本跟隔离级别有关;
哪些是快照读?比如:select * from account;
好处:快,支持高并发。
MVCC(多版本并发控制协议)

repeatable-read隔离级别下

记录数据在读取事务开始时刻,已提交的(未删除的)的版本;
在整个事务中,只会读取该版本的数据,任何修改更新都不会影响;
read-committed隔离级别下

数据读取的时刻,已提交的(未删除)的数据;
read-uncommitted隔离级别下:

没有版本的概念,所有数据都会更新到数据库,只用读取最新的数据即可。
serializable

没有版本的概念,读也会加锁。

当前读
当前读:只会读取当前最新的值。
示例:
update account set money = money - 50 where id = 1;
以及所有的修改命令,
再加上:

select * from account where … lock in share mode:读取数据,并加共享锁。
select * from account where … for update:读取数据,并加排它锁/互斥锁。

间隙锁(Mysql的Repeatable-Read解决幻读)

idusernamepasswordmoneyrole
1adminadmin0.00admin
2huaweihw66665999.00
3redmik301999.00
5oppoopporeno3299.00
10vivovivox308848.00
12mimialpha8848.00
13huaweihw111115999.00
14oppoace30002999.00

示例1:

事务A:

update account set money=1111 where id>7;

事务B:

insert into account (id,username,password,money) values(8,"mi","mimix3",3499);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

解释:(5,10),[10,14],(14,+无穷)加间隙锁,不能insert into

update account set money=999 where id=13;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

解释:id>7的[10,14]加行锁,不能update
Read-committed无间隙锁,性能较好。

示例2:

事务A:

update account set money=999 where role="admin";

事务B:

update account set money=999 where id=10;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
insert into account (id,username,password,money) values(8,"mi","mimix3",3499);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

解释:role不是索引,在用它update时,会锁表(行锁+间隙锁都开启),update和insert都不能成功;

使用注解时的配置类示例

package com.myspring.day8.myConfig;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@EnableTransactionManagement
@Configuration
@PropertySource("jdbc.properties")
@ComponentScan("com.myspring.day8")
public class BookConfig {
    @Value("${jdbcUrl}")
    private String jdbcurl;
    @Value("${myname}")
    private String username;
    @Value("${password}")
    private String password;
    @Value("${driverClass}")
    private String driverClass;

    @Bean("dataSource")
    public DataSource getDataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUrl(jdbcurl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClass);
        return dataSource;
    }

    @Bean("transactionManager")
    public PlatformTransactionManager getTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource);
//        禁止内部事务在出错时设置“rollback-only”
//        manager.setGlobalRollbackOnParticipationFailure(false);
        return manager;
    }

    @Bean("jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值