`
b_l_east
  • 浏览: 639350 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Oracle和Mysql中的数据库事务问题:Mysql Read-Repeatable有问题

 
阅读更多

今天不知不觉想到数据库的乐观锁和悲观锁,遂想写个程序测测,却发现了另一个问题,Mysql InnoDB的Read-Repeatable事务级别使用不当会存在数据一致性问题。

 

如下的测试程序:

 

 

public class OptimisticAndPessimisticLockTest2 {

	public static void main(String[] args) throws Exception {
		//创建测试表和数据
		initDatabase();
		
		//创建两个线程同时操作同一条记录
		OptimisticThread ot1 = new OptimisticThread(newConnection(), "O1");
		OptimisticThread ot2 = new OptimisticThread(newConnection(), "O2");
		
		ot1.start();
		ot2.start();
	}
	
	public static Connection newConnection() throws Exception {
		Class.forName("com.mysql.jdbc.Driver");
		Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
		return con;
	}
	
	public static void initDatabase() throws Exception {
		Connection con = newConnection();
		Statement stmt = con.createStatement();
		stmt.execute("drop table if exists locktest");
		stmt.execute("create table locktest( name varchar(10)) ENGINE=InnoDB");
		stmt.executeUpdate("insert into locktest values('XJD')");
		con.close();
	}
	
	public static class OptimisticThread extends Thread {
		Connection con;
		String name;
		
		public OptimisticThread(Connection con, String name) {
			this.con = con;
			this.name = name;
		}
		
		@Override
		public void run() {
			try {
				//设置事务级别为可重复读
				this.con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
				this.con.setAutoCommit(false); //开始事务
				System.out.println("Started Transaction...: " + name);
				
				Statement stmt = this.con.createStatement();
				
				//先查询一下是否有'XJD'的记录
				ResultSet rs = stmt.executeQuery("select * from locktest where name='XJD'");
				if (rs.next()) {
					System.out.println("Got Record: " + name + " value: " + rs.getString(1));
				}
				rs.close();
				
				Thread.sleep(5000);//暂停5s让另一个线程也查询完成
				
				//更新'XJD'的记录
				int i = stmt.executeUpdate("update locktest set name = '" + name + "' where name = 'XJD'");
				System.out.println("Update Record: " + name + " count: " + i);//更新成功后i为1
				
				Thread.sleep(5000);//暂停5s让另一个线程也作更新操作
				
				//查询更新后的记录
				rs = stmt.executeQuery("select * from locktest where name='" + name + "'");
				if (rs.next()) {
					System.out.println("Got Record: " + name + " value: " + rs.getString(1));
				}
				rs.close();
				//查询原来的记录
				rs = stmt.executeQuery("select * from locktest where name='XJD'");
				if (rs.next()) {
					System.out.println("Got Record: " + name + " value: " + rs.getString(1));
				}
				rs.close();
				
				Thread.sleep(10000);
				
				System.out.println("Commiting Transaction...: " + name);
				this.con.commit();
				this.con.close();
				
			} catch (SQLException e) {
				System.out.println("Exception in " + name + ": " + e);
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
		
	}

}

 

输出结果:

 

 

Started Transaction...: O1
Got Record: O1 value: XJD
Started Transaction...: O2
Got Record: O2 value: XJD
Update Record: O1 count: 1
Got Record: O1 value: O1
Commiting Transaction...: O1
Update Record: O2 count: 0    //见下一行的说明
Got Record: O2 value: XJD       //此处在O2线程中还可以查询到XJD记录,但前一条的Update结果却是0
Commiting Transaction...: O2
 

从输出结果中注释的两行可以看出,Read-Repeatable事务级别容易出现问题:

  O1和O2两个线程都开启了事务--O1和O2中都可以查询到XJD的记录--O1更新并提交了XJD记录为'O1'--O2中Update语句返回0可知O2没有更新到‘XJD'的记录--但是O2中仍可使用查询语句查询到‘XJD'的记录(因为可重得读事务设置)--但此时问题就来了,我在O2中可查询到记录,为什么更新不到呢????

 

从上面的分析,可以看出,Read-Repeatable事务级别容易出现业务上的问题,比如我们在一个事务中查询到一条记录,而后我们对该记录进行操作,发现这些操作跟本不起作用,如果业务比较复杂,跨度大,很容易使我们“迷惑“,我们错在哪,为什么查询到了,却更新不到!!!

 

难怪Oracle不支持Read-Repeatable事务,在对Oracle执行:

 

 

con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);

 抛出异常:

 

 

java.sql.SQLException: 仅 READ_COMMITTED 和 SERIALIZABLE 是有效的事务处理级
 

我使用的是Mysql默认安装,发现Mysql Innodb默认使用的就是Read-Repeatable事务,所以只能说要谨慎吧!

 

 

再则对于乐观锁,可能使用版本列、时间戳列、其它列数据对比,无论是何种方式,都要在提交前先查询一次,与之前查询的数据进行某些列的对比,如果使用了Read-Repeatable事务,那么对比永远是相同的,这样乐观锁就出现问题了,不是我们想要的结果,所以在使用乐观锁时不能使用Read-Repeatable事务,而应该使用Read-Commited事务。

 

以上为个人见解,本人对数据库事使用不是很多,有问题之处望高人指点赐教!!!

 

此处附上一处乐观与悲观锁的文章:http://www.zhujiangroad.com/program/Oracle/21775.html

 

 

分享到:
评论

相关推荐

    MySQL数据库相关课件PPT

    隔离级别包括读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)。并发控制通过锁定机制实现,包括行锁、表锁等。 十、存储引擎 MySQL支持多种存储...

    MySQL数据库面试宝典1.pdf

    - **InnoDB**:支持多种索引类型,包括B树和哈希索引,支持事务和行级锁定。 **3.4 InnoDB引擎的4大特性** - **事务支持**:确保数据的一致性和完整性。 - **行级锁定**:允许更高的并发访问。 - **外键支持**:...

    oracle转mysql.rar

    在事务控制上,Oracle提供了更高级别的隔离级别,如序列化(SERIALIZABLE),而在MySQL中,默认隔离级别是可重复读(REPEATABLE READ)。此外,Oracle的保存点(SAVEPOINT)在MySQL中也有相应的实现,但语法有所不同...

    MySQL初级与高级教程

    ### MySQL初级与高级教程知识点概览 #### 一、MySQL基础知识 1. **数据库系统概述** ...通过以上知识点的学习,读者可以系统地掌握MySQL从基础到高级的各种技能,为实际项目中的数据库设计与管理打下坚实的基础。

    KFC系列之 - Oracle DBA入门Mysql(中)

    - **tx_isolation**:用于设置当前会话的隔离级别,可以设置为`READ-UNCOMMITTED`、`READ-COMMITTED`、`REPEATABLE-READ`或`SERIALIZABLE`。 - **innodb_lock_wait_timeout**:设置在等待锁时的超时时间,单位为秒。...

    mysql-connector-java-5.1.6-bin.jar

    3. **事务支持**:支持JDBC的事务处理,包括读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)等隔离级别。 4. **结果集处理**:提供了处理查询结果的方法,可以将结果集转换为Java对象,如`ResultSet`。 ...

    mysql面试题,MySQL是一种关系型数据库管理系统,由Oracle公司开发

    答:MySQL是一种关系型数据库管理系统,由Oracle公司开发。 2. MySQL的安装有哪些方式? 答:本地安装、虚拟机安装、云服务安装(阿里云RDS、腾讯云CDB等) 3. MySQL的数据类型有哪些? 答:数值型(整数、小数)、日期型、...

    JDBC驱动包(oracle和mysql).zip_jdbc_oracle_piecedze

    此外,数据库事务管理也是关键点,JDBC提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)。选择合适的事务隔离级别有助于...

    MySQL面试题(含答案).pdf

    MySQL是一种流行的开源关系型数据库管理系统,以其高效、稳定和易用...以上是MySQL面试中常见的知识点,涵盖数据库特性、表类型、数据类型、事务处理、存储引擎等多个方面,这些知识对理解和操作MySQL数据库至关重要。

    mysql和oracle的区别

    **MySQL**默认只支持“提交读”(Read Committed)隔离级别,这意味着在一个事务中读取的数据只反映了其他事务提交后的状态。这意味着在MySQL中,如果一个会话正在更新数据,其他会话将无法访问这部分数据,但可以在...

    数据库事务及锁机制面试题

    事务是数据库系统中一组操作的集合,用于确保数据的一致性和完整性。在事务处理中,事务被视为一个不可分割的工作单元,其中包含的操作要么全部成功,要么全部失败。事务具有四大特性,即ACID特性: 1. **原子性...

    mysql-connector-java-5.1.12.rar 源代码

    MySQL Connector/J 5.1.12 是 MySQL 官方提供的用于 Java 应用程序连接 MySQL 数据库的驱动程序。这个源代码版本包含了用于与 ...同时,源代码也是学习 JDBC 和数据库连接管理的好材料,有助于提升数据库编程技能。

    数据库面试必备!mysql 面试 55题

    - **Repeatable Read**:除了上述限制外,还禁止幻读现象,即在同一事务中两次相同的查询可能会有不同的结果。 - **Serializable**:最高级别的隔离,确保所有事务依次执行,不会出现并发问题。 #### 九、ENUM ...

    数据库市场产品特性及适用场景.pptx

    - **事务**:确保数据操作的完整性和一致性,包括四种隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。 - **并发控制**:通过锁机制解决事务间的冲突,防止脏读、不可重复读和幻读等...

    09-MySQL数据库面试题-重点.docx

    事务的隔离级别有 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE 等。 五、锁 锁是指数据库管理系统中用来控制并发访问的机制。锁有很多种类型,如行锁、表锁、页锁等。锁的粒度有行级锁、页...

    mysql常见⾯试题,可以看看了解下

    MySQL是世界上最流行的关系型数据库管理系统之一,广泛应用于各种规模的应用中。以下是一些关于MySQL的常见面试题,以及相关的知识点: 1. 登录MySQL数据库:使用命令`mysql -u username -p`,其中`username`是你的...

    MySQL55题答案.pdf

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,尤其在Web应用程序中广泛应用。以下是一些关于MySQL的知识点,基于题目中提到的PDF文件可能包含的内容: 1. **自增主键的分配**: - 当删除MyISAM表的记录并...

    数据库面试题--值得一看

    - 事务的隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)、串行化(SERIALIZABLE)。 - 锁机制:行级锁、表级锁、页级锁,以及乐观锁和悲观锁的比较。 5. **...

    数据库相关文档

    数据库是信息技术中的核心组成部分,主要用于存储、管理、检索和共享数据。它是一个有组织的数据集合,支持高效的数据操作和管理,使得数据之间的关联和逻辑结构得以清晰体现。本压缩包文件"数据库相关文档"可能包含...

    数据库事务隔离级别.docx

    ### 数据库事务隔离级别详解 ...例如,MySQL默认使用Repeatable Read作为隔离级别,而Oracle则默认使用Read Committed。每种隔离级别都有其适用场景,合理设置可以帮助开发者更好地管理数据的一致性和系统的性能。

Global site tag (gtag.js) - Google Analytics