Greetings, the attached patch will extend the JDBCStore configuration possibilities to allow setting of all (arbitrary in fact) Commons DBCP configuration properties and to pass properties directly to the underlying JDBC-driver.
Commons DBCP have a plethora of options that can be studied in detail here: http://jakarta.apache.org/commons/dbcp/configuration.html
This patch addresses the following issues:
1. Cannot set (or control usage of) the DBCP connection validation query
After applying the patch, any DBCP properties like validationQuery, testOnBorrow, testWhileIdle, can be set in the Slide domain configuration with a "dbcp." prefix.
Example nodestore config for Oracle:
<parameter name="dbcpPooling">true</parameter> <parameter name="dbcp.maxWait">5000</parameter> <parameter name="dbcp.maxActive">50</parameter> <parameter name="dbcp.maxIdle">25</parameter> <parameter name="dbcp.validationQuery">SELECT 1 FROM DUAL</parameter> <parameter name="dbcp.testOnBorrow">true</parameter> <parameter name="dbcp.testOnReturn">false</parameter> <parameter name="dbcp.testWhileIdle">false</parameter>
2. Cannot pass properties to the JDBC-driver
(With MySQL it was previously possible, but not all drivers support extending the JDBC URL with ?property=value. Oracle for one does not.)
After applying the patch, it is now possible to pass a list of JDBC-driver properties from the Slide domain configuration through the "dbcp.connectionProperties" setting. The format is semicolon separated, eg "defaultRowPrefetch=30;disableDefineColumnType=true" for setting Oracle row-prefetching to 30 rows per server rountrip and switching to the Oracle-recommended default of disableDefineColumnType=true for the Oracle 10 JDBC thin-driver.
3. Shutting down the Slide JDBCStore does not shutdown DBCP pool
After applying the patch, the DBCP pool will be decommisioned on the disconnect() call on a clean Slide exit (it can be reconnected by calling connect() and the isConnected semantics is updated so that connectIfNeeded will call connect() if the pool is down).
4. Synchronization issue when using DBCP in multiple JDBCStore- instances within a Domain
Naming the DBCP connection pool with System.identityHashCode is not guaranteed to be unique withing the Domain.
After applying the patch, the JDBCStore will use the DBPC BasicDataSource with a Store-local (protected instance var) reference and it will be guaranteed that each Store instance uses a unique DBCP DataSource/pool instance.
Some of the DriverManager deadlock issues reported on the list and in bugzilla should be addressed by #1 (set dbcp.maxWait != -1 to prevent waiting forever for a new connection) and #4 above (.
If the patch gets applied I will do some more extensive testing with a newly built Slide from CVS and see if we can close some bugzilla issues as a result.
I have tested the patch with a real-world multithreaded application using several Connection instances simultaneously and two different JDBCStore configurations for different stores in the domain (one fully JDBC-based and one with descriptors in DB and content in the ContextTxFileContentStore).
Test were done with Oracle9i RDBMS, Oracle thin JDBC driver and JDBCStore (with patch applied) configured with OracleRDBMSAdapter.
A previous patch posted here, but not yet applied, was also applied on the local source. (See http://www.mail-archive.com/slide-dev@jakarta.apache.org/msg14543.html)
The patch is in unified format and created against the trunk, updated from CVS around lunchtime today.
I have also updated the forrest xdoc for the J2EE/JDBC store HOWTO and the patch includes this change and the resulting generated site-doc HTML.
Regards, Martin
Index: src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java =================================================================== RCS file: /home/cvspublic/jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java,v retrieving revision 1.23 diff -u -r1.23 JDBCStore.java --- src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java 1 Oct 2004 15:20:09 -0000 1.23 +++ src/stores/org/apache/slide/store/impl/rdbms/JDBCStore.java 27 Apr 2005 16:23:23 -0000 @@ -5,7 +5,7 @@ * * ==================================================================== * - * Copyright 1999-2002 The Apache Software Foundation + * Copyright 1999-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,15 +28,17 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Hashtable; +import java.util.Iterator; +import java.util.Properties; -import org.apache.commons.dbcp.DriverManagerConnectionFactory; -import org.apache.commons.dbcp.PoolableConnectionFactory; -import org.apache.commons.dbcp.PoolingDriver; -import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.dbcp.BasicDataSource; +import org.apache.commons.dbcp.BasicDataSourceFactory; import org.apache.slide.common.NamespaceAccessToken; import org.apache.slide.common.ServiceInitializationFailedException; import org.apache.slide.common.ServiceParameterErrorException; import org.apache.slide.common.ServiceParameterMissingException; +import org.apache.slide.common.ServiceDisconnectionFailedException; +import org.apache.slide.common.ServiceConnectionFailedException; import org.apache.slide.store.ContentStore; import org.apache.slide.store.LockStore; import org.apache.slide.store.NodeStore; @@ -47,29 +49,44 @@ /** * Store implementation that is able to store all information (like structure, - * locks and content) in a JDBC-aware relational database system. As this - * implementation only uses a single connection to the database, it does not - * work properly in production environments that require simultaneous access by - * multiple clients. + * locks and content) in a JDBC-aware relational database system. + * <p> + * Set the [EMAIL PROTECTED] #CONF_KEY_DBCP_ENABLED} configuration attribute to true + * to enable Commons DBCP connection pooling. * * @version $Revision: 1.23 $ + * @see <a href="http://jakarta.apache.org/slide/howto-j2eestore.html">Slide Configuration HOWTO</a> + * for complete configuration information */ public class JDBCStore extends AbstractRDBMSStore implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore { - public static final String DBCP_URL = "jdbc:apache:commons:dbcp"; + /** Configuration key: "true"=use Commons DBCP connection pooling. */ + protected static final String CONF_KEY_DBCP_ENABLED = "dbcpPooling"; - public static final String TRANSACTION_NONE = "NONE"; - public static final String TRANSACTION_READ_UNCOMMITTED = "READ_UNCOMMITTED"; - public static final String TRANSACTION_READ_COMMITTED = "READ_COMMITTED"; - public static final String TRANSACTION_REPEATABLE_READ = "REPEATABLE_READ"; - public static final String TRANSACTION_SERIALIZABLE = "SERIALIZABLE"; + /** + * Configuration key prefix for all Commons DBCP settings. + * To pass properties directly to the underlying JDBC-driver, + * use the <b>[EMAIL PROTECTED] #CONF_KEY_DBCP_PREFIX}.connectionProperties</b> + * configuration property in your Slide domain configuration, + * set the value to semicolon-separated name=value pairs + * (eg "cachePreparedStatements=true;rowPrefetchSize=50;foo=bar"). + * @see <a href="http://jakarta.apache.org/commons/dbcp/configuration.html"> + * Commons DBCP website</a> for info about possible settings + */ + protected static final String CONF_KEY_DBCP_PREFIX = "dbcp."; + + protected static final String TRANSACTION_NONE = "NONE"; + protected static final String TRANSACTION_READ_UNCOMMITTED = "READ_UNCOMMITTED"; + protected static final String TRANSACTION_READ_COMMITTED = "READ_COMMITTED"; + protected static final String TRANSACTION_REPEATABLE_READ = "REPEATABLE_READ"; + protected static final String TRANSACTION_SERIALIZABLE = "SERIALIZABLE"; public static final int DEFAUT_ISOLATION_LEVEL = Connection.TRANSACTION_READ_COMMITTED; protected static String isolationLevelToString(int isolationLevel) { - String levelString; + final String levelString; switch (isolationLevel) { case Connection.TRANSACTION_NONE : levelString = TRANSACTION_NONE; @@ -95,50 +112,48 @@ } protected static int stringToIsolationLevelToString(String levelString) { + final int transactionIsolationLevel; if (TRANSACTION_NONE.equals(levelString)) { - return Connection.TRANSACTION_NONE; + transactionIsolationLevel = Connection.TRANSACTION_NONE; } else if (TRANSACTION_READ_UNCOMMITTED.equals(levelString)) { - return Connection.TRANSACTION_READ_UNCOMMITTED; + transactionIsolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED; } else if (TRANSACTION_READ_COMMITTED.equals(levelString)) { - return Connection.TRANSACTION_READ_COMMITTED; + transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED; } else if (TRANSACTION_REPEATABLE_READ.equals(levelString)) { - return Connection.TRANSACTION_REPEATABLE_READ; + transactionIsolationLevel = Connection.TRANSACTION_REPEATABLE_READ; } else if (TRANSACTION_SERIALIZABLE.equals(levelString)) { - return Connection.TRANSACTION_SERIALIZABLE; + transactionIsolationLevel = Connection.TRANSACTION_SERIALIZABLE; } else { - return -1; + transactionIsolationLevel = -1; } + return transactionIsolationLevel; } // ----------------------------------------------------- Instance Variables - /** - * Driver class name. - */ + /** JDBC driver class name. */ protected String driver; - /** - * Connection URL. - */ + /** JDBC connection URL. */ protected String url; - /** - * User name. - */ - protected String user = ""; + /** Database user-name. */ + protected String user; - /** - * Password. - */ - protected String password = ""; + /** Database password. */ + protected String password; - protected boolean useDbcpPooling = false; + /** Transaction isolation level. */ + protected int isolationLevel; - protected String dbcpPoolName = "dbcpPool" + System.identityHashCode(this); + /** Switch for enabling Commons DBCP connection pooling. */ + protected boolean useDbcpPooling; - protected int maxPooledConnections = -1; + /** Properties set from Store configuration, to be used with DBCP. */ + protected Properties dbcpProperties; - protected int isolationLevel = DEFAUT_ISOLATION_LEVEL; + /** Connection pool DataSource (set only if using Commons DBCP). */ + protected BasicDataSource dbcpDataSource; // -------------------------------------------------------- Service Methods @@ -174,17 +189,21 @@ } // User name + user = ""; value = (String) parameters.get("user"); if (value != null) { user = value; } // Password + password = ""; value = (String) parameters.get("password"); if (value != null) { password = value; } + // Transaction isolation level + isolationLevel = DEFAUT_ISOLATION_LEVEL; value = (String) parameters.get("isolation"); if (value != null) { isolationLevel = stringToIsolationLevelToString(value); @@ -208,85 +227,75 @@ } } - value = (String) parameters.get("dbcpPooling"); + // Connection pooling + useDbcpPooling = false; + value = (String) parameters.get(CONF_KEY_DBCP_ENABLED); if (value != null) { useDbcpPooling = "true".equals(value); } if (useDbcpPooling) { - value = (String) parameters.get("maxPooledConnections"); - if (value != null) { - try { - maxPooledConnections = Integer.parseInt(value); - } catch (NumberFormatException nfe) { - getLogger().log( - "Could not set maximum pooled connections, parameter must be integer", - LOG_CHANNEL, - Logger.WARNING); + // Set up configuration properties to be used with Commons DBCP + dbcpProperties = getDbcpPoolProperties(parameters); - } - } + // Add driver and logon information + dbcpProperties.put("driverClassName", driver); + dbcpProperties.put("url", url); + dbcpProperties.put("username", user); + dbcpProperties.put("password", password); + + // Set TX isolation level + final String isolationLevelString; + isolationLevelString = isolationLevelToString(isolationLevel); + dbcpProperties.put("defaultTransactionIsolation", + isolationLevelString); + + // Turn off autocommit + dbcpProperties.put("defaultAutoCommit", + String.valueOf(Boolean.FALSE)); } super.setParameters(parameters); } /** - * Initializes driver. + * Initializes this store. * <p/> - * Occurs in four steps : - * <li>Driver class is loaded</li> - * <li>Driver is instantiated</li> - * <li>Driver registration in the driver manager</li> - * <li>Creation of the basic tables, if they didn't exist before</li> - * - * @exception ServiceInitializationFailedException Throws an exception - * if the data source has already been initialized before + * If Commons DBCP is used, initialization is done by: + * <ol> + * <li>Loading JDBC-driver class (and running static initializers)</li> + * </ol> + * DBCP will handled DriverManager registration internally, which will + * (together with further initialization of Connection pool) occur in + * the [EMAIL PROTECTED] #connect} method. + * <p/> + * Otherwise (ie not using DBCP), initialization is done by: + * <ol> + * <li>Loading JDBC-driver class (and running static initializers)</li> + * <li>Instantiating Driver instance</li> + * <li>Driver registration in the JDBC DriverManager</li> + * </ol> + * + * @exception ServiceInitializationFailedException if JDBC driver + * classloading or registration fails */ public synchronized void initialize(NamespaceAccessToken token) throws ServiceInitializationFailedException { // XXX might be done already in setParameter if (!alreadyInitialized) { try { - // Loading and registering driver + // Load driver class and force static init getLogger().log("Loading and registering driver '" + driver + "'", LOG_CHANNEL, Logger.INFO); - Class driverClass = Class.forName(driver); - Driver driverInstance = (Driver) driverClass.newInstance(); - String levelString = isolationLevelToString(isolationLevel); + final ClassLoader cl = Thread.currentThread().getContextClassLoader(); + final Class driverClass = Class.forName(driver, true, cl); - getLogger().log("Setting isolation level '" + levelString + "'", LOG_CHANNEL, Logger.INFO); - - // use DBCP pooling if enabled + // Use Commons DBCP pooling if enabled if (useDbcpPooling) { getLogger().log("Using DBCP pooling", LOG_CHANNEL, Logger.INFO); - GenericObjectPool connectionPool = new GenericObjectPool(null); - if (maxPooledConnections != -1) { - connectionPool.setMaxActive(maxPooledConnections); - } - getLogger().log( - "Number of connections set to " + connectionPool.getMaxActive(), - LOG_CHANNEL, - Logger.INFO); - - DriverManagerConnectionFactory connectionFactory = - new DriverManagerConnectionFactory(url, user, password); - new PoolableConnectionFactory( - connectionFactory, - connectionPool, - // TODO switching on pooling of prepared statements causes problems with closing of connections - // switched off for now -// new StackKeyedObjectPoolFactory(), - null, - null, - false, - false, - isolationLevel); - PoolingDriver driver = new PoolingDriver(); - driver.registerPool(dbcpPoolName, connectionPool); - // already done when loding PoolingDriver class - // DriverManager.registerDriver(driver); } else { + // Register Driver instance with JDBC DriverManager + final Driver driverInstance = (Driver) driverClass.newInstance(); DriverManager.registerDriver(driverInstance); getLogger().log("Not using DBCP pooling", LOG_CHANNEL, Logger.WARNING); } @@ -300,18 +309,68 @@ alreadyInitialized = true; } } + } + public void connect() throws ServiceConnectionFailedException { + super.connect(); + if (useDbcpPooling) { + try { + dbcpDataSource = (BasicDataSource) + BasicDataSourceFactory.createDataSource(dbcpProperties); + + // The BasicDataSource has lazy initialization + // borrowing a connection will start the DataSource + // and make sure it is configured correctly. + final Connection conn = dbcpDataSource.getConnection(); + conn.close(); + } catch (Exception e) { + getLogger().log( + "Initialization of connection pool failed (" + + e.getMessage() + ")", + LOG_CHANNEL, Logger.ERROR); + throw new ServiceConnectionFailedException(this, e); + } finally { + logConnectionPoolStatistics(); + } + } + } + + public boolean isConnected() { + if (useDbcpPooling) { + return dbcpDataSource != null; + } + return super.isConnected(); + } + + public void disconnect() throws ServiceDisconnectionFailedException { + if (useDbcpPooling) { + if (dbcpDataSource != null) { + try { + dbcpDataSource.close(); + } catch (SQLException e) { + getLogger().log( + "Decomissioning of connection pool failed (" + + e.getMessage() + ")", + LOG_CHANNEL, Logger.ERROR); + throw new ServiceDisconnectionFailedException(this, e); + } + dbcpDataSource = null; + } + } + super.disconnect(); } protected Connection getNewConnection() throws SQLException { + final Connection connection; - Connection connection; if (useDbcpPooling) { try { - connection = DriverManager.getConnection(DBCP_URL + ":" + dbcpPoolName); + connection = dbcpDataSource.getConnection(); } catch (SQLException e) { getLogger().log("Could not create connection. Reason: " + e, LOG_CHANNEL, Logger.EMERGENCY); throw e; + } finally { + logConnectionPoolStatistics(); } } else { try { @@ -335,7 +394,6 @@ if (connection.getAutoCommit()) { connection.setAutoCommit(false); } - } return connection; @@ -344,4 +402,73 @@ protected boolean includeBranchInXid() { return false; } + + /** + * Returns properties to be used with Commons DBCP BasicDataSource. + * + * @param parameters the configuration parameters for this store + * @return properties to pass to the DBCP datasource, set up + * according to store configuration parameters (never null) + */ + protected Properties getDbcpPoolProperties(Hashtable parameters) { + final Properties props = new Properties(); + + if (parameters == null) { + return props; + } + + // Set all DBCP properties + final int prefixSkipchars = CONF_KEY_DBCP_PREFIX.length(); + final Iterator keyIter = parameters.keySet().iterator(); + while (keyIter.hasNext()) { + final String key = String.valueOf(keyIter.next()); + if (key.startsWith(CONF_KEY_DBCP_PREFIX)) { + final String property = key.substring(prefixSkipchars); + final Object value = parameters.get(key); + if (value != null) { + props.put(property, value.toString()); + } + } + } + + int intValue = -2; // use -2, since -1 and 0 are magic numbers already + // Old maxActive setting ("maxPooledConnections") have priority + final Object value = parameters.get("maxPooledConnections"); + if (value != null) { + try { + intValue = Integer.parseInt(value.toString()); + } catch (NumberFormatException e) { + getLogger().log("Could not parse configuration setting " + + "maxPooledConnections, parameter must be integer", + LOG_CHANNEL, + Logger.WARNING); + } + } + if (intValue > -2) { + getLogger().log("The maxPooledConnections configuration " + + "attribute is deprecated, please use " + + CONF_KEY_DBCP_PREFIX + "maxActive instead.", + LOG_CHANNEL, + Logger.WARNING); + props.put("maxActive", value.toString()); + } + return props; + } + + /** + * Log statistics for Connection pool + * (when using Commons DBCP and log level DEBUG). + */ + protected void logConnectionPoolStatistics() { + // Avoid String concatenation if message is not going to be logged + if (useDbcpPooling && getLogger().getLoggerLevel(LOG_CHANNEL) >= Logger.DEBUG) { + getLogger().log("Connection pool stats: active: " + + dbcpDataSource.getNumActive() + " (max: " + + dbcpDataSource.getMaxActive() + "), idle: " + + dbcpDataSource.getNumIdle() + "(max: " + + dbcpDataSource.getMaxIdle() + ")", + LOG_CHANNEL, Logger.DEBUG); + } + } + } Index: src/doc/howto-j2eestore.xml =================================================================== RCS file: /home/cvspublic/jakarta-slide/src/doc/howto-j2eestore.xml,v retrieving revision 1.9 diff -u -r1.9 howto-j2eestore.xml --- src/doc/howto-j2eestore.xml 17 Sep 2004 08:05:23 -0000 1.9 +++ src/doc/howto-j2eestore.xml 27 Apr 2005 16:23:23 -0000 @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="ISO-8859-1"?> - +<!-- Version: $Id$ --> <document> - <properties> + <properties> <author email="[EMAIL PROTECTED]">Colin Britton</author> <author email="[EMAIL PROTECTED]">Oliver Zeigermann</author> + <author email="[EMAIL PROTECTED]">Martin Kalén</author> <title>J2EE/JDBC Store Howto</title> </properties> @@ -12,32 +13,32 @@ <section name="Configuring Slide"> <p>In order to use the J2EE stores, the Domain.xml file needs to contain the following configuration for the store: -<pre> -<definition> - <store name="j2ee"> - <nodestore classname="org.apache.slide.store.impl.rdbms.J2EEStore"> - <parameter name="datasource">jdbc/mtx</parameter> - <parameter name="adapter">org.apache.slide.store.impl.rdbms.MySqlRDBMSAdapter</parameter> - <parameter name="compress">false</parameter> - </nodestore> - <securitystore> - <reference store="nodestore"/> - </securitystore> - <lockstore> - <reference store="nodestore"/> - </lockstore> - <revisiondescriptorsstore> - <reference store="nodestore"/> - </revisiondescriptorsstore> - <revisiondescriptorstore> - <reference store="nodestore"/> - </revisiondescriptorstore> - <contentstore> - <reference store="nodestore"/> - </contentstore> - </store> - <scope match="/" store="j2ee"/> -</definition> +<pre><![CDATA[ +<definition> + <store name="j2ee"> + <nodestore classname="org.apache.slide.store.impl.rdbms.J2EEStore"> + <parameter name="datasource">jdbc/mtx</parameter> + <parameter name="adapter">org.apache.slide.store.impl.rdbms.MySqlRDBMSAdapter</parameter> + <parameter name="compress">false</parameter> + </nodestore> + <securitystore> + <reference store="nodestore"/> + </securitystore> + <lockstore> + <reference store="nodestore"/> + </lockstore> + <revisiondescriptorsstore> + <reference store="nodestore"/> + </revisiondescriptorsstore> + <revisiondescriptorstore> + <reference store="nodestore"/> + </revisiondescriptorstore> + <contentstore> + <reference store="nodestore"/> + </contentstore> + </store> + <scope match="/" store="j2ee"/> +</definition>]]> </pre> where the adapter determines which database adapter you want to use. In this case you configured the MySQL adapter. Most adapters have a parameter to decide whether the content shall be compressed (zipped) before storing to the database. This <em>might</em> @@ -49,53 +50,56 @@ <p>If your store is not configured using a datasource looked up using JNDI you will have to provide more information to Slide like this for example: -<pre> - -<definition> -<store name="MySqlStore"> - <nodestore classname="org.apache.slide.store.impl.rdbms.JDBCStore"> - <parameter name="adapter">org.apache.slide.store.impl.rdbms.MySqlRDBMSAdapter</parameter> - <parameter name="driver">com.mysql.jdbc.Driver</parameter> - <parameter name="url">jdbc:mysql://localhost/Slide</parameter> - <parameter name="user">root</parameter> - <parameter name="dbcpPooling">true</parameter> - <parameter name="maxPooledConnections">10</parameter> - <parameter name="isolation">SERIALIZABLE</parameter> - <parameter name="compress">false</parameter> - </nodestore> - <contentstore> - <reference store="nodestore" /> - </contentstore> - <securitystore> - <reference store="nodestore" /> - </securitystore> - <lockstore> - <reference store="nodestore" /> - </lockstore> - <revisiondescriptorsstore> - <reference store="nodestore" /> - </revisiondescriptorsstore> - <revisiondescriptorstore> - <reference store="nodestore" /> - </revisiondescriptorstore> - </store> - <scope match="/" store="MySqlStore"/> -</definition> +<pre><![CDATA[ +<definition> +<store name="MySqlStore"> + <nodestore classname="org.apache.slide.store.impl.rdbms.JDBCStore"> + <parameter name="adapter">org.apache.slide.store.impl.rdbms.MySqlRDBMSAdapter</parameter> + <parameter name="driver">com.mysql.jdbc.Driver</parameter> + <parameter name="url">jdbc:mysql://localhost/Slide</parameter> + <parameter name="user">root</parameter> + <parameter name="isolation">SERIALIZABLE</parameter> + <parameter name="compress">false</parameter> + <parameter name="dbcpPooling">true</parameter> + <parameter name="dbcp.maxActive">10</parameter> + <parameter name="dbcp.validationQuery">SELECT 1</parameter> + <parameter name="dbcp.maxWait">5000</parameter> + <!-- Set arbitrary (semicolon-separated) properties for the JDBC-driver: + <parameter name="dbcp.connectionProperties">cachePrepStmts=true;prepStmtCacheSqlLimit=512</parameter> --> + </nodestore> + <contentstore> + <reference store="nodestore" /> + </contentstore> + <securitystore> + <reference store="nodestore" /> + </securitystore> + <lockstore> + <reference store="nodestore" /> + </lockstore> + <revisiondescriptorsstore> + <reference store="nodestore" /> + </revisiondescriptorsstore> + <revisiondescriptorstore> + <reference store="nodestore" /> + </revisiondescriptorstore> + </store> + <scope match="/" store="MySqlStore"/> +</definition>]]> </pre> You can see you will have to configure you driver, the connection url and the user for the database. You can optionally configure if connection pooling using DBCP is enabled or not and if enabled how many connections shall be pooled. If you want you can -also choose the isolation level of your database. <code>SERIALIZABLE</code> is a safe choice, but - depending on you database - at least <code>READ COMMITTED</code> +also choose the isolation level of your database. <code>SERIALIZABLE</code> is a safe choice, but - depending on you database - at least <code>READ COMMITTED</code> is recommended. </p> </section> <section name="Configuring Tomcat 4.x"> - <p>In order to use this with Tomcat you need to setup the datasource. - Instructions for this are at + <p>In order to use this with Tomcat you need to setup the datasource. + Instructions for this are at <a href="http://jakarta.apache.org/tomcat/tomcat-4.0-doc/jndi-resources-howto.html"> http://jakarta.apache.org/tomcat/tomcat-4.0-doc/jndi-resources-howto.html</a>. </p> - <p>If you follow the above instructions you will make changes similar to the + <p>If you follow the above instructions you will make changes similar to the following in web.xml and server.xml.</p> <p> <pre> Index: docs/howto-j2eestore.html =================================================================== RCS file: /home/cvspublic/jakarta-slide/docs/howto-j2eestore.html,v retrieving revision 1.24 diff -u -r1.24 howto-j2eestore.html --- docs/howto-j2eestore.html 31 Dec 2004 04:51:04 -0000 1.24 +++ docs/howto-j2eestore.html 27 Apr 2005 16:23:23 -0000 @@ -6,6 +6,8 @@ <meta value="[EMAIL PROTECTED]" name="email"> <meta value="Oliver Zeigermann" name="author"> <meta value="[EMAIL PROTECTED]" name="email"> +<meta value="Martin Kalén" name="author"> +<meta value="[EMAIL PROTECTED]" name="email"> </head> <body vlink="#525D76" alink="#525D76" link="#525D76" text="#000000" bgcolor="#ffffff"> <table cellspacing="4" width="100%" border="0"> @@ -191,7 +193,6 @@ <p>If your store is not configured using a datasource looked up using JNDI you will have to provide more information to Slide like this for example: <pre> - <definition> <store name="MySqlStore"> <nodestore classname="org.apache.slide.store.impl.rdbms.JDBCStore"> @@ -199,10 +200,14 @@ <parameter name="driver">com.mysql.jdbc.Driver</parameter> <parameter name="url">jdbc:mysql://localhost/Slide</parameter> <parameter name="user">root</parameter> - <parameter name="dbcpPooling">true</parameter> - <parameter name="maxPooledConnections">10</parameter> <parameter name="isolation">SERIALIZABLE</parameter> <parameter name="compress">false</parameter> + <parameter name="dbcpPooling">true</parameter> + <parameter name="dbcp.maxActive">10</parameter> + <parameter name="dbcp.validationQuery">SELECT 1</parameter> + <parameter name="dbcp.maxWait">5000</parameter> + <!-- Set arbitrary (semicolon-separated) properties for the JDBC-driver: + <parameter name="dbcp.connectionProperties">cachePrepStmts=true;prepStmtCacheSqlLimit=512</parameter> --> </nodestore> <contentstore> <reference store="nodestore" /> @@ -225,7 +230,7 @@ </pre> You can see you will have to configure you driver, the connection url and the user for the database. You can optionally configure if connection pooling using DBCP is enabled or not and if enabled how many connections shall be pooled. If you want you can -also choose the isolation level of your database. <code>SERIALIZABLE</code> is a safe choice, but - depending on you database - at least <code>READ COMMITTED</code> +also choose the isolation level of your database. <code>SERIALIZABLE</code> is a safe choice, but - depending on you database - at least <code>READ COMMITTED</code> is recommended. </p> @@ -243,13 +248,13 @@ <td> <blockquote> -<p>In order to use this with Tomcat you need to setup the datasource. - Instructions for this are at +<p>In order to use this with Tomcat you need to setup the datasource. + Instructions for this are at <a href="http://jakarta.apache.org/tomcat/tomcat-4.0-doc/jndi-resources-howto.html"> http://jakarta.apache.org/tomcat/tomcat-4.0-doc/jndi-resources-howto.html</a>. </p> -<p>If you follow the above instructions you will make changes similar to the +<p>If you follow the above instructions you will make changes similar to the following in web.xml and server.xml.</p> <p>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]