事务解决的问题:转账问题。
甲向乙转账1000元
执行步骤:1、甲的账户 - 1000 2、乙的账户 + 1000
如果执行第一步之后,第二步出现问题,此时数据就发生了错误。
事务就是把一组操作打包在一起,执行的时候能够保证这些操作之间满足一定的特性,避免出现上面的问题。
事务的特性:
1、原子性:一个事务是一个不可分割的单位。要么全部执行,要么全都不执行。(本质上是通过回滚方式来实现)。
2、一致性:事务处于执行前后,数据处于合法状态。
3、持久性:事务执行完毕之后,数据就被持久修改了。(写到磁盘里了)
4、隔离性:多个事务并发执行时,事务之间不能相互干扰。(本质上是线程安全问题)
隔离性和并发是相悖的,如果多个事务之间,隔离性越强,并发程度就越低;隔离性越弱,并发程度就越高,效率就越高。
隔离是为了保证数据的准确,并发是为了提高效率。
并发执行事务时产生的问题。
1、脏读。
如果一个事务A正在修改数据(还未提交),事务B事务读取了这里的修改内容,此时这样的事务B读操作就是脏读。因为事务A在提交数据之前,随时可能修改刚才的数据。
解决方案:写操作加锁,写的时候,不能读。事务A在修改数据的过程中(提交之前),事务B尝试读,就会阻塞,一直阻塞到事务A提交数据之后,事务B才能读到数据。
引入写加锁,事务的并发程度和效率降低,隔离性提高。
2、不可重复读。
事务A内部两次读取同一个数据,发现数据不一样(读的数据过程中另一事务修改了数据),就叫不可重复读。
解决方案:读也加锁。之前写加锁是指修改数据的时候,不能读取数据,但事务B读取数据的时候,事务A还可以修改数据。读加锁:事务B读取数据的时候,事务A不能修改数据。
引入读加锁,事务的并发程度就更低了,效率也更低了,隔离性更高。
3、幻读
一次事务执行过程中,两次读取到的结果集不一样(具体的数据结果不一样)。
解决方案:串行化,让修改操作与读操作彻底穿行执行,A修改时B不可以读,B读时A不可以修改。
此时的并发程度最低,效率也最低,但是数据的可靠性最高。
只要是并发编程,都会有这些问题。
MySQL的隔离级别。
1、read uncommitted:允许读取未提交的数据(隔离程度最低,并发性最高,有脏读)。
2、read committed:只允许读取已经提交的数据,相当于写加锁(隔离性提高一些,并发性降低,解决脏读,有不可重复读)。
3、repeatable read:MySQL默认级别,给读也加锁(隔离性又提高,并发性降低,解决不可重复读,会有幻读问题)。
4、serializable:严格串行化执行(隔离性最高,并发最低,解决幻读)。