关于数据库的事务

由于Mongodb不支持事务(老版本),自己在工作中也从来没有用过事务,今天在面试的时候提到类似这么一个问题:在数据库中要新增一条A记录,同时要修改B记录的一个字段,这个肯定是用事务实现,但是Mongodb不支持事务,你会怎么设计数据库的事务?

很尴尬,我不知道如何回答。

1.事务的用法

先来一段事务的使用方法(网上看到的,不保证正确性)

try {  
    conn.setAutoCommit(false);  //将自动提交设置为false  

    ps.executeUpdate("修改SQL"); //执行修改操作  

    ps.executeQuery("查询SQL");  //执行查询操作                 

    conn.commit();      //当两个操作成功后手动提交  

} catch (Exception e) {  

    conn.rollback();    //一旦其中一个操作出错都将回滚,使两个操作都不成功  

    e.printStackTrace();  
} 

由以上代码可以看出,将两个操作当作一个事务来执行,执行完毕后可以commit该事务,否则回滚该事务,不会对数据库中的数据产生任何影响。

2.事务的实现

事务有四大特性:ACID
以转账操作为例,A账户转账100元给B账户。
原子性:即两个操作要么都执行,要么都不产生效果,绝对不会产生A-B的中间状态。
一致性:即A账户减少了100元钱,B账户就一定增加了100元,否则就违背了一致性。
隔离性:两个事务之间的操作不应该互相影响。
持久性:数据库事务一旦提交,就不会再被修改。

问题一:原子性和一致性有什么区别?
从描述上来看,原子性保证所有操作必须执行或者都不产生效果,那么只有AB两个状态,即一致性的两种状态。
那为什么说原子性不能保证一致性呢?
因为事务1在执行的时候,事务2有可能会影响到事务1的中间状态,这就引入了隔离性。

问题二:怎么保证原子性?
先写日志,再改数据。
将所有对数据库的操作,都先通过记录日志的方式保存下来,当发生异常情况时,可以重放日志操作来撤销对数据库的修改。
日志记录完整,但再写数据库时异常,重启后这部分数据重放进入数据库。
日志记录异常,日志都不完整,重放时没有commit标记,不会进入数据库。

问题三:怎么保证一致性?
引入隔离性。

问题四:怎么保证隔离性?
各种锁。
悲观锁:
在一个事务未提交前,禁止另一个事务做修改,这样的话当然保证了独立性,但是性能会差。为了提高性能,引入了各种粒度的锁(数据库表级、行级、库级锁,各种性质的锁:排它锁,死锁问题:两阶段锁

乐观锁:
在比较晚提交的事务当中检测数据是否被修改,如果被修改了,就放弃本次提交。

参考文章:来源知乎

你可能感兴趣的:(数据库)