一直以来,都认为在开启事务下如果往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锁导致的。
全文总结,啰啰嗦嗦半天来个最终的总结,很多小小的问题,如果我们逐步深入都有很多值得玩味的地方,对于我们程序员来说,需要善于思考推理和实践。
分享到:
相关推荐
在SQLite中,BEGIN命令用于开启一个事务,而COMMIT则用于提交事务。当进行大量数据插入时,一次性提交所有操作比逐条执行插入要快得多。这是因为SQLite在事务内部执行的所有更改都是暂存的,直到COMMIT命令执行才会...
DB2ir,全称DB2 Interactive Repl,是一个命令行工具,允许用户与DB2数据库进行交互式的SQL查询和操作。它类似于其他数据库系统的命令行接口,如MySQL的mysql客户端或PostgreSQL的psql。DB2ir提供了实时反馈,使得...
- `php artisan config:cache`: 缓存配置,将所有配置合并到一个文件中,减少启动时间。 - `php artisan route:clear`: 清除路由缓存,重新加载路由定义。 - `php artisan view:clear`: 清除视图缓存,重新编译...
拷贝commit-msg到每个需要使用gerrit提交代码的项目中 将commit-msg文件拷贝到 -> 项目文件夹\.git\hooks(文件夹不存在则新建), 这时将上次commit的代码reset后再次commit and push -> push to Gerrit即可。 详情...
当应用程序成功连接到数据库时,一个事务即自动启动,并在执行`COMMIT`或`ROLLBACK`语句时结束。下一条SQL语句则开启新的事务。 **1.1.2 开发方法选择** 为了访问和管理DB2数据库,开发者可以选择多种不同的编程...
- `db2 bind <file_path>`:绑定一个函数文件。 **注意事项:** - `<file_path>`应替换为函数文件的完整路径。 - 函数文件通常位于`C:\sqllib\function`目录下。 #### 九、优化表结构 **命令:** - `db2 reorg ...
以下是一个连接示例: ```python import ibm_db # 定义连接字符串 dsn = "DRIVER={IBM DB2 ODBC DRIVER};DATABASE=;HOSTNAME=;PORT=;PROTOCOL=TCPIP;UID=;PWD=<password>" # 连接数据库 conn = ibm_db.connect...
DB4O是一个开源的纯面向对象数据库引擎,对于Java与.NET开发者来说都是一个简单易用的对象持久化工具,使用简单。下面是关于DB4O的详细教程,包括打开数据库、插入记录、查询记录、更新对象和删除对象等操作。 打开...
DB2是一款高性能、企业级的关系型数据库管理系统,广泛应用于金融、电信、航空等领域。 DB2驱动jar包通常包含以下几种类型: 1. **类型1(JDBC-ODBC桥接驱动)**:这是最早的Java数据库连接方式,依赖于本地ODBC...
DB2是一款由IBM开发的关系型数据库管理系统,广泛应用于企业级数据存储和管理。在Java编程环境中,如果要与DB2数据库进行交互,通常需要引入特定的JDBC驱动,也就是DB2的jar包。本资源提供的两个jar包可能包含了DB2...
- **表**:表是数据的基本单元,由列和行组成,每一列代表一个特定的数据类型,每一行代表一条记录。 - **SQL**:结构化查询语言,用于查询、插入、更新和删除数据库中的数据。 2. **DB2 安装与配置** - **安装*...
总结来说,Berkley DB 作为一个内存数据库,因其高效、灵活和易于集成的特性,在许多应用场景中,尤其是在需要高性能、低延迟的数据存储时,是一个理想的解决方案。在JAVA版的Berkley DB中,开发者可以通过简单的API...
DB2是一款由IBM开发的关系型数据库管理系统,广泛应用于企业级数据存储和管理。掌握DB2的实用技巧对于数据库管理员和开发人员来说至关重要。本篇将深入探讨DB2的一些关键特性和实用技巧,帮助你更高效地操作和管理...
掌握这些DB2常用命令,不仅可以提高日常数据库管理的效率,还能帮助在遇到问题时快速定位和解决问题。对于DB2管理员来说,这是一份非常实用的参考资料。通过实践和学习,你可以进一步提升在DB2环境中的操作技能。
在数据库管理中,DB2 是一个非常重要的关系型数据库管理系统,由 IBM 开发。当需要对 DB2 表进行操作,比如清空其中的所有数据时,有几种不同的 SQL 语句可以实现这一目标。以下是对标题和描述中涉及的知识点的详细...
DB2是一款由IBM开发的关系型数据库管理系统,广泛应用于企业级数据存储和管理。"db2 reference" 提到的主要是DB2 V9版本的SQL语句和命令参考,这对于理解和操作DB2数据库至关重要。下面将详细阐述这两个核心领域的...
子查询允许在一个查询中嵌套另一个查询,用于处理复杂的数据筛选。联接操作将两个或更多表中的数据合并,如内连接(INNER JOIN)、外连接(LEFT JOIN、RIGHT JOIN、FULL JOIN)。视图是虚拟的表,基于一个或多个实际...
- **作用**: 将多个SQL语句组合在一起作为一个事务执行。 - **示例**: ```sql BEGIN ATOMIC UPDATE table1 SET column1 = value1 WHERE condition1; INSERT INTO table2 (column1, column2) VALUES (value1, ...