提交 5cbc873e authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 4cde8b24
...@@ -20,6 +20,8 @@ Advanced Topics ...@@ -20,6 +20,8 @@ Advanced Topics
Linked Tables</a><br /> Linked Tables</a><br />
<a href="#transaction_isolation"> <a href="#transaction_isolation">
Transaction Isolation</a><br /> Transaction Isolation</a><br />
<a href="#mvcc">
Multi-Version Concurrency Control (MVCC)</a><br />
<a href="#clustering"> <a href="#clustering">
Clustering / High Availability</a><br /> Clustering / High Availability</a><br />
<a href="#two_phase_commit"> <a href="#two_phase_commit">
...@@ -176,6 +178,26 @@ connection will get a lock timeout exception. The lock timeout can be set indivi ...@@ -176,6 +178,26 @@ connection will get a lock timeout exception. The lock timeout can be set indivi
for each connection. for each connection.
</p> </p>
<br /><a name="mvcc"></a>
<h2>Multi-Version Concurrency Control (MVCC)</h2>
<p>
The MVCC feature allows higher concurrency than using (table level or row level) locks.
When using MVCC in this database, delete, insert and update operations will only issue a
shared lock on the table. Table are still locked exclusively when adding or removing columns,
when dropping the table, and when using SELECT ... FOR UPDATE. Connections
only 'see' committed data, and own changes. That means, if connection A updates
a row but doesn't commit this change yet, connection B will see the old value.
Only when the change is committed, the new value is visible by other connections
(read committed). If multiple connections concurrently try to update the same row, this
database fails fast: a concurrent update exception is thrown.
</p>
<p>
To use the MVCC feature, append MVCC=TRUE to the database URL:
<pre>
jdbc:h2:~/test;MVCC=TRUE
</pre>
</p>
<br /><a name="clustering"></a> <br /><a name="clustering"></a>
<h2>Clustering / High Availability</h2> <h2>Clustering / High Availability</h2>
<p> <p>
......
...@@ -311,20 +311,20 @@ public class TableData extends Table implements RecordReader { ...@@ -311,20 +311,20 @@ public class TableData extends Table implements RecordReader {
return; return;
} }
long max = System.currentTimeMillis() + session.getLockTimeout(); long max = System.currentTimeMillis() + session.getLockTimeout();
synchronized (database) {
while (true) {
if (lockExclusive == session) {
return;
}
if (!force && database.isMultiVersion()) { if (!force && database.isMultiVersion()) {
// MVCC: update, delete, and insert use a shared lock // MVCC: update, delete, and insert use a shared lock
// but select doesn't lock // select doesn't lock
if (exclusive) { if (exclusive) {
exclusive = false; exclusive = false;
} else { } else {
return; return;
} }
} }
synchronized (database) {
while (true) {
if (lockExclusive == session) {
return;
}
if (exclusive) { if (exclusive) {
if (lockExclusive == null) { if (lockExclusive == null) {
if (lockShared.isEmpty()) { if (lockShared.isEmpty()) {
......
...@@ -142,15 +142,6 @@ java org.h2.test.TestAll timer ...@@ -142,15 +142,6 @@ java org.h2.test.TestAll timer
/* /*
TODO history:
Math operations using unknown data types (for example -? and ?+?) are now interpreted as decimal.
INSTR, LOCATE: backward searching is not supported by using a negative start position
TODO doc:
MVCC still locks the table exclusively when adding or removing columns and when dropping the table.
Also, a shared lock is still added when inserting or removing rows.
replicating file system replicating file system
background thread writing file system (all writes) background thread writing file system (all writes)
......
...@@ -40,13 +40,14 @@ public class TestMVCC extends TestBase { ...@@ -40,13 +40,14 @@ public class TestMVCC extends TestBase {
DeleteDbFiles.execute(null, "test", true); DeleteDbFiles.execute(null, "test", true);
Class.forName("org.h2.Driver"); Class.forName("org.h2.Driver");
c1 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE", "sa", "sa"); c1 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE;LOCK_TIMEOUT=10", "sa", "sa");
s1 = c1.createStatement(); s1 = c1.createStatement();
c2 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE", "sa", "sa"); c2 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE;LOCK_TIMEOUT=10", "sa", "sa");
s2 = c2.createStatement(); s2 = c2.createStatement();
c1.setAutoCommit(false); c1.setAutoCommit(false);
c2.setAutoCommit(false); c2.setAutoCommit(false);
// it should not be possible to drop a table when an uncommitted transaction changed something
s1.execute("create table test(id int primary key)"); s1.execute("create table test(id int primary key)");
s1.execute("insert into test values(1)"); s1.execute("insert into test values(1)");
try { try {
...@@ -60,6 +61,23 @@ public class TestMVCC extends TestBase { ...@@ -60,6 +61,23 @@ public class TestMVCC extends TestBase {
s2.execute("drop table test"); s2.execute("drop table test");
c2.rollback(); c2.rollback();
// select for update should do an exclusive lock, even with mvcc
s1.execute("create table test(id int primary key, name varchar(255))");
s1.execute("insert into test values(1, 'y')");
c1.commit();
s2.execute("select * from test for update");
try {
s1.execute("insert into test values(2, 'x')");
error("Unexpected success");
} catch (SQLException e) {
// lock timeout expected
checkNotGeneralException(e);
}
c2.rollback();
s1.execute("drop table test");
c1.commit();
c2.commit();
s1.execute("create table test(id int primary key, name varchar(255))"); s1.execute("create table test(id int primary key, name varchar(255))");
s2.execute("insert into test values(4, 'Hello')"); s2.execute("insert into test values(4, 'Hello')");
c2.rollback(); c2.rollback();
......
select instr('asgisj','s', -1) from dual; select instr('abcisj','s', -1) from dual;
> 5; > 5;
CREATE TABLE TEST(ID INT); CREATE TABLE TEST(ID INT);
INSERT INTO TEST VALUES(1), (2), (3); INSERT INTO TEST VALUES(1), (2), (3);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论