一、事务
事务定义:满足acid的一到多个SQL组成的一个整体。
二、事务特性
1、原子性:一个整体,不可分割。
拿转账举例,A转给B100元,A-100和B+100是一个整体,不能单独发生,若是A-100成功,B+100未成功,则整个事务将回滚。
2、一致性:
拿转账举例,A转给B100元,A-100则B必须+100,不能不加或者+200,否则增加和减少的数据不一致,钱的总数发生了改变。
再例如,删除一个学生,则学生相关的成绩,选课等等和这个学生的相关信息也要一并删除。
3、独立性:
独立性是多个事务之间,形容事物之间彼此的可见性的。
绝对的独立性是指一个事物未结束,则它的执行过程对其他事务是不可见的。(但是独立性越高,性能越差,因此实际应用中往往不会使用绝对独立性)
不同的独立性级别用事务的隔离级别来形容。
4、持久性:
事务一旦提交,则数据库中必须要做成相应的操作,即使数据库崩溃,待恢复时,数据库也要根据日志完成事务中的一系列操作。
三、事务的隔离级别
事务的隔离级别是用来形容事务之间彼此的可见性的。
1、未提交的读:
事务还未提交,便可以读到这个事务的操作流程产生的结果。
例:A转账给B100元这个事务还未提交,其他事务就可以查到A-100.
一旦转账失败,事务回滚.则其他事务查到的数据就是脏数据。
结果:产生脏读
2、提交的读:
必须等当前事务提交后,其他事务才能读取这个事物的结果,但是允许其他事务更新数据,当前事务可能会获得两次不一样的结果。
解决:脏读
结果:产生不可重复读问题
3、可重复读:
必须等当前事务提交后,其他事务才能读取这个事物的结果,但是允许其他事务插入数据,当前事务可能会获得新增数据。
解决:不可重复读
结果:产生幻读问题
4、序列化:
必须等当前事务提交后,其他事务才能读取这个事物的结果,不允许插入也不允许修改
解决:幻读
结果:不会产生问题
四、更新丢失
1、定义:如果多个线程操作,基于同一个查询结构对表中的记录进行修改,那么后修改的记录将会覆盖前面修改的记录,前面的修改就丢失掉了,这就叫做更新丢失。
2、序列化可以防止更新丢失问题的发生。其他的三个隔离级别都有可能发生更新丢失问题。
3、解决:
加乐观锁:
乐观的认为每一条sql语句都不会出现更新丢失的情况,然后
在表中增加一个version字段,在更新数据库记录是将version加一,从而在修改数据时通过检查版本号是否改变判断出当前更新基于的查询是否已经是过时的版本。
如果数据库中数据的修改比较多,更新失败的次数会比较多,程序需要多次重复执行更新操作。
五、锁机制
记录锁 – 锁定某行
间隙锁 – 锁定某个区间
临键锁 – 锁定左开右闭的一段区间
(各种锁各司其职,结合一些其他的机制,实现事务的隔离,比较复杂,就不深入理解了)
1、共享锁:允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。
2、排他锁:一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。
共享锁【S锁】
又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
排他锁【X锁】
又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。