`
zoutm
  • 浏览: 95478 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

一个关于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锁导致的。

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

分享到:
评论

相关推荐

    Laravel开发-laravel-db-commands

    Laravel开发-laravel-db-commands Laravel数据库命令

    SVN时,出现Failed to run the WC DB work queue的解决办法

    当更新SVN时,出现Failed to run the WC DB work queue

    【RocksDB】TransactionDB源码分析.docx

    RocksDB的Transaction分为两类:Pessimistic和Optimistic,类似悲观锁和乐观锁的区别,PessimisticTransaction的冲突检测和加锁是在事务中每次写操作之前做的(commit后释放),如果失败则该操作失败;...

    sqlite3含命令大全

    利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了): sqlite3 film.db 在大量插入资料时,你可能会需要先打这个指令: begin; 插入完资料后要记得打这个指令,资料才会写进...

    Design and Architecture of CockroachDb

    The map is composed of one or more ranges and each range is backed by data stored in RocksDB (a variant of leveldb), and is replicated to a total of three or more cockroach servers. Ranges are ...

    DB2中常用的SQL语句

    DB2中常用的SQL语句 经典SQL语句集锦 SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT) DCL—数据控制语言(GRANT,REVOKE,COMMIT,ROLLBACK)

    pre-commit-hooks-safety:预先提交的钩子,用于根据safety-db检查您的Python依赖项

    一个钩子,用于根据检查您的Python依赖。 它会在存储库中检查所有名称中包含requirements文件。 发布详细信息: 用法 - repo: https://github.com/Lucas-C/pre-commit-hooks-safety rev: v1.2.1 hooks: - id:...

    pouchdb-commit-log

    require ( 'assert' )var db = new Pouch ( 'testdb' , { db : require ( 'memdown' ) } )CommitLog ( db , 'a' )db1 . append ( 'letters' , { name : 'a' } ) . then ( function ( ) { return db1 . append ( '...

    在db2数据库写存储过程

    实际完整的例子,通过测试的 DROP PROCEDURE "GetCommentByOrderID" @ CREATE PROCEDURE "PLName"(--存储过程名字 IN orders_ID BIGINT, OUT Comments VARCHAR(254) ) BEGIN declare TEMP VARCHAR(254...commit; END @

    commit-colors:every每次编写提交时,都会在终端中看到一个可爱的色板

    每次编写提交时,您的终端上都会显示一个可爱的色板。 十六进制颜色来自提交ID中的前六个字符。 看起来是这样的: 有关此项目的现场演示和背景知识,请。 提交颜色是用Go编写的,并且可以在Mac,Windows和Linux上...

    fn:python库,用于基于当前时间和git commit生成文件名

    这是一个很小的库,用于生成文件名。 它会根据当前的git commit以及时间和日期为您提供唯一的文件名。 从终端调用fn ,文件名如下所示: 20190126-142138-244db3e-5f3a90f9 20190126-142155-244db3e-42464759 ...

    DB2 9 基础(730 考试)认证指南,第 4 部分

    在学完本教程之后,您应该能够: • 了解 SQL 的基本知识,特别是 SQL 语言的元素 ...• 使用 COMMIT 和 ROLLBACK 语句管理事务,知道是什么组成了事务边界 • 从命令行创建并调用 SQL 过程和用户定义函数

    call-center-db

    为您的新Create repository from template一个名称,然后按绿色的“ Create repository from template按钮 将新创建的存储库克隆到计算机 4。 根据 ,将db.json的内容更改为您自己的内容,然后commit db.json的更改...

    sqlLiteManager

    解决方案: 首先,打开隐藏的文件夹,会发现 .svn 文件夹,打开之后会发现有个wc.db的文件 使用sqlLitManager 打开,会看到如下所示内容 ,选择sql视图 在里面输入 delete from wc_lock where 1=1 ,然后执行 之后...

    DbVisualizer-8.0.9.rar

    (7)Auto Commit:是否自动提交,自动commit 3、驱动(Driver)选择DB2之后,自动出现三个新的内容: (1)Database Server:数据库的地址,IP (2)Database Port:数据库端口 (3)Database:数据名称 4、然后...

    capistrano-db-mirror:从远程镜像数据库

    capistrano-db-镜像 从远程... 如果要回滚数据库, $ rake db:mirror:rollback要求卡皮斯特拉诺 3 转储贡献分叉吧创建您的功能分支( git checkout -b my-new-feature ) 提交您的更改( git commit -am 'Add some f

    db-mariadb

    gem 'db-mariadb'然后执行: $ bundle或将其自己安装为: $ gem install db-mariadb用法贡献叉它创建功能分支( git checkout -b my-new-feature ) 提交更改( git commit -am 'Add some feature' ) 推送到分支...

    mysql C++ API 实现

    用c++实现的mysql 访问 /* * test.cpp * * Created on: 2011-3-19 * Author: root * table: * create table users ( ... db.commit(); else db.rollback(); db.close(); return 0; }

    简单的ADO.net数据访问客户端

    这些扩展方法具有与IDbClient中的方法很类似的签名,但能够接收一个用于存放参数信息的.net对象,以节省许多编码量(是的,和Dapper、ServiceStack.OrmLite很相似)。 通过这些扩展方法,上面使用参数的示例可以...

    github-commit-crawler:Github使用Node.js,Slack API,Kakao work Bot API提交搜寻器

    github-commit-crawler Github使用Node.js,Slack API,Kakaowork Bot API提交抓取工具前端功能每小时都会读取与Slack链接的GitHub的提交历史记录,并将其存储在Postgresql中。 提供用于提交记录的REST API 成员的...

Global site tag (gtag.js) - Google Analytics