342 lines
16 KiB
XML
342 lines
16 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
/*
|
|
* Copyright 2002-2008 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
-->
|
|
<chapter xml:id="dao" xmlns="http://docbook.org/ns/docbook" version="5">
|
|
<title>DAO support</title>
|
|
|
|
<section xml:id="dao-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>Spring promotes the use of data access interfaces in your
|
|
application architecture. These interfaces encapsulate the storage and
|
|
retrieval of data and objects specific to your business domain without
|
|
reference to a specific persistence API. Within a layered architecture,
|
|
the service layer is typically responsible for coordinating responses to a
|
|
particular business request and it delegates any persistence related
|
|
activities to objects that implement these data access interfaces. These
|
|
objects are commonly referred to as DAOs (Data Access Objects) and the
|
|
architectural layer as a DAL (Data Access Layer).</para>
|
|
|
|
<para>The benefits of using DAOs in your application are increased
|
|
portability across persistence technology and ease of testing. Testing is
|
|
more easily facilitated because a mock or stub implementation of the data
|
|
access interface can be easily created in a NUnit test so that service
|
|
layer functionality can be tested without any dependency on the database.
|
|
This is beneficial because tests that rely on the database are usually
|
|
hard to set up and tear down and also are impractical for testing
|
|
exceptional behavior.</para>
|
|
|
|
<para>The Data Access Object (DAO) support in Spring is aimed at making it
|
|
easy to work with data access technologies like ADO.NET and NHibernate in
|
|
a standardized way. Spring provides two central pieces of functionality to
|
|
meet this goal. The first is providing a common exception hierarchy across
|
|
providers and the second is providing base DAOs classes that raise the
|
|
level of abstraction when performing common ADO.NET operations. This
|
|
allows one to switch between the aforementioned persistence technologies
|
|
fairly easily and it also allows one to code without worrying about
|
|
catching exceptions that are specific to each technology.</para>
|
|
</section>
|
|
|
|
<section xml:id="dao-exceptions">
|
|
<title>Consistent exception hierarchy</title>
|
|
|
|
<para>Database exceptions in the ADO.NET API are not consistent across
|
|
providers. The .NET 1.1 BCL did not provide a common base class for
|
|
ADO.NET exceptions. As such you were required to handle exceptions
|
|
specific to each provider such as
|
|
<literal>System.Data.SqlClient.SqlException</literal> or
|
|
<literal>System.Data.OracleClient.OracleException</literal>. The .NET
|
|
2.0 BCL improved in this regard by introducing a common base class for
|
|
exceptions, <literal>System.Data.Common.DbException</literal>. However
|
|
the common DbException is not very portable either as it provides a vendor
|
|
specific error code as the underlying piece of information as to what went
|
|
wrong. This error code is different across providers for the same
|
|
conceptual error, such as a violation of data integrity or providing bad
|
|
SQL grammar.</para>
|
|
|
|
<para>To promote writing portable and descriptive exception handling code
|
|
Spring provides a convenient translation from technology specific
|
|
exceptions like <literal>System.Data.SqlClient.SqlException</literal>
|
|
or <literal>System.Data.OracleClient.OracleException</literal> to its
|
|
own exception hierarchy with the
|
|
<literal>Spring.Dao.DataAccessException</literal> as the root
|
|
exception. These exceptions wrap the original exception so there is never
|
|
any risk that one might lose any information as to what might have gone
|
|
wrong.</para>
|
|
|
|
<para>In addition to exceptions from ADO.NET providers, Spring can also
|
|
wrap NHibernate-specific exceptions.. This allows one to handle most
|
|
persistence exceptions, which are non-recoverable, only in the appropriate
|
|
layers, without boilerplate using or catch and throw blocks, and exception
|
|
declarations. As mentioned above, ADO.NET exceptions (including
|
|
database-specific dialects) are also converted to the same hierarchy,
|
|
meaning that one can perform some operations with ADO.NET within a
|
|
consistent programming model. The above holds true for the various
|
|
template-based versions of the ORM access framework.</para>
|
|
|
|
<para>The exception hierarchy that Spring uses is outlined in the
|
|
following image:</para>
|
|
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata fileref="images/DataAccessException.gif" />
|
|
</imageobject>
|
|
</mediaobject>
|
|
|
|
<para>(Please note that the class hierarchy detailed in the above image
|
|
shows only a subset of the whole, rich,
|
|
<literal>DataAccessException</literal> hierarchy.)</para>
|
|
|
|
<para>The exception translation functionality is in the namespace
|
|
Spring.Data.Support and is based on the interface
|
|
<literal>IAdoExceptionTranslator</literal> shown below.</para>
|
|
|
|
<programlisting language="csharp">public interface IAdoExceptionTranslator
|
|
{
|
|
DataAccessException Translate( string task, string sql, Exception exception );
|
|
}</programlisting>
|
|
|
|
<para>The arguments to the translator are a task string providing a
|
|
description of the task being attempted, the SQL query or update that
|
|
caused the problem, and the 'raw' exception thrown by the ADO.NET data
|
|
provider. The additional task and SQL arguments allow for very readable
|
|
and clear error messages to be created when an exception occurs.</para>
|
|
|
|
<para>A default implementation,
|
|
<literal>ErrorCodeExceptionTranslator</literal>, is provided that uses the
|
|
error codes defined for each data provider in the file dbproviders.xml.
|
|
Refer to this file, an embedded resource in the Spring.Data assembly, for
|
|
the exact mappings of error codes to Spring DataAccessExceptions.</para>
|
|
|
|
<para>A common need is to modify the error codes that are map onto the
|
|
exception hierarchy. There are several ways to accomplish this
|
|
task.</para>
|
|
|
|
<para>One approach is to override the error codes that are defined in
|
|
<code>assembly://Spring.Data/Spring.Data.Common/dbproviders.xml</code>. By
|
|
default, the <link
|
|
linkend="dbprovider-dbprovider">DbProviderFactory</link> will look for
|
|
additional metadata for the IoC container it uses internally to define and
|
|
manage the DbProviders in a file named <literal>dbProviders.xml</literal>
|
|
located in the root runtime directory. (You can change this location, see
|
|
the documentation on <link lang=""
|
|
linkend="dbprovider-dbprovider">DbProvider</link> for more information.)
|
|
This is a standard Spring application context so all features, such as
|
|
<link
|
|
linkend="objects-factory-customizing-factory-postprocessors">ObjectFactoryPostProcessors</link>
|
|
are available and will be automatically applied. Defining a <link
|
|
linkend="objects-factory-overrideconfigurer">PropertyOverrideConfigurer</link>
|
|
in this additional configuration file will allow for you to override
|
|
specific property values defined in the embedded resource file. As an
|
|
example, the additional <literal>dbProviders.xml</literal> file shown
|
|
below will add the error code <literal>2601</literal> to the list of error
|
|
codes that map to a
|
|
<literal>DataIntegrityViolationException</literal>.</para>
|
|
|
|
<para><programlisting language="myxml"><objects xmlns='http://www.springframework.net'>
|
|
|
|
<alias name='SqlServer-2.0' alias='SqlServer2005'/>
|
|
|
|
<object name="appConfigPropertyOverride" type="Spring.Objects.Factory.Config.PropertyOverrideConfigurer, Spring.Core">
|
|
<property name="Properties">
|
|
<name-values>
|
|
<add key="SqlServer2005.DbMetadata.ErrorCodes.DataIntegrityViolationCodes"
|
|
value="544,2601,2627,8114,8115"/>
|
|
</name-values>
|
|
</property>
|
|
</object>
|
|
|
|
</objects></programlisting>The reason to define the alias is that <link
|
|
linkend="objects-factory-overrideconfigurer">PropertyOverrideConfigurer</link>
|
|
assumes a period <literal>(.)</literal> as the separator to pick out the
|
|
object name but the names of the objects in
|
|
<literal>dbProviders.xml</literal> have periods in them (i.e.
|
|
SqlServer-2.0 or System.Data.SqlClient). Creating an alias that has no
|
|
periods in the name is a workaround.</para>
|
|
|
|
<para>Another way to customize the mappings of error codes to exceptions
|
|
is to subclass <literal>ErrorCodeExceptionTranslator</literal> and
|
|
override the method, <literal>DataAccessException
|
|
TranslateException(string task, string sql, string errorCode, Exception
|
|
exception)</literal>. This will be called before referencing the metadata
|
|
to perform exception translation. The vendor specific error code provided
|
|
as a method argument has already been parsed out of the raw ADO.NET
|
|
exception. If you create your own specific subclass, then you should set
|
|
the property <literal>ExceptionTranslator</literal> on
|
|
<literal>AdoTemplate</literal> and
|
|
<literal>HibernateTemplate/HibernateTransactionManager</literal> to refer
|
|
to your custom implementation (unless you are using autowiring).</para>
|
|
|
|
<para>The third way is to write an implementation of
|
|
<literal>IAdoExceptionTranslator</literal> and set the property
|
|
<literal>FallbackTranslator</literal>'on
|
|
<literal>ErrorCodeExceptionTranslator</literal>. In this case you are
|
|
responsible for parsing our the vendor specific error code from the raw
|
|
ADO.NET exception. As with the case of subclassing
|
|
ErrorCodeExceptionTranslator, you will need to refer to this custom
|
|
exception translator when using <literal>AdoTemplate</literal> or
|
|
<literal>HibernateTemplate/HibernateTransactionManager</literal>.</para>
|
|
|
|
<para>The ordering of the exception translation processing is as follows.
|
|
The method TranslateException is called first, then the standard exception
|
|
translation logic, then the FallbackTranslator.</para>
|
|
|
|
<para>Note that you can use this API directly in your own Spring
|
|
independent data layer. If you are using Spring's ADO.NET abstraction
|
|
class, <literal>AdoTemplate</literal>, or
|
|
<literal>HibernateTemplate</literal>, the converted exceptions will be
|
|
thrown automatically. Somewhere in between these two cases is using
|
|
Spring's declarative transaction management features in .NET 2.0 with the
|
|
raw ADO.NET APIs and using <literal>IAdoExceptionTranslator</literal> in
|
|
your exception handling layer (which might be implemented in AOP using
|
|
Spring's exception translation aspect).</para>
|
|
|
|
<para>Some of the more common data access exceptions are described here.
|
|
Please refer to the API documentation for more details.</para>
|
|
|
|
<table>
|
|
<title>Common DataAccessExceptions</title>
|
|
|
|
<tgroup cols="2">
|
|
<colspec align="left" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Exception</entry>
|
|
|
|
<entry>Description</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>BadSqlGrammarException</entry>
|
|
|
|
<entry>Exception thrown when SQL specified is invalid.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>DataIntegrityViolationException</entry>
|
|
|
|
<entry>Exception thrown when an attempt to insert or update data
|
|
results in violation of an integrity constraint. For example,
|
|
inserting a duplicate key.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>PermissionDeniedDataAccessException</entry>
|
|
|
|
<entry>Exception thrown when the underling resource denied a
|
|
permission to access a specific element, such as a specific
|
|
database table.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>DataAccessResourceFailureException</entry>
|
|
|
|
<entry>Exception thrown when a resource fails completely, for
|
|
example, if we can't connect to a database.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>ConcurrentyFailureException</entry>
|
|
|
|
<entry>Exception thrown when a concurrency error occurs.
|
|
OptimisticLockingFailureException and
|
|
PessimisticLockingFailureException are subclasses. This is a
|
|
useful exception to catch and to retry the transaction again. See
|
|
Spring's <link linkend="retry-aspect">Retry Aspect</link> for an
|
|
AOP based solution.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>OptimisticLockingFailureException</entry>
|
|
|
|
<entry>Exception thrown when there an optimistic locking failure
|
|
occurs. The subclass ObjectOptimisticLockingFailureException can
|
|
be used to examine the Type and the IDof the object that failed
|
|
the optimistic locking.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>PessimisticLockingFailure</entry>
|
|
|
|
<entry>Exception thrown when a pessimistic locking failure
|
|
occures. Subclasses of this exception are
|
|
CannotAcquireLockException, CannotSerializeTransactionException,
|
|
and DeadlockLoserDataAccessException.</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>CannotAcquireLockException</entry>
|
|
|
|
<entry>Exception thrown when a lock can not be acquired, for
|
|
example during an update, i..e a select for update</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>CannotSerializeTransactionException</entry>
|
|
|
|
<entry>Exception thrown when a transaction can not be
|
|
serialized.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Consistent abstract classes for DAO support</title>
|
|
|
|
<para>To make it easier to work with a variety of data access technologies
|
|
such as ADO.NET, NHibernate, and iBatis.NET in a consistent way, Spring
|
|
provides a set of abstract DAO classes that one can extend. These abstract
|
|
classes have methods for providing the data source and any other
|
|
configuration settings that are specific to the technology one is
|
|
currently using.</para>
|
|
|
|
<para>DAO support classes:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>AdoDaoSupport</literal> - super class for ADO.NET
|
|
data access objects. Requires a
|
|
<literal>DbProvider</literal> to be provided; in turn,
|
|
this class provides a <literal>AdoTemplate</literal> instance
|
|
initialized from the supplied
|
|
<literal>DbProvider</literal> to subclasses. See the
|
|
documentation for <literal>AdoTemplate</literal> for more
|
|
information.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>HibernateDaoSupport</literal> - super class for
|
|
NHibernate data access objects. Requires a
|
|
<literal>ISessionFactory</literal> to be provided; in
|
|
turn, this class provides a <literal>HibernateTemplate</literal>
|
|
instance initialized from the supplied
|
|
<literal>SessionFactory</literal> to subclasses. Can
|
|
alternatively be initialized directly via a
|
|
<literal>HibernateTemplate</literal>, to reuse the latter's
|
|
settings like <literal>SessionFactory</literal>, flush
|
|
mode, exception translator, etc. This is contained in a download
|
|
separate from the main Spring.NET distribution.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</chapter> |