一个关于DB commit的小问题

一直以来,都认为在开启事务下如果往DB里面进行操作,过程中没有发生异常,commit一定会成功。由此可以推出一个矛盾的结论,如果有一个connect开启事务,增加一条记录,假如这个记录的primary key为name,输入的记录name为joe,未提交,另外一个connect开启事务,增加同一的记录,这个增加的结果会怎么样呢?假如增加成功,则第一个connect开启的事务commit应该会失败,如果不失败则会增加2条具有相同key的记录,违背了数据库的唯一性约束。具体情况是怎么样的呢?

有句话说得好,理论解决不了就实践,实践解决不了再理论,上面的推导肯定有错误的或者有些细节的地方没考虑到。ok,让我先实践吧,实践出真知。</p><p>我首先用toad工具向oracle一张表插入一条记录,但不commit,然后用java程序开启另一个connect往同一张表写相同记录,commit,run代码,一直被block。奇怪难得哪里有死锁,或未唤醒的地方。测试程序都非常简单。先贴出代码,免得大家说我瞎扯。

public class DBTest {
	public static void main(String[] args) {
		String sDBDriver = "com.inet.ora.OraDriver";
		String sConnStr = "jdbc:inetora:10.224.188.10:1522:shcnc2?streamstolob=true";

		Connection conn = null;
		Statement stmt = null;
		try {
			Class.forName(sDBDriver);
			conn = DriverManager.getConnection(sConnStr, "dms2", "pass");
			stmt = conn.createStatement();
			// stmt.executeQuery("create table aaa(aaa int)");
			stmt.executeUpdate("insert into joetesttb values('abce')");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 因此我们总结一下,如果connect相关事务涉及到的记录已经被上锁(即使看不到该记录),将阻塞sql语句的执行,直到记录解锁为止。似乎问题到此为止了,但遇到这样的问题如果不再深入一下,就太浪费了。

事实上我们还不能确定是不是真的是记录上锁了,为了验证这个问题,让我们稍稍修改前面的代码,插入另外一个值,跟另一个未提交事务的值不一样,执行,不再阻塞了。果然和我们猜测一样,确实记录上锁。

让我们把问题再引申一下:既然可以通过这种方式来阻塞跨进程的线程,是否可用提供分布式锁的功能呢?我们知道,在DMS中也用了DB锁,但那种锁的实现是通过轮询,如果db中存在该记录,则挂起当前线程,通过间隔一段时间再尝试,这种锁在遇到高并发高冲突的情况下非常糟糕,锁的敏感度不高。线程可能长期到不到锁。采用DB record锁应该是相对比较好的模式,当然采用DB记录锁来做为分布式锁在salebility方面有很大的约束。如果需要具有高可靠可伸缩的分布式式锁服务,使用我们基于zookeeper实现的分布式锁应该是最佳方案。

突然使我想到在DMS程序调试过程中遇到过一直被阻塞,但通过监控线程没有发现死等或者死锁的情况,始终想不通是什么问题,很有可能是DB锁导致的。

全文总结,啰啰嗦嗦半天来个最终的总结,很多小小的问题,如果我们逐步深入都有很多值得玩味的地方,对于我们程序员来说,需要善于思考推理和实践。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值