一直以来,都认为在开启事务下如果往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数据库命令
当更新SVN时,出现Failed to run the WC DB work queue
RocksDB的Transaction分为两类:Pessimistic和Optimistic,类似悲观锁和乐观锁的区别,PessimisticTransaction的冲突检测和加锁是在事务中每次写操作之前做的(commit后释放),如果失败则该操作失败;...
利用输出的资料,建立一个一模一样的数据库(加上以上指令,就是标准的SQL数据库备份了): sqlite3 film.db 在大量插入资料时,你可能会需要先打这个指令: begin; 插入完资料后要记得打这个指令,资料才会写进...
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语句 经典SQL语句集锦 SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT) DCL—数据控制语言(GRANT,REVOKE,COMMIT,ROLLBACK)
一个钩子,用于根据检查您的Python依赖。 它会在存储库中检查所有名称中包含requirements文件。 发布详细信息: 用法 - repo: https://github.com/Lucas-C/pre-commit-hooks-safety rev: v1.2.1 hooks: - id:...
require ( 'assert' )var db = new Pouch ( 'testdb' , { db : require ( 'memdown' ) } )CommitLog ( db , 'a' )db1 . append ( 'letters' , { name : 'a' } ) . then ( function ( ) { return db1 . append ( '...
实际完整的例子,通过测试的 DROP PROCEDURE "GetCommentByOrderID" @ CREATE PROCEDURE "PLName"(--存储过程名字 IN orders_ID BIGINT, OUT Comments VARCHAR(254) ) BEGIN declare TEMP VARCHAR(254...commit; END @
每次编写提交时,您的终端上都会显示一个可爱的色板。 十六进制颜色来自提交ID中的前六个字符。 看起来是这样的: 有关此项目的现场演示和背景知识,请。 提交颜色是用Go编写的,并且可以在Mac,Windows和Linux上...
这是一个很小的库,用于生成文件名。 它会根据当前的git commit以及时间和日期为您提供唯一的文件名。 从终端调用fn ,文件名如下所示: 20190126-142138-244db3e-5f3a90f9 20190126-142155-244db3e-42464759 ...
在学完本教程之后,您应该能够: • 了解 SQL 的基本知识,特别是 SQL 语言的元素 ...• 使用 COMMIT 和 ROLLBACK 语句管理事务,知道是什么组成了事务边界 • 从命令行创建并调用 SQL 过程和用户定义函数
为您的新Create repository from template一个名称,然后按绿色的“ Create repository from template按钮 将新创建的存储库克隆到计算机 4。 根据 ,将db.json的内容更改为您自己的内容,然后commit db.json的更改...
解决方案: 首先,打开隐藏的文件夹,会发现 .svn 文件夹,打开之后会发现有个wc.db的文件 使用sqlLitManager 打开,会看到如下所示内容 ,选择sql视图 在里面输入 delete from wc_lock where 1=1 ,然后执行 之后...
(7)Auto Commit:是否自动提交,自动commit 3、驱动(Driver)选择DB2之后,自动出现三个新的内容: (1)Database Server:数据库的地址,IP (2)Database Port:数据库端口 (3)Database:数据名称 4、然后...
capistrano-db-镜像 从远程... 如果要回滚数据库, $ rake db:mirror:rollback要求卡皮斯特拉诺 3 转储贡献分叉吧创建您的功能分支( git checkout -b my-new-feature ) 提交您的更改( git commit -am 'Add some f
gem 'db-mariadb'然后执行: $ bundle或将其自己安装为: $ gem install db-mariadb用法贡献叉它创建功能分支( git checkout -b my-new-feature ) 提交更改( git commit -am 'Add some feature' ) 推送到分支...
用c++实现的mysql 访问 /* * test.cpp * * Created on: 2011-3-19 * Author: root * table: * create table users ( ... db.commit(); else db.rollback(); db.close(); return 0; }
这些扩展方法具有与IDbClient中的方法很类似的签名,但能够接收一个用于存放参数信息的.net对象,以节省许多编码量(是的,和Dapper、ServiceStack.OrmLite很相似)。 通过这些扩展方法,上面使用参数的示例可以...
github-commit-crawler Github使用Node.js,Slack API,Kakaowork Bot API提交抓取工具前端功能每小时都会读取与Slack链接的GitHub的提交历史记录,并将其存储在Postgresql中。 提供用于提交记录的REST API 成员的...