提交 81c34acc authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 9030e8e7
......@@ -54,22 +54,27 @@ Advanced Topics
<h2>Result Sets</h2>
<h3>Limiting the Number of Rows</h3>
<p>
Before the result is returned to the application, all rows are read by the database.
Server side cursors are not supported currently.
If only the first few rows are interesting for the application, then the
result set size should be limited to improve the performance.
This can be done using LIMIT in a query (example: SELECT * FROM TEST LIMIT 100),
or by using Statement.setMaxRows(max).
</p>
<h3>Large Result Sets and External Sorting</h3>
<p>
For result set larger than 1000 rows, the result is buffered to disk. If ORDER BY is used,
the sorting is done using an external sort algorithm. In this case, each block of rows is sorted using
quick sort, then written to disk; when reading the data, the blocks are merged together.
</p>
<br /><a name="large_objects"></a>
<h2>Large Objects</h2>
<h3>Storing and Reading Large Objects</h3>
<p>
If it is possible that the objects don't fit into memory, then the data type
CLOB (for textual data) or BLOB (for binary data) should be used.
For these data types, the objects are not fully read into memory, by using streams.
......@@ -78,26 +83,29 @@ PreparedStatement.setCharacterStream. To read a BLOB, use ResultSet.getBinaryStr
and to read a CLOB, use ResultSet.getCharacterStream.
If the client/server mode is used, the BLOB and CLOB data is fully read into memory when
accessed. In this case, the size of a BLOB or CLOB is limited by the memory.
</p>
<br /><a name="linked_tables"></a>
<h2>Linked Tables</h2>
<p>
This database supports linked tables, which means tables that don't exist in the current database but
are just links to another database. To create such a link, use the CREATE LINKED TABLE statement:
</p>
<pre>
CREATE LINKED TABLE LINK('org.postgresql.Driver', 'jdbc:postgresql:test', 'sa', 'sa', 'TEST');
</pre>
<p>
It is then possible to access the table in the usual way.
There is a restriction when inserting data to this table: When inserting or updating rows into the table,
NULL and values that are not set in the insert statement are both inserted as NULL.
This may not have the desired effect if a default value in the target table is other than NULL.
</p>
<br /><a name="transaction_isolation"></a>
<h2>Transaction Isolation</h2>
<p>
This database supports the following transaction isolation levels:
</p>
<ul>
<li><b>Serializable</b><br />
This is the default level.<br />
......@@ -115,11 +123,9 @@ This database supports the following transaction isolation levels:
or append ;LOCK_MODE=0 to the database URL: jdbc:h2:~/test;LOCK_MODE=0
</li>
</ul>
<p>
When using the isolation level 'serializable', dirty reads, non-repeatable reads, and phantom reads are prohibited.
</p>
<ul>
<li><b>Dirty Reads</b><br />
Means a connection can read uncommitted changes made by another connection.<br />
......@@ -137,6 +143,7 @@ When using the isolation level 'serializable', dirty reads, non-repeatable reads
</ul>
<h3>Table Level Locking</h3>
<p>
The database allows multiple concurrent connections to the same database.
To make sure all connections only see consistent data, table level locking is used.
This mechanism does not allow high concurrency, but is very fast.
......@@ -149,14 +156,17 @@ to write to a table (update or delete a row), an exclusive lock is required. To
exclusive lock, other connection must not have any locks on the object. After the
connection commits, all locks are released.
This database keeps all locks in memory.
</p>
<h3>Lock Timeout</h3>
<p>
If a connection cannot get a lock on an object, the connection waits for some amount
of time (the lock timeout). During this time, hopefully the connection holding the
lock commits and it is then possible to get the lock. If this is not possible because
the other connection does not release the lock for some time, the unsuccessful
connection will get a lock timeout exception. The lock timeout can be set individually
for each connection.
</p>
<br /><a name="clustering"></a>
<h2>Clustering / High Availability</h2>
......@@ -167,6 +177,7 @@ same database. If both servers run, each database operation is executed on both
If one server fails (power, hardware or network failure), the other server can still continue to work.
From this point on, the operations will be executed only on one server until the other server
is back up.
</p><p>
Clustering can only be used in the server mode (the embedded mode does not support clustering).
It is possible to restore the cluster without stopping the server, however it is critical that no other
application is changing the data in the first database while the second database is restored, so
......@@ -183,9 +194,11 @@ To initialize the cluster, use the following steps:
</li></ul>
<h3>Using the CreateCluster Tool</h3>
<p>
To understand how clustering works, please try out the following example.
In this example, the two databases reside on the same computer, but usually, the
databases will be on different servers.
</p>
<ul>
<li>Create two directories: server1 and server2.
Each directory will simulate a directory on a computer.
......@@ -226,6 +239,7 @@ and re-run the CreateCluster tool.
</li></ul>
<h3>Clustering Algorithm and Limitations</h3>
<p>
Read-only queries are only executed against the first cluster node, but all other statements are
executed against all nodes. There is currently no load balancing made to avoid problems with
transactions. The following functions may yield different results on different cluster nodes and must be
......@@ -233,10 +247,13 @@ executed with care: RANDOM_UUID(), SECURE_RAND(), SESSION_ID(), MEMORY_FREE(), M
CSVREAD(), CSVWRITE(), RAND() [when not using a seed]. Those functions should not be used
directly in modifying statements (for example INSERT, UPDATE, or MERGE). However, they can be used
in read-only statements and the result can then be used for modifying statements.
</p>
<br /><a name="two_phase_commit"></a>
<h2>Two Phase Commit</h2>
<p>
The two phase commit protocol is supported. 2-phase-commit works as follows:
</p>
<ul>
<li>Autocommit needs to be switched off
</li><li>A transaction is started, for example by inserting a row
......@@ -255,14 +272,17 @@ The two phase commit protocol is supported. 2-phase-commit works as follows:
<br /><a name="compatibility"></a>
<h2>Compatibility</h2>
<p>
This database is (up to a certain point) compatible to other databases such as HSQLDB, MySQL and PostgreSQL.
There are certain areas where H2 is incompatible.
</p>
<h3>Transaction Commit when Autocommit is On</h3>
<p>
At this time, this database engine commits a transaction (if autocommit is switched on) just before returning the result.
For a query, this means the transaction is committed even before the application scans through the result set, and before the result set is closed.
Other database engines may commit the transaction in this case when the result set is closed.
</p>
<h3>Keywords / Reserved Words</h3>
<p>
......@@ -279,43 +299,57 @@ for example CURRENT_TIMESTAMP.
<br /><a name="windows_service"></a>
<h2>Run as Windows Service</h2>
<p>
Using a native wrapper / adapter, Java applications can be run as a Windows Service.
There are various tools available to do that. The Java Service Wrapper from Tanuki Software, Inc.
(<a href="http://wrapper.tanukisoftware.org">http://wrapper.tanukisoftware.org</a>)
is included in the installation. Batch files are provided to install, start, stop and uninstall the H2 Database Engine Service.
This service contains the TCP Server and the H2 Console web application.
The batch files are located in the directory H2/service.
</p>
<h3>Install the Service</h3>
<p>
The service needs to be registered as a Windows Service first.
To do that, double click on 1_install_service.bat.
If successful, a command prompt window will pop up and disappear immediately. If not, a message will appear.
</p>
<h3>Start the Service</h3>
<p>
You can start the H2 Database Engine Service using the service manager of Windows,
or by double clicking on 2_start_service.bat.
Please note that the batch file does not print an error message if the service is not installed.
</p>
<h3>Connect to the H2 Console</h3>
<p>
After installing and starting the service, you can connect to the H2 Console application using a browser.
Double clicking on 3_start_browser.bat to do that. The
default port (8082) is hard coded in the batch file.
</p>
<h3>Stop the Service</h3>
<p>
To stop the service, double click on 4_stop_service.bat.
Please note that the batch file does not print an error message if the service is not installed or started.
</p>
<h3>Uninstall the Service</h3>
<p>
To uninstall the service, double click on 5_uninstall_service.bat.
If successful, a command prompt window will pop up and disappear immediately. If not, a message will appear.
</p>
<br /><a name="odbc_driver"></a>
<h2>ODBC Driver</h2>
<p>
This database does not come with its own ODBC driver at this time,
but it supports the PostgreSQL network protocol.
Therefore, the PostgreSQL ODBC driver can be used.
Support for the PostgreSQL network protocol is quite new and should be viewed
as experimental. It should not be used for production applications.
</p>
<h3>ODBC Installation</h3>
<p>
......@@ -385,15 +419,19 @@ Currently, statements can not be cancelled when using the PG protocol.
</p>
<h3>Security Considerations</h3>
<p>
Currently, the PG Server does not support challenge response or encrypt passwords.
This may be a problem if an attacker can listen to the data transferred between the ODBC driver
and the server, because the password is readable to the attacker.
Also, it is currently not possible to use encrypted SSL connections.
Therefore the ODBC driver should not be used where security is important.
</p>
<br /><a name="acid"></a>
<h2>ACID</h2>
<p>
In the database world, ACID stands for:
</p>
<ul>
<li>Atomicity: Transactions must be atomic, meaning either all tasks are performed or none.
</li><li>Consistency: All operations must comply with the defined constraints.
......@@ -402,24 +440,32 @@ In the database world, ACID stands for:
</li></ul>
<h3>Atomicity</h3>
<p>
Transactions in this database are always atomic.
</p>
<h3>Consistency</h3>
<p>
This database is always in a consistent state.
Referential integrity rules are always enforced.
</p>
<h3>Isolation</h3>
<p>
For H2, the default isolation level is 'serializable', which means complete isolation.
The default transaction isolation level for many other databases is 'read committed'.
This provides better performance, but also means that transactions are not completely isolated.
H2 supports the transaction isolation levels 'serializable', 'read committed', and 'read uncommitted'.
</p>
<h3>Durability</h3>
<p>
This database does not guarantee that all committed transactions survive a power failure.
Tests show that all databases sometimes lose transactions on power failure (for details, see below).
Where losing transactions is not acceptable, a laptop or UPS (uninterruptible power supply) should be used.
If durability is required for all possible cases of hardware failure, clustering should be used,
such as the H2 clustering mode.
</p>
<br /><a name="durability_problems"></a>
<h2>Durability Problems</h2>
......@@ -488,6 +534,7 @@ In the performance comparison, commit delay was used for all databases that supp
</p>
<h3>Running the Durability Test</h3>
<p>
To test the durability / non-durability of this and other databases, you can use the test application
in the package org.h2.test.poweroff. Two computers with network connection are required to run this test.
One computer just listens, while the test application is run (and power is cut) on the other computer.
......@@ -499,9 +546,11 @@ The listener computer displays the last inserted record number every 10 seconds.
manually, then restart the computer, and run the application again. You will find out that in most cases,
none of the databases contains all the records that the listener computer knows about. For details, please
consult the source code of the listener and test application.
</p>
<br /><a name="using_recover_tool"></a>
<h2>Using the Recover Tool</h2>
<p>
The recover tool can be used to extract the contents of a data file, even if the database is corrupted.
At this time, it does not extract the content of the log file or large objects (CLOB or BLOB).
To run the tool, type on the command line:
......@@ -512,6 +561,7 @@ For each database in the current directory, a text file will be created.
This file contains raw insert statement (for the data) and data definition (DDL) statement to recreate
the schema of the database. This file cannot be executed directly, as the raw insert statements
don't have the correct table names, so the file needs to be pre-processed manually before executing.
</p>
<br /><a name="file_locking_protocols"></a>
<h2>File Locking Protocols</h2>
......@@ -531,7 +581,9 @@ The two methods are 'file method' and 'socket methods'.
</p>
<h3>File Locking Method 'File'</h3>
<p>
The default method for database file locking is the 'File Method'. The algorithm is:
</p>
<ul>
<li>When the lock file does not exist, it is created (using the atomic operation File.createNewFile).
Then, the process waits a little bit (20ms) and checks the file again. If the file was changed
......@@ -568,8 +620,10 @@ to the user if it cannot open a database, and not try again in a (fast) loop.
</p>
<h3>File Locking Method 'Socket'</h3>
<p>
There is a second locking mechanism implemented, but disabled by default.
The algorithm is:
</p>
<ul>
<li>If the lock file does not exist, it is created.
Then a server socket is opened on a defined port, and kept open.
......@@ -583,14 +637,17 @@ and this process throws an exception (database is in use). If the original proce
died (for example due to a blackout, or abnormal termination of the virtual machine),
then the port was released. The new process deletes the lock file and starts again.
</li></ul>
<p>
This method does not require a watchdog thread actively polling (reading) the same
file every second. The problem with this method is, if the file is stored on a network
share, two processes (running on different computers) could still open the same
database files, if they do not have a direct TCP/IP connection.
<p>
<br /><a name="sql_injection"></a>
<h2>Protection against SQL Injection</h2>
<h3>What is SQL Injection</h3>
<p>
This database engine provides a solution for the security vulnerability known as 'SQL Injection'.
Here is a short description of what SQL injection means.
Some applications build SQL statements with embedded user input such as:
......@@ -606,8 +663,10 @@ SELECT * FROM USERS WHERE PASSWORD='' OR ''='';
</pre>
Which is always true no matter what the password stored in the database is.
For more information about SQL Injection, see Glossary and Links.
</p>
<h3>Disabling Literals</h3>
<p>
SQL Injection is not possible if user input is not directly embedded in SQL statements.
A simple solution for the problem above is to use a PreparedStatement:
<pre>
......@@ -630,8 +689,10 @@ do not include literals.
There is also a second mode where number literals are allowed: SET ALLOW_LITERALS NUMBERS.
To allow all literals, execute SET ALLOW_LITERALS ALL (this is the default setting).
Literals can only be enabled or disabled by an administrator.
</p>
<h3>Using Constants</h3>
<p>
Disabling literals also means disabling hard-coded 'constant' literals. This database supports
defining constants using the CREATE CONSTANT command. Constants can be defined only
when literals are enabled, but used even when literals are disabled. To avoid name clashes
......@@ -645,18 +706,23 @@ SELECT * FROM USERS WHERE TYPE=CONST.ACTIVE;
Even when literals are enabled, it is better to use constants instead
of hard-coded number or text literals in queries or views. With constants, typos are found at compile
time, the source code is easier to understand and change.
</p>
<h3>Using the ZERO() Function</h3>
<p>
It is not required to create a constant for the number 0 as there is already a built-in function ZERO():
<pre>
SELECT * FROM USERS WHERE LENGTH(PASSWORD)=ZERO();
</pre>
</p>
<br /><a name="security_protocols"></a>
<h2>Security Protocols</h2>
<p>
The following paragraphs document the security protocols used in this database.
These descriptions are very technical and only intended for security experts that already know
the underlying security primitives.
</p>
<h3>User Password Encryption</h3>
<p>
......@@ -736,17 +802,22 @@ database operations take about 2.2 times longer when using XTEA, and 2.5 times l
</p>
<h3>SSL/TLS Connections</h3>
<p>
Remote SSL/TLS connections are supported using the Java Secure Socket Extension
(SSLServerSocket / SSLSocket). By default, anonymous SSL is enabled.
The default cipher suite is <code>SSL_DH_anon_WITH_RC4_128_MD5</code>.
</p>
<h3>HTTPS Connections</h3>
<p>
The web server supports HTTP and HTTPS connections using SSLServerSocket.
There is a default self-certified certificate to support an easy starting point, but
custom certificates are supported as well.
</p>
<br /><a name="uuid"></a>
<h2>Universally Unique Identifiers (UUID)</h2>
<p>
This database supports the UUIDs. Also supported is a function to create new UUIDs using
a cryptographically strong pseudo random number generator.
With random UUIDs, the chance of two having the same value can be calculated
......@@ -773,6 +844,7 @@ Some values are:
</pre>
One's annual risk of being hit by a meteorite is estimated to be one chance in 17 billion,
that means the probability is about 0.000'000'000'06.
</p>
<br /><a name="system_properties"></a>
<h2>Settings Read from System Properties</h2>
......@@ -781,11 +853,9 @@ Some settings of the database can be set on the command line using
-DpropertyName=value. It is usually not required to change those settings manually.
The settings are case sensitive.
Example:
</p>
<pre>
java -Dh2.serverCachedObjects=256 org.h2.tools.Server
</pre>
<p>
The current value of the settings can be read in the table
INFORMATION_SCHEMA.SETTINGS
</p>
......
......@@ -212,22 +212,27 @@ Features
</table>
<h3>Derby and HSQLDB</h3>
<p>
After an unexpected process termination (for example power failure), H2 can recover safely and
automatically without any user interaction. For Derby and HSQLDB, there are some manual steps required
('Another instance of Derby may have already booted the database' /
'The database is already in use by another process').
</p>
<h3>DaffodilDb and One$Db</h3>
<p>
It looks like the development of this database has stopped. The last release was February 2006.
</p>
<h3>McKoi</h3>
<p>
It looks like the development of this database has stopped. The last release was August 2004
</p>
<br /><a name="products_work_with"></a>
<h2>Products that Work with H2</h2>
<table>
<tr><th>Product</th><th>Description</th></tr>
<tr>
<td><a href="http://jackrabbit.apache.org">Apache Jackrabbit</a></td>
<td>Open source implementation of the Java Content Repository API (JCR).</td>
......@@ -314,7 +319,9 @@ It looks like the development of this database has stopped. The last release was
<br /><a name="connection_modes"></a>
<h2>Connection Modes</h2>
<p>
The following connection modes are supported:
</p>
<ul>
<li>Local connections using JDBC (embedded)
</li><li>Remote connections using JDBC over TCP/IP (client/server)
......@@ -436,12 +443,14 @@ This is achieved using different database URLs. The settings in the URLs are not
</table>
<h3>Connecting to an Embedded (Local) Database</h3>
<p>
The database URL for connecting to a local database is <code>jdbc:h2:[file:][&lt;path&gt;]&lt;databaseName&gt;</code>.
The prefix <code>file:</code> is optional. If no or only a relative path is used, then the current working
directory is used as a starting point. The case sensitivity of the path and database name depend on the
operating system, however it is suggested to use lowercase letters only.
The database name must be at least three characters long (a limitation of File.createTempFile).
To point to the user home directory, use ~/, as in: jdbc:h2:~/test.
</p>
<h3>Memory-Only Databases</h3>
<p>
......@@ -467,6 +476,7 @@ An example database URL is: <code>jdbc:h2:tcp://localhost/mem:db1</code>
<br /><a name="file_encryption"></a>
<h2>Connecting to a Database with File Encryption</h2>
<p>
To use file encryption, it is required to specify the encryption algorithm (the 'cipher')
and the file password. The algorithm needs to be specified using the connection parameter.
Two algorithms are supported: XTEA and AES. The file password is specified in the password field,
......@@ -474,6 +484,7 @@ before the user password. A single space needs to be added between the file pass
and the user password; the file password itself may not contain spaces. File passwords
(as well as user passwords) are case sensitive. Here is an example to connect to a password
encrypted database:
</p>
<pre>
Class.forName("org.h2.Driver");
String url = "jdbc:h2:~/test;CIPHER=AES";
......@@ -501,6 +512,7 @@ if the database files are only accessed by the one (and always the same) compute
</li><li>It is also possible to open the database without file locking;
in this case it is up to the application to protect the database files.
</li></ul>
<p>
To open the database with a different file locking method, use the parameter 'FILE_LOCK'.
The following code opens the database with the 'socket' locking method:
<pre>
......@@ -514,9 +526,11 @@ String url = "jdbc:h2:~/test;FILE_LOCK=NO";
</pre>
For more information about the algorithms please see in Advanced Topics under
File Locking Protocol.
</p>
<br /><a name="database_only_if_exists"></a>
<h2>Opening a Database Only if it Already Exists</h2>
<p>
By default, when an application calls <code>DriverManager.getConnection(url,...)</code>
and the database specified in the URL does not yet exist, a new (empty) database is created.
In some situations, it is better to restrict creating new database, and only open
......@@ -524,6 +538,7 @@ the database if it already exists. This can be done by adding <code>;ifexists=tr
to the URL. In this case, if the database does not already exist, an exception is thrown when
trying to connect. The connection only succeeds when the database already exists.
The complete URL may look like this:
</p>
<pre>
String url = "jdbc:h2:/data/sample;IFEXISTS=TRUE";
</pre>
......@@ -532,6 +547,7 @@ String url = "jdbc:h2:/data/sample;IFEXISTS=TRUE";
<h2>Closing the Database</h2>
<h3>Delayed Database Closing</h3>
<p>
Usually, the database is closed when the last connection to it is closed. In some situations
this slows down the application, for example when it is not possible leave the connection open.
The automatic closing of the database can be delayed or disabled with the SQL statement
......@@ -545,8 +561,10 @@ The value -1 means the database is never closed automatically.
The value 0 is the default and means the database is closed when the last connection is closed.
This setting is persistent and can be set by an administrator only.
It is possible to set the value in the database URL: <code>jdbc:h2:~/test;DB_CLOSE_DELAY=10</code>.
</p>
<h3>Don't Close the Database when the VM Exits</h3>
<p>
By default, a database is closed when the last connection is closed. However, if it is never closed,
the database is closed when the virtual machine exits normally. This is done using a shutdown hook.
In some situations, the database should not be closed in this case, for example because the
......@@ -555,12 +573,14 @@ For those cases, the automatic closing of the database can be disabled in the da
The first connection (the one that is opening the database) needs to
set the option in the database URL (it is not possible to change the setting afterwards).
The database URL to disable database closing on exit is:
</p>
<pre>
String url = "jdbc:h2:~/test;DB_CLOSE_ON_EXIT=FALSE";
</pre>
<br /><a name="log_index_changes"></a>
<h2>Log Index Changes</h2>
<p>
Usually, changes to the index file are not logged for performance.
If the index file is corrupt or missing when opening a database, it is re-created from the data.
The index file can get corrupt when the database is not shut down correctly,
......@@ -572,8 +592,10 @@ so that recovery from a corrupted index file is fast.
To enable log index changes, add LOG=2 to the URL, as in jdbc:h2:~/test;LOG=2
This setting should be specified when connecting.
The update performance of the database will be reduced when using this option.
</p>
<h3>Ignore Unknown Settings</h3>
<p>
Some applications (for example OpenOffice.org Base) pass some additional parameters
when connecting to the database. Why those parameters are passed is unknown.
The parameters PREFERDOSLIKELINEENDS and IGNOREDRIVERPRIVILEGES are such examples,
......@@ -581,17 +603,21 @@ they are simply ignored to improve the compatibility with OpenOffice.org. If an
passes other parameters when connecting to the database, usually the database throws an exception
saying the parameter is not supported. It is possible to ignored such parameters by adding
;IGNORE_UNKNOWN_SETTINGS=TRUE to the database URL.
</p>
<h3>Changing Other Settings when Opening a Connection</h3>
<p>
In addition to the settings already described (cipher, file_lock, ifexists, user, password),
other database settings can be passed in the database URL.
Adding <code>setting=value</code> at the end of an URL is the
same as executing the statement <code>SET setting value</code> just after
connecting. For a list of settings supported by this database please see the
SQL grammar documentation.
</p>
<br /><a name="custom_access_mode"></a>
<h2>Custom File Access Mode</h2>
<p>
Usually, the database opens log, data and index files with the access mode 'rw', meaning
read-write (except for read only databases, where the mode 'r' is used).
Also supported are 'rws' and 'rwd'.
......@@ -603,26 +629,33 @@ String url = "jdbc:h2:~/test;ACCESS_MODE_LOG=rws;ACCESS_MODE_DATA=rws";
</pre>
For more information see <a href="advanced.html#durability_problems">Durability Problems</a>.
On many operating systems the access mode 'rws' does not guarantee that the data is written to the disk.
</p>
<br /><a name="multiple_connections"></a>
<h2>Multiple Connections</h2>
<h3>Opening Multiple Databases at the Same Time</h3>
<p>
An application can open multiple databases at the same time, including multiple
connections to the same database. The number of open database is only limited by the memory available.
</p>
<h3>Multiple Connections to the Same Database: Client/Server</h3>
If you want to access the same database at the same time from different processes or computers,
you need to use the client / server mode. In this case, one process acts as the server, and the
other processes (that could reside on other computers as well) connect to the server via TCP/IP
(or SSL/TLS over TCP/IP for improved security).
<p>
If you want to access the same database at the same time from different processes or computers,
you need to use the client / server mode. In this case, one process acts as the server, and the
other processes (that could reside on other computers as well) connect to the server via TCP/IP
(or SSL/TLS over TCP/IP for improved security).
</p>
<h3>Multithreading Support</h3>
This database is multithreading-safe. That means, if an application is multi-threaded, it does not need
to worry about synchronizing the access to the database. Internally, most requests to the same database
are synchronized. That means an application can use multiple threads all accessing the same database
at the same time, however if one thread executes a long running query, the other threads
need to wait.
<p>
This database is multithreading-safe. That means, if an application is multi-threaded, it does not need
o worry about synchronizing the access to the database. Internally, most requests to the same database
are synchronized. That means an application can use multiple threads all accessing the same database
at the same time, however if one thread executes a long running query, the other threads
need to wait.
</p>
<h3>Locking, Lock-Timeout, Deadlocks</h3>
<p>
......@@ -860,8 +893,10 @@ Here is the list of currently supported modes and the difference to the regular
<br /><a name="trace_options"></a>
<h2>Using the Trace Options</h2>
<p>
To find problems in an application, it is sometimes good to see what database operations
where executed. This database offers the following trace features:
</p>
<ul>
<li>Trace to System.out and/or a file
</li><li>Support for trace levels OFF, ERROR, INFO, and DEBUG
......@@ -871,6 +906,7 @@ where executed. This database offers the following trace features:
</li></ul>
<h3>Trace Options</h3>
<p>
The simplest way to enable the trace option is setting it in the database URL.
There are two settings, one for System.out (TRACE_LEVEL_SYSTEM_OUT) tracing,
and one for file tracing (TRACE_LEVEL_FILE).
......@@ -886,22 +922,25 @@ Example:
<pre>
SET TRACE_LEVEL_SYSTEM_OUT 3
</pre>
</p>
<h3>Setting the Maximum Size of the Trace File</h3>
<p>
When using a high trace level, the trace file can get very big quickly.
The size of the file can be limited by executing the SQL statement
<code>SET TRACE_MAX_FILE_SIZE maximumFileSizeInMB</code>.
If the log file exceeds the limit, the file is renamed to .old and a new file is created.
If another .old file exists, it is deleted.
The default setting is 16 MB. Example:
</p>
<pre>
SET TRACE_MAX_FILE_SIZE 1
</pre>
<h3>Java Code Generation</h3>
<p>
When setting the trace level to INFO or DEBUG, Java source code is generated as well, so that
problem can be reproduced more easily. The trace file looks like this:
<pre>
...
12-20 20:58:09 jdbc[0]:
......@@ -910,7 +949,6 @@ problem can be reproduced more easily. The trace file looks like this:
/**/dbMeta3.getTables(null, "", null, new String[]{"TABLE", "VIEW"});
...
</pre>
You need to filter out the lines without /**/ to get the Java source code.
In Windows, a simple way to do that is:
<pre>
......@@ -925,6 +963,7 @@ Class.forName("org.h2.Driver");
}}
</pre>
Also, the user name and password needs to be set, because they are not listed in the trace file.
</p>
<h3>Enabling the Trace Option at Runtime by Manually Creating a File</h3>
<p>
......@@ -946,6 +985,7 @@ will always enable the trace mode when connecting.
<br /><a name="read_only"></a>
<h2>Read Only Databases</h2>
<p>
If the database files are read-only, then the database is read-only as well.
It is not possible to create new tables, add or modify data in this database.
Only SELECT statements are allowed.
......@@ -954,9 +994,11 @@ Then, make the database files read-only using the operating system.
When you open the database now, it is read-only.
There are two ways an application can find out a database is read-only:
By calling Connection.isReadOnly() or by executing the SQL statement CALL READONLY().
</p>
<br /><a name="storage_formats"></a>
<h2>Binary and Text Storage Formats</h2>
<p>
This database engine supports both binary and text storage formats.
The binary format is faster, but the text storage format can be useful as well,
for example to debug the database engine.
......@@ -964,6 +1006,7 @@ If a database already exists, the storage format is recognized automatically.
New databases are created in the binary storage format by default.
To create a new database in the text storage format, the database URL must contain
the parameter STORAGE=TEXT. Example URL: jdbc:h2:~/test;STORAGE=TEXT
</p>
<br /><a name="low_disk_space"></a>
<h2>Graceful Handling of Low Disk Space Situations</h2>
......@@ -987,12 +1030,15 @@ See also the DatabaseEventListener API.
</p>
<h3>Opening a Corrupted Database</h3>
<p>
If a database can not be opened because the boot info (the SQL script that is run at startup)
is corrupted, then the database can be opened by specifying a database event listener.
The exceptions are logged, but opening the database will continue.
</p>
<br /><a name="computed_columns"></a>
<h2>Computed Columns / Function Based Index</h2>
<p>
Function indexes are not directly supported by this database, but they can be easily emulated
by using computed columns. For example, if an index on the upper-case version of
a column is required, just create a computed column with the upper-case version of the original column,
......@@ -1012,6 +1058,7 @@ column when querying the table:
INSERT INTO ADDRESS(ID, NAME) VALUES(1, 'Miller');
SELECT * FROM ADDRESS WHERE UPPER_NAME='MILLER';
</pre>
</p>
<br /><a name="multi_dimensional"></a>
<h2>Multi-Dimensional Indexes</h2>
......@@ -1066,7 +1113,6 @@ password will not be stored in the swap file.
</p><p>
This database supports using char arrays instead of String to pass user and file passwords.
The following code can be used to do that:
</p>
<pre>
Class.forName("org.h2.Driver");
String url = "jdbc:h2:simple";
......@@ -1086,8 +1132,10 @@ try {
</pre>
In this example, the password is hard code in the application, which is not secure of course.
However, Java Swing supports a way to get passwords using a char array (JPasswordField).
</p>
<h3>Passing the User Name and/or Password in the URL</h3>
<p>
Instead of passing the user name as a separate parameter as in
<code>
Connection conn = DriverManager.
......@@ -1099,10 +1147,11 @@ Connection conn = DriverManager.
getConnection("jdbc:h2:~/test;USER=sa;PASSWORD=123");
</code>
The settings in the URL override the settings passed as a separate parameter.
</p>
<br /><a name="user_defined_functions"></a>
<h2>User Defined Functions and Stored Procedures</h2>
<p>
In addition to the built-in functions, this database supports user defined Java functions.
In this database, Java functions can be used as stored procedures as well.
A function must be declared (registered) before it can be used.
......@@ -1122,21 +1171,29 @@ The Java function must be registered in the database by calling CREATE ALIAS:
CREATE ALIAS IS_PRIME FOR "org.h2.samples.Function.isPrime"
</pre>
For a complete sample application, see src/test/org/h2/samples/Function.java.
</p>
<h3>Function Data Type Mapping</h3>
<p>
Functions that accept non-nullable parameters such as 'int' will not be called if one of those parameters is NULL.
In this case, the value NULL is used as the result. If the function should be called in this case, you need
to use 'java.lang.Integer' instead of 'int'.
</p>
<h3>Functions that require a Connection</h3>
<p>
If the first parameter in a Java function is a java.sql.Connection, then the connection
to database is provided. This connection does not need to be closed before returning.
</p>
<h3>Functions throwing an Exception</h3>
<p>
If a function throws an Exception, then the current statement is rolled back
and the exception is thrown to the application.
</p>
<h3>Functions returning a Result Set</h3>
<p>
Functions may returns a result set. Such a function can be called with the CALL statement:
<pre>
public static ResultSet query(Connection conn, String sql) throws SQLException {
......@@ -1146,8 +1203,10 @@ public static ResultSet query(Connection conn, String sql) throws SQLException {
CREATE ALIAS QUERY FOR "org.h2.samples.Function.query";
CALL QUERY('SELECT * FROM TEST');
</pre>
</p>
<h3>Using SimpleResultSet</h3>
<p>
A function that returns a result set can create this result set from scratch using the SimpleResultSet tool:
<pre>
import org.h2.tools.SimpleResultSet;
......@@ -1164,8 +1223,10 @@ public static ResultSet simpleResultSet() throws SQLException {
CREATE ALIAS SIMPLE FOR "org.h2.samples.Function.simpleResultSet";
CALL SIMPLE();
</pre>
</p>
<h3>Using a Function as a Table</h3>
<p>
A function returning a result set can be like a table.
However, in this case the function is called at least twice:
First while parsing the statement to collect the column names
......@@ -1192,9 +1253,11 @@ public static ResultSet getMatrix(Integer id) throws SQLException {
CREATE ALIAS MATRIX FOR "org.h2.samples.Function.getMatrix";
SELECT * FROM MATRIX(3) WHERE X>0;
</pre>
</p>
<br /><a name="triggers"></a>
<h2>Triggers</h2>
<p>
This database supports Java triggers that are called before or after a row is updated, inserted or deleted.
Triggers can be used for complex consistency checks, or to update related data in the database.
It is also possible to use triggers to simulate materialized views.
......@@ -1219,9 +1282,11 @@ CREATE TRIGGER INV_INS AFTER INSERT ON INVOICE
FOR EACH ROW CALL "org.h2.samples.TriggerSample"
</pre>
The trigger can be used to veto a change, by throwing a SQL Exception.
</p>
<br /><a name="compacting"></a>
<h2>Compacting a Database</h2>
<p>
Empty space in the database file is re-used automatically.
To re-build the indexes, the most simple way is to delete the .index.db file
while the database is closed. However in some situations (for example after deleting
......@@ -1240,6 +1305,7 @@ public static void compact(String dir, String dbName,
See also the sample application org.h2.samples.Compact.
The commands SCRIPT / RUNSCRIPT can be used as well to create the a backup
of a database and re-build the database from the script.
</p>
<br /><a name="cache_settings"></a>
<h2>Cache Settings</h2>
......@@ -1265,7 +1331,9 @@ is listed for the data and index file.
<br /><a name="why_java"></a>
<h2>Why Java</h2>
<p>
A few reasons using a Java database are:
</p>
<ul>
<li>Very simple to integrate in Java applications
</li><li>Support for many different platforms
......
......@@ -18,12 +18,14 @@ Initial Developer: H2 Group
</frameset>
<noframes>
<body>
<p>
H2 (for 'Hypersonic 2') is free a Java SQL DBMS.
Clustering, embedded and server mode, transactions, referential integrity,
views, subqueries, triggers, encryption, and disk based or in-memory operation
are supported. A browser based console application is included.
If you see this page your browser does not support frames.
Please click here to view the <a href="search.html">index</a>.
</p>
</body>
</noframes>
</html>
......@@ -18,12 +18,14 @@ Initial Developer: H2 Group
</frameset>
<noframes>
<body>
<p>
H2 (for 'Hypersonic 2') is free a Java SQL DBMS.
Clustering, embedded and server mode, transactions, referential integrity,
views, subqueries, triggers, encryption, and disk based or in-memory operation
are supported. A browser based console application is included.
If you see this page your browser does not support frames.
Please click here to view the <a href="search_ja.html">index</a>.
</p>
</body>
</noframes>
</html>
......@@ -1092,6 +1092,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Automatic mode: jdbc:h2:auto: (embedded mode if possible, if not use server mode).
Problem: what to do when server stops while others are connected to it.
</li><li>Access rights: remember the owner of an object. COMMENT: allow owner of object to change it.
</li><li>Implement INSTEAD OF trigger.
</li></ul>
<h3>Not Planned</h3>
......
......@@ -4,7 +4,7 @@
Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
H2 Database Engine
</title><link rel="stylesheet" type="text/css" href="stylesheet.css" />
......
......@@ -22,10 +22,11 @@ Performance
<br /><a name="performance_comparison"></a>
<h2>Performance Comparison</h2>
<p>
In most cases H2 is a lot faster than all other
(open source and not open source) database engines.
Please note this is mostly a single connection benchmark run on one computer.
</p>
<h3>Embedded</h3>
<table border="1" class="bar">
......@@ -76,6 +77,7 @@ Please note this is mostly a single connection benchmark run on one computer.
<h3>Benchmark Results and Comments</h3>
<h4>H2</h4>
<p>
Version 1.0 (2007-06-17) was used for the test.
For simpler operations, the performance of H2 is about the same as for HSQLDB.
For more complex queries, the query optimizer is very important.
......@@ -85,8 +87,10 @@ disk if more than a certain number of records are returned.
The advantage of buffering is, there is no limit on the result set size.
The open/close time is almost fixed, because of the file locking protocol: The engine waits
20 ms after opening a database to ensure the database files are not opened by another process.
</p>
<h4>HSQLDB</h4>
<p>
Version 1.8.0.5 was used for the test.
Cached tables are used in this test (hsqldb.default_table_type=cached),
and the write delay is 1 second (SET WRITE_DELAY 1).
......@@ -101,21 +105,27 @@ AND S_W_ID=? AND S_I_ID=OL_I_ID AND S_QUANTITY&lt;?
The PolePosition benchmark also shows that the query optimizer does not do a very good job for some queries.
A disadvantage in HSQLDB is the slow startup / shutdown time (currently not listed) when using bigger databases.
The reason is, a backup of the database is created whenever the database is opened or closed.
</p>
<h4>Derby</h4>
<p>
Version 10.2.1.6 was used for the test. Derby is clearly the slowest embedded database in this test.
This seems to be a structural problem, because all operations are really slow.
It will not be easy for the developers of Derby to improve the performance to a reasonable level.
</p>
<h4>PostgreSQL</h4>
<p>
Version 8.1.4 was used for the test.
The following options where changed in postgresql.conf:
fsync = off, commit_delay = 1000.
PostgreSQL is run in server mode. It looks like the base performance is slower than
MySQL, the reason could be the network layer.
The memory usage number is incorrect, because only the memory usage of the JDBC driver is measured.
</p>
<h4>MySQL</h4>
<p>
Version 5.0.22 was used for the test.
MySQL was run with the InnoDB backend.
The setting innodb_flush_log_at_trx_commit
......@@ -127,48 +137,64 @@ Too bad this setting is not listed in the configuration wizard,
and it always overwritten when using the wizard.
You need to change this setting manually in the file my.ini, and then restart the service.
The memory usage number is incorrect, because only the memory usage of the JDBC driver is measured.
</p>
<h4>Firebird</h4>
<p>
Firebird 1.5 (default installation) was tested, but the results are not published currently.
It is possible to run the performance test with the Firebird database,
and any information on how to configure Firebird for higher performance are welcome.
</p>
<h4>Why Oracle / MS SQL Server / DB2 are Not Listed</h4>
<p>
The license of these databases does not allow to publish benchmark results.
This doesn't mean that they are fast. They are in fact quite slow,
and need a lot of memory. But you will need to test this yourself.
SQLite was not tested because the JDBC driver doesn't support transactions.
</p>
<h3>About this Benchmark</h3>
<h4>Number of Connections</h4>
<p>
This is mostly a single-connection benchmark.
BenchB uses multiple connections, the other tests one connection.
</p>
<h4>Real-World Tests</h4>
<p>
Good benchmarks emulate real-world use cases. This benchmark includes 3 test cases:
A simple test case with one table and many small updates / deletes.
BenchA is similar to the TPC-A test, but single connection / single threaded (see also: www.tpc.org).
BenchB is similar to the TPC-B test, using multiple connections (one thread per connection).
BenchC is similar to the TPC-C test, but single connection / single threaded.
</p>
<h4>Comparing Embedded with Server Databases</h4>
<p>
This is mainly a benchmark for embedded databases (where the application runs in the same
virtual machine than the database engine). However MySQL and PostgreSQL are not Java
databases and cannot be embedded into a Java application.
For the Java databases, both embedded and server modes are tested.
</p>
<h4>Test Platform</h4>
<p>
This test is run on Windows XP with the virus scanner switched off.
The VM used is Sun JDK 1.5.
</p>
<h4>Multiple Runs</h4>
<p>
When a Java benchmark is run first, the code is not fully compiled and
therefore runs slower than when running multiple times. A benchmark
should always run the same test multiple times and ignore the first run(s).
This benchmark runs three times, the last run counts.
</p>
<h4>Memory Usage</h4>
<p>
It is not enough to measure the time taken, the memory usage is important as well.
Performance can be improved in databases by using a bigger in-memory cache,
but there is only a limited amount of memory available on the system.
......@@ -177,13 +203,17 @@ uses 'disk based' tables for all databases.
Unfortunately, it is not so easy to calculate the memory usage of PostgreSQL
and MySQL, because they run in a different process than the test. This benchmark currently
does not print memory usage of those databases.
</p>
<h4>Delayed Operations</h4>
<p>
Some databases delay some operations (for example flushing the buffers)
until after the benchmark is run. This benchmark waits between
each database tested, and each database runs in a different process (sequentially).
</p>
<h4>Transaction Commit / Durability</h4>
<p>
Durability means transaction committed to the database will not be lost.
Some databases (for example MySQL) try to enforce this by default by calling fsync() to flush the buffers, but
most hard drives don't actually flush all data. Calling fsync() slows down transaction commit a lot,
......@@ -194,11 +224,15 @@ inserts. However many applications need 'short' transactions at runtime (a commi
This benchmark commits after each update / delete in the simple benchmark, and after each
business transaction in the other benchmarks. For databases that support delayed commits,
a delay of one second is used.
</p>
<h4>Using Prepared Statements</h4>
<p>
Wherever possible, the test cases use prepared statements.
</p>
<h4>Currently Not Tested: Startup Time</h4>
<p>
The startup time of a database engine is important as well for embedded use.
This time is not measured currently.
Also, not tested is the time used to create a database and open an existing database.
......@@ -206,6 +240,7 @@ Here, one (wrapper) connection is opened at the start,
and for each step a new connection is opened and then closed.
That means the Open/Close time listed is for opening a connection
if the database is already in use.
</p>
<h3>PolePosition Benchmark</h3>
<p>
......@@ -240,6 +275,7 @@ It was developed / sponsored by db4o.
<h2>Application Profiling</h2>
<h3>Analyze First</h3>
<p>
Before trying to optimize the performance, it is important to know where the time is actually spent.
The same is true for memory problems.
Premature or 'blind' optimization should be avoided, as it is not an efficient way to solve the problem.
......@@ -249,26 +285,32 @@ But this does not work for complex applications with many modules, and for memor
A very good tool to measure both the memory and the CPU is the
<a href="http://www.yourkit.com">YourKit Java Profiler</a>. This tool is also used
to optimize the performance and memory footprint of this database engine.
</p>
<br /><a name="database_performance_tuning"></a>
<h2>Database Performance Tuning</h2>
<h3>Virus Scanners</h3>
<p>
Some virus scanners scan files every time they are accessed.
It is very important for performance that database files are not scanned for viruses.
The database engine does never interprets the data stored in the files as programs,
that means even if somebody would store a virus in a database file, this would
be harmless (when the virus does not run, it cannot spread).
Some virus scanners allow excluding file endings. Make sure files ending with .db are not scanned.
</p>
<h3>Using the Trace Options</h3>
<p>
If the main performance hot spots are in the database engine, in many cases the performance
can be optimized by creating additional indexes, or changing the schema. Sometimes the
application does not directly generate the SQL statements, for example if an O/R mapping tool
is used. To view the SQL statements and JDBC API calls, you can use the trace options.
For more information, see <a href="features.html#trace_options">Using the Trace Options</a>.
</p>
<h3>Index Usage</h3>
<p>
This database uses indexes to improve the performance of SELECT, UPDATE and DELETE statements.
If a column is used in the WHERE clause of a query, and if an index exists on this column,
then the index can be used. Multi-column indexes are used if all or the first columns of the index are used.
......@@ -277,25 +319,32 @@ Indexes are not used to order result sets: The results are sorted in memory if r
Indexes are created automatically for primary key and unique constraints.
Indexes are also created for foreign key constraints, if required.
For other columns, indexes need to be created manually using the CREATE INDEX statement.
</p>
<h3>Optimizer</h3>
<p>
This database uses a cost based optimizer. For simple and queries and queries with medium complexity
(less than 7 tables in the join), the expected cost (running time) of all possible plans is calculated,
and the plan with the lowest cost is used. For more complex queries, the algorithm first tries
all possible combinations for the first few tables, and the remaining tables added using a greedy algorithm
(this works well for most joins). Afterwards a genetic algorithm is used to test at most 2000 distinct plans.
Only left-deep plans are evaluated.
</p>
<h3>Expression Optimization</h3>
<p>
After the statement is parsed, all expressions are simplified automatically if possible. Operations
are evaluated only once if all parameters are constant. Functions are also optimized, but only
if the function is constant (always returns the same result for the same parameter values).
If the WHERE clause is always false, then the table is not accessed at all.
</p>
<h3>COUNT(*) Optimization</h3>
<p>
If the query only counts all rows of a table, then the data is not accessed.
However, this is only possible if no WHERE clause is used, that means it only works for
queries of the form SELECT COUNT(*) FROM table.
</p>
<h3>Updating Optimizer Statistics / Column Selectivity</h3>
<p>
......
......@@ -40,6 +40,9 @@ public class JdbcSQLException extends SQLException {
}
private static String buildMessage(String message, String sql, String state) {
if(message == null) {
message = "";
}
StringBuffer buff = new StringBuffer(message);
if(sql != null) {
buff.append("; SQL statement: ");
......
......@@ -4,7 +4,10 @@
*/
package org.h2.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.h2.server.TcpServer;
......@@ -94,6 +97,23 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
/*
search from a frame (but usually don't use frames)
Class.forName("org.h2.Driver");
DeleteDbFiles.execute("~", null, true);
Connection conn1 = DriverManager.getConnection("jdbc:h2:~/test");
Statement s1 = conn1.createStatement();
s1.execute("create table test(id int)");
conn1.setAutoCommit(false);
s1.execute("delete from test");
s1.execute("PREPARE COMMIT TX_8");
s1.execute("COMMIT TRANSACTION TX_8");
Connection conn2 = DriverManager.getConnection("jdbc:h2:~/test");
conn2.createStatement().execute("select * from test");
call N'@name';
pg_version is in public instead of pg_catalog
copyright to include 2007
......
......@@ -17,7 +17,7 @@ public class DbStarter implements ServletContextListener {
// You can also get the setting from a context-param in web.xml:
ServletContext servletContext = servletContextEvent.getServletContext();
// String url = servletContext.getInitParameter("db.url");
conn = DriverManager.getConnection("jdbc:h2:test", "sa", "");
conn = DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
servletContext.setAttribute("connection", conn);
} catch (Exception e) {
e.printStackTrace();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论