Commit ee8d39a8 authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Add mention of transactions and large objects.

 Still need the code updated for LO examples.
parent 0655b150
<Chapter Id="jdbc"> <chapter id="jdbc">
<Title>JDBC Interface</Title> <title>JDBC Interface</title>
<para> <para>
<note> <note>
<title>Author</title> <title>Author</title>
<para> <para>
Written by <ulink url="peter@retep.org.uk">Peter T. Mount</ulink>, the Written by <ulink url="peter@retep.org.uk">Peter T. Mount</ulink>, the
author of the <acronym>JDBC</acronym> driver. author of the <acronym>JDBC</acronym> driver.
</para> </para>
</note> </note>
</para> </para>
<para> <para>
<acronym>JDBC</acronym> is a core <acronym>API</acronym> of Java 1.1 and later. <acronym>JDBC</acronym> is a core <acronym>API</acronym> of Java 1.1 and later.
It provides a standard set of It provides a standard set of
interfaces to <acronym>SQL</acronym>-compliant databases. interfaces to <acronym>SQL</acronym>-compliant databases.
</para> </para>
<para>
<application>Postgres</application> provides <para>
a type 4 <acronym>JDBC</acronym> Driver. Type 4 indicates that the driver <application>Postgres</application> provides
is written in Pure Java, and communicates in the database's own network a <firstterm>type 4</firstterm> <acronym>JDBC</acronym> Driver.
protocol. Because of this, the driver is platform independent. Once compiled, Type 4 indicates that the driver
the driver can be used on any platform. is written in Pure Java, and communicates in the database's own network
</para> protocol. Because of this, the driver is platform independent. Once compiled,
the driver can be used on any platform.
<sect1> </para>
<title>Building the <acronym>JDBC</acronym> Interface</title>
<sect1>
<sect2> <title>Building the <acronym>JDBC</acronym> Interface</title>
<title>Compiling the Driver</title>
<sect2>
<para> <title>Compiling the Driver</title>
The driver's source is located in the <filename>src/interfaces/jdbc</filename>
directory of the <para>
source tree. To compile simply change directory to that directory, and type: The driver's source is located in the <filename>src/interfaces/jdbc</filename>
directory of the
<programlisting> source tree. To compile simply change directory to that directory, and type:
<programlisting>
% make % make
</programlisting> </programlisting>
</para> </para>
<para> <para>
Upon completion, you will find the archive <filename>postgresql.jar</filename> Upon completion, you will find the archive <filename>postgresql.jar</filename>
in the current in the current
directory. This is the <acronym>JDBC</acronym> driver. directory. This is the <acronym>JDBC</acronym> driver.
<note> <note>
<para> <para>
You must use <application>make</application>, You must use <application>make</application>,
not <application>javac</application>, not <application>javac</application>,
as the driver uses some dynamic as the driver uses some dynamic
loading techniques for performance reasons, loading techniques for performance reasons,
and <application>javac</application> cannot cope. and <application>javac</application> cannot cope.
The <filename>Makefile</filename> will generate the jar archive. The <filename>Makefile</filename> will generate the jar archive.
</para> </para>
</note> </note>
</para> </para>
</sect2> </sect2>
<sect2> <sect2>
<title>Installing the Driver</title> <title>Installing the Driver</title>
<para> <para>
To use the driver, the jar archive postgresql.jar needs to be included in To use the driver, the jar archive postgresql.jar needs to be included in
the CLASSPATH. the <envar>CLASSPATH</envar>.
</para> </para>
<para>
Example: <sect3>
</para> <title>Example</title>
<para>
I have an application that uses the <acronym>JDBC</acronym> driver to access a large database <para>
containing astronomical objects. I have the application and the jdbc driver I have an application that uses the <acronym>JDBC</acronym> driver to access a large database
installed in the /usr/local/lib directory, and the java jdk installed in /usr/local/jdk1.1.6. containing astronomical objects. I have the application and the jdbc driver
</para> installed in the /usr/local/lib directory, and the java jdk installed in /usr/local/jdk1.1.6.
</para>
<para>
To run the application, I would use: <para>
</para> To run the application, I would use:
<para>
export CLASSPATH = \ <programlisting>
/usr/local/lib/finder.jar:/usr/local/lib/postgresql.jar:. export CLASSPATH = /usr/local/lib/finder.jar:/usr/local/lib/postgresql.jar:.
java uk.org.retep.finder.Main java uk.org.retep.finder.Main
</para> </programlisting>
<para> </para>
Loading the driver is covered later on in this chapter.
</para> <para>
</sect2> Loading the driver is covered later on in this chapter.
</sect1> </para>
</sect3>
<sect1> </sect2>
<title>Preparing the Database for <acronym>JDBC</acronym></title> </sect1>
<para> <sect1>
Because Java can only use TCP/IP connections, the <application>Postgres</application> postmaster <title>Preparing the Database for <acronym>JDBC</acronym></title>
must be running with the -i flag.
</para> <para>
<para> Because Java can only use TCP/IP connections, the <application>Postgres</application> postmaster
Also, the <filename>pg_hba.conf</filename> file must be configured. It's located in the PGDATA must be running with the -i flag.
directory. In a default installation, this file permits access only by UNIX </para>
domain sockets. For the <acronym>JDBC</acronym> driver to connect to the same localhost, you need
to add something like: <para>
</para> Also, the <filename>pg_hba.conf</filename> file must be configured. It's located in the PGDATA
<para> directory. In a default installation, this file permits access only by Unix
domain sockets. For the <acronym>JDBC</acronym> driver to connect to the same localhost, you need
to add something like:
<programlisting>
host all 127.0.0.1 255.255.255.255 password host all 127.0.0.1 255.255.255.255 password
</para> </programlisting>
<para>
Here access to all databases are possible from the local machine Here access to all databases are possible from the local machine
with <acronym>JDBC</acronym>. with <acronym>JDBC</acronym>.
</para> </para>
<para> <para>
The <acronym>JDBC</acronym> Driver supports trust, ident, The <acronym>JDBC</acronym> Driver supports trust, ident,
password and crypt authentication methods. password and crypt authentication methods.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>Using the Driver</title> <title>Using the Driver</title>
<para> <para>
This section is not intended as a complete guide to This section is not intended as a complete guide to
<acronym>JDBC</acronym> programming, but <acronym>JDBC</acronym> programming, but
should help to get you started. For more information refer to the standard should help to get you started. For more information refer to the standard
<acronym>JDBC</acronym> <acronym>API</acronym> documentation. <acronym>JDBC</acronym> <acronym>API</acronym> documentation.
</para> Also, take a look at the examples included with the source. The basic
<para> example is used here.
Also, take a look at the examples included with the source. The basic </para>
example is used here. </sect1>
</para>
</sect1> <sect1>
<title>Importing <acronym>JDBC</acronym></title>
<sect1>
<title>Importing <acronym>JDBC</acronym></title> <para>
Any source that uses <acronym>JDBC</acronym>
<para> needs to import the java.sql package, using:
Any source that uses <acronym>JDBC</acronym>
needs to import the java.sql package, using: <programlisting>
<programlisting>
import java.sql.*; import java.sql.*;
</programlisting> </programlisting>
<important> <important>
<para> <para>
Do not import the postgresql package. If you do, your source will not Do not import the postgresql package. If you do, your source will not
compile, as javac will get confused. compile, as javac will get confused.
</para> </para>
</important> </important>
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>Loading the Driver</title> <title>Loading the Driver</title>
<para> <para>
Before you can connect to a database, you need to load the driver. There Before you can connect to a database, you need to load the driver. There
are two methods available, and it depends on your code to the best one to use. are two methods available, and it depends on your code to the best one to use.
</para> </para>
<para> <para>
In the first method, your code implicitly loads the driver using the In the first method, your code implicitly loads the driver using the
Class.forName() method. For <application>Postgres</application>, you would use: <function>Class.forName()</function> method.
For <application>Postgres</application>, you would use:
<programlisting>
<programlisting>
Class.forName("postgresql.Driver"); Class.forName("postgresql.Driver");
</programlisting> </programlisting>
This will load the driver, and while loading, the driver will automatically This will load the driver, and while loading, the driver will automatically
register itself with <acronym>JDBC</acronym>. register itself with <acronym>JDBC</acronym>.
</para> </para>
<para> <para>
Note: The <function>forName()</function> method Note: The <function>forName()</function> method
can throw a ClassNotFoundException, so you will can throw a <literal>ClassNotFoundException</literal>, so you will
need to catch it if the driver is not available. need to catch it if the driver is not available.
</para> </para>
<para> <para>
This is the most common method to use, but restricts your code to use just This is the most common method to use, but restricts your code to use just
<application>Postgres</application>. <application>Postgres</application>.
If your code may access another database in the future, and you If your code may access another database in the future, and you
don't use our extensions, then the second method is advisable. don't use our extensions, then the second method is advisable.
</para> </para>
<para> <para>
The second method passes the driver as a parameter to the JVM as it starts, The second method passes the driver as a parameter to the JVM as it starts,
using the -D argument. using the -D argument. Example:
</para>
<para> <programlisting>
Example:
<programlisting>
% java -Djdbc.drivers=postgresql.Driver example.ImageViewer % java -Djdbc.drivers=postgresql.Driver example.ImageViewer
</programlisting> </programlisting>
</para>
In this example, the JVM will attempt to load the driver as part of it's
<para> initialisation. Once done, the ImageViewer is started.
In this example, the JVM will attempt to load the driver as part of it's </para>
initialisation. Once done, the ImageViewer is started.
<para>
</para> Now, this method is the better one to use because it allows your code to
<para> be used with other databases, without recompiling the code. The only thing
Now, this method is the better one to use because it allows your code to that would also change is the URL, which is covered next.
be used with other databases, without recompiling the code. The only thing </para>
that would also change is the URL, which is covered next.
</para> <para>
One last thing. When your code then tries to open a Connection, and you get
<para> a <literal>No driver available</literal> SQLException being thrown,
One last thing. When your code then tries to open a Connection, and you get this is probably
a <literal>No driver available</literal> SQLException being thrown, caused by the driver not being in the classpath, or the value in the parameter
this is probably not being correct.
caused by the driver not being in the classpath, or the value in the parameter </para>
not being correct. </sect1>
</para>
</sect1> <sect1>
<title>Connecting to the Database</title>
<sect1>
<title>Connecting to the Database</title> <para>
With <acronym>JDBC</acronym>, a database is represented by a URL
<para> (Uniform Resource Locator).
With <acronym>JDBC</acronym>, a database is represented by a URL With <application>Postgres</application>, this takes one of the following
(Uniform Resource Locator). forms:
With <application>Postgres</application>, this takes one of the following
forms: <itemizedlist>
<listitem>
<itemizedlist> <para>
<listitem> jdbc:postgresql:<replaceable class="parameter">database</replaceable>
<para> </para>
jdbc:postgresql:<replaceable class="parameter">database</replaceable> </listitem>
</para>
</listitem> <listitem>
<para>
<listitem> jdbc:postgresql://<replaceable class="parameter">>hos</replaceable>>/<replaceable class="parameter">database</replaceable>
<para> </para>
jdbc:postgresql://<replaceable class="parameter">host</replaceable>/<replaceable class="parameter">database</replaceable> </listitem>
</para>
</listitem> <listitem>
<para>
<listitem> jdbc:postgresql://<replaceable class="parameter">>hos</replaceable>><replaceable class="parameter">">po</replaceable>e>/<replaceable class="parameter">database</replaceable>
<para> </para>
jdbc:postgresql://<replaceable class="parameter">host</replaceable>:<replaceable class="parameter">port</replaceable>/<replaceable class="parameter">database</replaceable> </listitem>
</para> </itemizedlist>
</listitem>
where:
</itemizedlist>
<variablelist>
where: <varlistentry>
<term>
<variablelist> <replaceable class="parameter">host</replaceable>
<varlistentry> </term>
<term> <listitem>
<replaceable class="parameter">host</replaceable> <para>
</term> The hostname of the server. Defaults to "localhost".
<listitem> </para>
<para> </listitem>
The hostname of the server. Defaults to "localhost". </varlistentry>
</para>
</listitem> <varlistentry>
</varlistentry> <term>
<replaceable class="parameter">port</replaceable>
<varlistentry> </term>
<term> <listitem>
<replaceable class="parameter">port</replaceable> <para>
</term> The port number the server is listening on. Defaults to the Postgres
<listitem> standard port number (5432).
<para> </para>
The port number the server is listening on. Defaults to the Postgres </listitem>
standard port number (5432). </varlistentry>
</para>
</listitem> <varlistentry>
</varlistentry> <term>
<replaceable class="parameter">database</replaceable>
<varlistentry> </term>
<term> <listitem>
<replaceable class="parameter">database</replaceable> <para>
</term> The database name.
<listitem> </para>
<para> </listitem>
The database name. </varlistentry>
</para> </variablelist>
</listitem> </para>
</varlistentry>
<para>
</variablelist> To connect, you need to get a Connection instance from
</para> <acronym>JDBC</acronym>. To do this,
you would use the DriverManager.getConnection() method:
<para>
To connect, you need to get a Connection instance from <programlisting>
<acronym>JDBC</acronym>. To do this,
you would use the DriverManager.getConnection() method:
</para>
<para>
Connection db = DriverManager.getConnection(url,user,pwd); Connection db = DriverManager.getConnection(url,user,pwd);
</para> </programlisting>
</sect1> </para>
</sect1>
<sect1>
<title>Issuing a Query and Processing the Result</title> <sect1>
<title>Issuing a Query and Processing the Result</title>
<para>
Any time you want to issue SQL statements to the database, you require a <para>
Statement instance. Once you have a Statement, you can use the executeQuery() Any time you want to issue SQL statements to the database, you require a
method to issue a query. This will return a ResultSet instance, which contains Statement instance. Once you have a Statement, you can use the executeQuery()
the entire result. method to issue a query. This will return a ResultSet instance, which contains
</para> the entire result.
</para>
<sect2>
<title>Using the Statement Interface</title> <sect2>
<title>Using the Statement Interface</title>
<para>
The following must be considered when using the Statement interface: <para>
The following must be considered when using the Statement interface:
<itemizedlist>
<listitem> <itemizedlist>
<para> <listitem>
You can use a Statement instance as many times as you want. You could <para>
create one as soon as you open the connection, and use it for the connections You can use a Statement instance as many times as you want. You could
lifetime. You have to remember that only one ResultSet can exist per Statement. create one as soon as you open the connection, and use it for the connections
</para> lifetime. You have to remember that only one ResultSet can exist per Statement.
</listitem> </para>
</listitem>
<listitem>
<para> <listitem>
If you need to perform a query while processing a ResultSet, you can <para>
simply create and use another Statement. If you need to perform a query while processing a ResultSet, you can
</para> simply create and use another Statement.
</listitem> </para>
<listitem> </listitem>
<para> <listitem>
If you are using Threads, and several are using the database, you must <para>
use a separate Statement for each thread. Refer to the sections covering If you are using Threads, and several are using the database, you must
Threads and Servlets later in this document if you are thinking of using them, use a separate Statement for each thread. Refer to the sections covering
as it covers some important points. Threads and Servlets later in this document if you are thinking of using them,
</para> as it covers some important points.
</listitem> </para>
</itemizedlist> </listitem>
</para> </itemizedlist>
</sect2> </para>
</sect2>
<sect2>
<title>Using the ResultSet Interface</title> <sect2>
<title>Using the ResultSet Interface</title>
<para>
The following must be considered when using the ResultSet interface: <para>
The following must be considered when using the ResultSet interface:
<itemizedlist>
<listitem> <itemizedlist>
<para> <listitem>
Before reading any values, you must call <function>next()</function>. This returns true if <para>
there is a result, but more importantly, it prepares the row for processing. Before reading any values, you must call <function>next()</function>. This returns true if
</para> there is a result, but more importantly, it prepares the row for processing.
</listitem> </para>
</listitem>
<listitem>
<para> <listitem>
Under the <acronym>JDBC</acronym> spec, you should access a field only once. It's safest <para>
to stick to this rule, although at the current time, the <application>Postgres</application> driver Under the <acronym>JDBC</acronym> spec, you should access a
will allow you to access a field as many times as you want. field only once. It's safest to stick to this rule, although
</para> at the current time, the <application>Postgres</application> driver
</listitem> will allow you to access a field as many times as you want.
</para>
<listitem> </listitem>
<para>
You must close a ResultSet by calling <function>close()</function> once you have finished with it. <listitem>
</para> <para>
</listitem> You must close a ResultSet by calling
<function>close()</function> once you have finished with it.
<listitem> </para>
<para> </listitem>
Once you request another query with the Statement used to create a
ResultSet, the currently open instance is closed. <listitem>
</para> <para>
</listitem> Once you request another query with the Statement used to create a
</itemizedlist> ResultSet, the currently open instance is closed.
</para> </para>
</listitem>
<para> </itemizedlist>
An example is as follows: </para>
<programlisting> <para>
An example is as follows:
<programlisting>
Statement st = db.createStatement(); Statement st = db.createStatement();
ResultSet rs = st.executeQuery("select * from mytable"); ResultSet rs = st.executeQuery("select * from mytable");
while(rs.next()) { while(rs.next()) {
...@@ -387,74 +388,97 @@ while(rs.next()) { ...@@ -387,74 +388,97 @@ while(rs.next()) {
} }
rs.close(); rs.close();
st.close(); st.close();
</programlisting> </programlisting>
</para> </para>
</sect2> </sect2>
</sect1> </sect1>
<sect1> <sect1>
<title>Performing Updates</title> <title>Performing Updates</title>
<para> <para>
To perform an update (or any other SQL statement that does not return a To perform an update (or any other SQL statement that does not return a
result), you simply use the executeUpdate() method: result), you simply use the <function>executeUpdate()</function> method:
<programlisting> <programlisting>
st.executeUpdate("create table basic (a int2, b int2)"); st.executeUpdate("create table basic (a int2, b int2)");
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>Closing the Connection</title> <title>Closing the Connection</title>
<para> <para>
To close the database connection, simply call the close() method to the Connection: To close the database connection, simply call the close() method to the Connection:
<programlisting> <programlisting>
db.close(); db.close();
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title>Using Large Objects</title> <title>Using Large Objects</title>
<para> <para>
In <application>Postgres</application>, In <application>Postgres</application>,
large objects (also known as <firstterm>blobs</firstterm>) are used to hold data in large objects (also known as <firstterm>blobs</firstterm>) are used to hold data in
the database that cannot be stored in a normal SQL table. They are stored as a the database that cannot be stored in a normal SQL table. They are stored as a
Table/Index pair, and are refered to from your own tables, by an OID value. Table/Index pair, and are referred to from your own tables by an OID value.
</para> </para>
<para> <para>
Now, there are you methods of using Large Objects. The first is the <important>
standard <acronym>JDBC</acronym> way, and is documented here. The other, uses our own extension <para>
to the api, which presents the libpq large object <acronym>API</acronym> to Java, providing even For <productname>Postgres</productname>, you must access large
better access to large objects than the standard. Internally, the driver uses objects within an SQL transaction. Although this has always been
the extension to provide large object support. true in principle, it was not strictly enforced until the
</para> release of v6.5. You would open a transaction by using the
<para> <function>setAutoCommit()</function> method with an input
In <acronym>JDBC</acronym>, the standard way to access them is using the getBinaryStream() parameter of <literal>false</literal>:
method in ResultSet, and setBinaryStream() method in PreparedStatement. These
methods make the large object appear as a Java stream, allowing you to use the <programlisting>
java.io package, and others, to manipulate the object. Connection mycon;
</para> ...
mycon.setAutoCommit(false);
<para> ... now use Large Objects
For example, suppose </programlisting>
you have a table containing the file name of an image, and a large object </para>
containing that image: </important>
</para>
<programlisting>
<para>
Now, there are two methods of using Large Objects. The first is the
standard <acronym>JDBC</acronym> way, and is documented here. The
other, uses our own extension
to the api, which presents the libpq large object
<acronym>API</acronym> to Java, providing even
better access to large objects than the standard. Internally, the driver uses
the extension to provide large object support.
</para>
<para>
In <acronym>JDBC</acronym>, the standard way to access them is using the getBinaryStream()
method in ResultSet, and setBinaryStream() method in PreparedStatement. These
methods make the large object appear as a Java stream, allowing you to use the
java.io package, and others, to manipulate the object.
</para>
<para>
For example, suppose
you have a table containing the file name of an image, and a large object
containing that image:
<programlisting>
create table images (imgname name,imgoid oid); create table images (imgname name,imgoid oid);
</programlisting> </programlisting>
</para> </para>
<para> <para>
To insert an image, you would use: To insert an image, you would use:
<programlisting> <programlisting>
File file = new File("myimage.gif"); File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file); FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement("insert into images values (?,?)"); PreparedStatement ps = conn.prepareStatement("insert into images values (?,?)");
...@@ -463,20 +487,20 @@ ps.setBinaryStream(2,fis,file.length()); ...@@ -463,20 +487,20 @@ ps.setBinaryStream(2,fis,file.length());
ps.executeUpdate(); ps.executeUpdate();
ps.close(); ps.close();
fis.close(); fis.close();
</programlisting> </programlisting>
</para> </para>
<para> <para>
Now in this example, setBinaryStream transfers a set number of bytes from a Now in this example, setBinaryStream transfers a set number of bytes from a
stream into a large object, and stores the OID into the field holding a stream into a large object, and stores the OID into the field holding a
reference to it. reference to it.
</para> </para>
<para> <para>
Retrieving an image is even easier (I'm using PreparedStatement here, but Retrieving an image is even easier (I'm using PreparedStatement here, but
Statement can equally be used): Statement can equally be used):
<programlisting> <programlisting>
PreparedStatement ps = con.prepareStatement("select oid from images where name=?"); PreparedStatement ps = con.prepareStatement("select oid from images where name=?");
ps.setString(1,"myimage.gif"); ps.setString(1,"myimage.gif");
ResultSet rs = ps.executeQuery(); ResultSet rs = ps.executeQuery();
...@@ -489,31 +513,33 @@ if(rs!=null) { ...@@ -489,31 +513,33 @@ if(rs!=null) {
rs.close(); rs.close();
} }
ps.close(); ps.close();
</programlisting> </programlisting>
</para> </para>
<para> <para>
Now here you can see where the Large Object is retrieved as an InputStream. Now here you can see where the Large Object is retrieved as an InputStream.
You'll also notice that we close the stream before processing the next row in You'll also notice that we close the stream before processing the next row in
the result. This is part of the <acronym>JDBC</acronym> Specification, which states that any the result. This is part of the <acronym>JDBC</acronym> Specification, which states that any
InputStream returned is closed when ResultSet.next() or ResultSet.close() is called. InputStream returned is closed when ResultSet.next() or ResultSet.close() is called.
</para> </para>
</sect1> </sect1>
<sect1> <sect1>
<title><application>Postgres</application> Extensions to the <acronym>JDBC</acronym> <acronym>API</acronym></title> <title><application>Postgres</application> Extensions to the
<acronym>JDBC</acronym> <acronym>API</acronym></title>
<para>
<application>Postgres</application> is an extensible database system. <para>
You can add your own functions <application>Postgres</application> is an extensible database system.
to the backend, which can then be called from queries, or even add your own You can add your own functions
data types. to the backend, which can then be called from queries, or even add your own
</para> data types.
<para> </para>
Now, as these are facilities unique to us, we support them from Java, with
a set of extension <acronym>API</acronym>'s. Some features within <para>
the core of the standard driver Now, as these are facilities unique to us, we support them from Java, with
actually use these extensions to implement Large Objects, etc. a set of extension <acronym>API</acronym>'s. Some features within
the core of the standard driver
actually use these extensions to implement Large Objects, etc.
<!-- <!--
************************************************************ ************************************************************
...@@ -2241,7 +2267,8 @@ java.lang.Object ...@@ -2241,7 +2267,8 @@ java.lang.Object
public class PGobject extends Object implements Serializable, public class PGobject extends Object implements Serializable,
Cloneable Cloneable
This class is used to describe data types that are unknown by <acronym>JDBC</acronym> This class is used to describe data types that are unknown by
<acronym>JDBC</acronym>
Standard. Standard.
A call to postgresql.Connection permits a class that extends this A call to postgresql.Connection permits a class that extends this
class to be associated with a named type. This is how the class to be associated with a named type. This is how the
...@@ -2550,7 +2577,8 @@ while another one is receiving results, and this would be a bad thing ...@@ -2550,7 +2577,8 @@ while another one is receiving results, and this would be a bad thing
for the database engine. for the database engine.
PostgreSQL 6.4, brings thread safety to the entire driver. Standard PostgreSQL 6.4, brings thread safety to the entire driver. Standard
<acronym>JDBC</acronym> was thread safe in 6.3.x, but the Fastpath <acronym>API</acronym> wasn't. <acronym>JDBC</acronym> was thread safe in 6.3.x, but the Fastpath
<acronym>API</acronym> wasn't.
So, if your application uses multiple threads (which most decent ones So, if your application uses multiple threads (which most decent ones
would), then you don't have to worry about complex schemes to ensure would), then you don't have to worry about complex schemes to ensure
...@@ -2614,3 +2642,20 @@ document, and also includes precompiled drivers for v6.4, and earlier. ...@@ -2614,3 +2642,20 @@ document, and also includes precompiled drivers for v6.4, and earlier.
</para> </para>
</sect1> </sect1>
</chapter> </chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/CATALOG"
sgml-local-ecat-files:nil
End:
--></book>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment