| S2Container.NET TOP page Transaction Control Transaction Attribute Local Transaction Using Microsoft Distributed Transaction Coordinator (MS DTC) System.Transactions Exceptions ## Transaction Contro Using S2Tx.NET, it is possible to apply an Aspect to manage transaction to a .NET object. Refer to Warnings before applying an aspect. S2Container.NET supports System.Transactions (.NET 2.0 or higher), local transaction, and MS DTC (Microsoft Distributed Transaction Coordinator). Following are transaction attributes available: ### Transaction Attributes Following Advice are defined in Tx.dicon (System.Transactions), LocalTx.dicon (local transaction), DTCTx.dicon (MS DTC).
Attribute | Component Name | Description
--- | --- | ---
Required | `LocalTx.RequiredTx` (local transaction) | Share if there is a transaction, and create a new transaction when necessary.
`DTCTx.RequiredTx` (MS DTC)
`Tx.RequiredTx` (System.Transactions)
RequiresNew | `LocalTx.RequiresNewTx` (local transaction) | Make new transaction create components independent of the current status of the context.
`DTCTx.RequiresNewTx` (MS DTC)
`Tx.RequiresNewTx` (System.Transactions)
Supported | `LocalTx.SupportedTx` (local transaction) | Share when transaction exists.
`DTCTx.SupportedTx` (MS DTC)
NotSupported | `Tx.NotSupportedTx` (local transaction) | Make context, which does not have transaction control, create component.
`DTCTx.NotSupportedTx` (MS DTC)
`Tx.NotSupportedTx` (System.Transactions)
### Local Transaction To use local transaction, retrieve a connection from Seasar.Extension.Tx.Impl.TxDataSource. DAO (Data Access Object) is not used because Advice(MethodInterceptor) manages opening and closing connections. Property of type Seasar.Extension.ADO.IDataSource is used to inject TxDataSource into DAO. Connection, transaction, command, parameter are created from dataSource. Following is an example of DAO interface and DAO implementation class. #### EmployeeDao.cs C#
    using System;
    using System.Data;
    using Seasar.Extension.ADO;

    namespace Seasar.Examples.Reference.LocalTx
    {
        // DAO interface to use EMP
        public interface IEmployeeDao
        {
            void Insert();
        }

        // DAO implementation class to use EMP
        public class EmployeeDaoImpl : IEmployeeDao
        {
            private IDataSource dataSource;

            // property to inject TxDataSource
            public IDataSource DataSource
            {
                set { dataSource = value; }
            }

            #region IEmployeeDao member

            public void Insert()
            {
                string sql = "insert into emp2 values(@empno, @ename, @deptnum)";

                using(IDbCommand cmd = dataSource.GetCommand(sql,
                          dataSource.GetConnection(), dataSource.GetTransaction()))
                {
                    cmd.Parameters.Add(dataSource.GetParameter("@empno", 99));
                    cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"));
                    cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31));
                    cmd.ExecuteNonQuery();
                    Console.WriteLine("Inserted employee");
                }
            }

            #endregion
        }
    }
VB.NET
    Imports System
    Imports System.Data
    Imports Seasar.Extension.ADO

    Namespace Seasar.Examples.Reference.LocalTx

       ' DAO interface to use EMP
       Public Interface IEmployeeDao
          Sub Insert()
       End Interface 'IEmployeeDao

       ' DAO implementation class to use EMP
       Public Class EmployeeDaoImpl
          Implements IEmployeeDao

          Private dataSource As IDataSource

          ' property to inject TxDataSource
          Public WriteOnly Property DataSource() As IDataSource
             Set(ByVal value As IDataSource)
                dataSource = value
             End Set
          End Property

          Public Sub Insert()

             Dim sql As String = "insert into emp2 values(@empno, @ename, @deptnum)"

             Dim cmd As IDbCommand = dataSource.GetCommand(sql, _
                dataSource.GetConnection(), dataSource.GetTransaction())
             Try
                cmd.Parameters.Add(dataSource.GetParameter("@empno", 99))
                cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"))
                cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31))
                cmd.ExecuteNonQuery()
                Console.WriteLine("Inserted employee")
             Finally
                cmd.Dispose()
             End Try
          End Sub
       End Class
    End Namespace
Class to executeIEmployeeDao #### LocalTxClient.cs C#
    using System;
    using Seasar.Framework.Container;
    using Seasar.Framework.Container.Factory;

    namespace Seasar.Examples.Reference.LocalTx
    {
        public class LocalTxClient
        {
            private static readonly String PATH
                    = "Seasar.Examples/Reference/LocalTx/LocalTxClient.dicon";

            public LocalTxClient() {}

            public void Main()
            {
                // create S2Container
                IS2Container container = S2ContainerFactory.Create(PATH);
                // initialize S2Container
                container.Init();

                // retrieve component to implement IEmployeeDao from S2Container
                IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));

                // insert employee
                dao.Insert();
            }
        }
    }
VB.NET
    Imports System
    Imports Seasar.Framework.Container
    Imports Seasar.Framework.Container.Factory

    Namespace Seasar.Examples.Reference.LocalTx

       Public Class LocalTxClient

          Private Shared PATH As [String] = _
             "Seasar.Examples/Reference/LocalTx/LocalTxClient.dicon"

          Public Sub New()
          End Sub

          Public Sub Main()

             ' create S2Container
             Dim container As IS2Container = S2ContainerFactory.Create(PATH)
             ' initialized S2Container
             container.Init()

             ' retrieve component to implement IEmployeeDao from S2Container
             Dim dao As IEmployeeDao = _
                CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao)

             ' insert employee
             dao.Insert()
          End Sub
       End Class
    End Namespace
Following is an example of a dicon file. To apply Required attribute transaction, aspect in EmployeeDaoImpl is set to LocalTx.Required. #### LocalTxClient.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components>
    <include path="Seasar.Examples/Tx.dicon" />
        <component name="LocalTxClient" class="Seasar.Examples.Reference.LocalTx.LocalTxClient" />

        <component class="Seasar.Examples.Reference.LocalTx.EmployeeDaoImpl">
            <aspect>LocalTx.RequiredTx</aspect>
        </component>
    </components>
#### Tx.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components namespace="LocalTx">
        <include path="Seasar.Examples/Ado.dicon" />

        <component name="RequiredTx" class="Seasar.Extension.Tx.TransactionInterceptor">
            <arg>
                <component class="Seasar.Extension.Tx.Impl.LocalRequiredTxHandler" />
            </arg>
        </component>

        ...

    </components>
#### Ado.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components namespace="Ado">

      <component name="SqlClient" class="Seasar.Extension.ADO.DataProvider">
        <property name="ConnectionType">"System.Data.SqlClient.SqlConnection"</property>
        <property name="CommandType">"System.Data.SqlClient.SqlCommand"</property>
        <property name="ParameterType">"System.Data.SqlClient.SqlParameter"</property>
        <property name="DataAdapterType">"System.Data.SqlClient.SqlDataAdapter"</property>
      </component>
      <component name="DataSource" class="Seasar.Extension.Tx.Impl.TxDataSource">
        <property name="DataProvider">SqlClient</property>
        <property name="ConnectionString">
    "Data Source=(local);Initial Catalog=s2dotnetdemo;Integrated Security=SSPI"
        </property>
      </component>

      <component class="Seasar.Extension.Tx.Impl.TransactionContext" />
    </components>
#### Result:
    DEBUG transaction began
    EMP inserted
    DEBUG transaction committed
### Using Microsoft Distributed Transaction Coordinator (MS DTC) MS DTC must be properly setup before using MS DTC. When MS DTC is used, connection do not have to be retrieved from TxDataSource, but to write source code that is not dependent on a data provider, connection, command, and parameter objects are created from Seasar.Extension.ADO.Impl.DataSourceImpl. When MS DTC is used, a transaction is maintained even if a connection is closed after each query. Following is an example of DAO interface and DAO implementation class. #### EmployeeDao.cs C#
    using System;
    using System.Data;
    using Seasar.Extension.ADO;

    namespace Seasar.Examples.Reference.DTCTx
    {
        // DAO interface to use EMP
        public interface IEmployeeDao
        {
            void Insert();
        }

        // DAO implementation class to use EMP
        public class EmployeeDaoImpl : IEmployeeDao
        {
            private IDataSource dataSource;

            // property to inject DataSourceImpl
            public IDataSource DataSource
            {
                set { dataSource = value; }
            }

            #region IEmployeeDao member

            public void Insert()
            {
                using(IDbConnection cn = dataSource.GetConnection())
                {
                    cn.Open();
                    string sql = "insert into emp2 values(@empno, @ename, @deptnum)";
                    using(IDbCommand cmd = dataSource.GetCommand(sql,cn))
                    {
                        cmd.Parameters.Add(dataSource.GetParameter("@empno", 99));
                        cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"));
                        cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31));
                        cmd.ExecuteNonQuery();
                        Console.WriteLine("inserted employee");
                    }
                }
            }

            #endregion
        }
    }
VB.NET
    Imports System
    Imports System.Data
    Imports Seasar.Extension.ADO

    Namespace Seasar.Examples.Reference.DTCTx

       ' DAO interface to use EMP
       Public Interface IEmployeeDao
          Sub Insert()
       End Interface

       ' DAO implementation class to use EMP
       Public Class EmployeeDaoImpl
          Implements IEmployeeDao

          Private dataSource As IDataSource

          ' property to inject DataSourceImpl
          Public WriteOnly Property DataSource() As IDataSource
             Set(ByVal value As IDataSource)
                dataSource = value
             End Set
          End Property

          Public Sub Insert()

             Dim cn As IDbConnection = dataSource.GetConnection()
             Try
                cn.Open()
                Dim sql As String = "insert into emp2 values(@empno, @ename, @deptnum)"
                Dim cmd As IDbCommand = dataSource.GetCommand(sql, cn)
                Try
                   cmd.Parameters.Add(dataSource.GetParameter("@empno", 99))
                   cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"))
                   cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31))
                   cmd.ExecuteNonQuery()
                   Console.WriteLine("inserted employee")
                Finally
                   cmd.Dispose()
                End Try
             Finally
                cn.Dispose()
             End Try

          End Sub

       End Class

    End Namespace
Class to execute IEmployeeDao is as follows: #### DTCTxClient.cs C#
    using System;
    using Seasar.Framework.Container;
    using Seasar.Framework.Container.Factory;

    namespace Seasar.Examples.Reference.DTCTx
    {
        public class DTCTxClient
        {
            private static readonly String PATH
                    = "Seasar.Examples/Reference/DTCTx/DTCTxClient.dicon";

            public DTCTxClient() {}

            public void Main()
            {
                // create S2Container
                IS2Container container = S2ContainerFactory.Create(PATH);
                // initialize S2Container
                container.Init();

                // retrieve component to implement IEmployeeDao from S2Container
                IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));

                // inserted employee
                dao.Insert();
            }
        }
    }
VB.NET
    Imports System
    Imports Seasar.Framework.Container
    Imports Seasar.Framework.Container.Factory

    Namespace Seasar.Examples.Reference.DTCTx

       Public Class DTCTxClient
          Private Shared PATH As [String] = _
             "Seasar.Examples/Reference/DTCTx/DTCTxClient.dicon"

          Public Sub New()
          End Sub

          Public Sub Main()

             ' create S2Container
             Dim container As IS2Container = S2ContainerFactory.Create(PATH)
             ' initialize S2Container
             container.Init()

             ' retrieve component to implement IEmployeeDao from S2Container
             Dim dao As IEmployeeDao = _
                CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao)

             ' insert employee
             dao.Insert()

          End Sub

       End Class

    End Namespace
Following is an example of a dicon file. To apply Required attribute transaction, aspect in EmployeeDaoImpl is set to DTCTx.RequiredTx. #### DTCTxClient.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components>
        <include path="Seasar.Examples/DTCTx.dicon" />

        <component name="DTCTxClient" class="Seasar.Examples.Reference.DTCTx.DTCTxClient" />

        <component class="Seasar.Examples.Reference.DTCTx.EmployeeDaoImpl">
            <aspect>DTCTx.RequiredTx</aspect>
        </component>

    </components>
#### DTCTx.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components namespace="DTCTx">
        <include path="Seasar.Examples/Ado.dicon" />

        <component name="DTCTransactionStateHandler"
                class="Seasar.Extension.Tx.Impl.DTCTransactionStateHandler" />

        <component name="RequiredTx" class="Seasar.Extension.Tx.TransactionInterceptor">
            <arg>
                <component class="Seasar.Extension.Tx.Impl.DTCRequiredTxHandler" />
            </arg>
        </component>

        ...

    </components>
Ado.dicon and result is the same as those of local transaction. ### System.Transactions Unlike in local transaction, connection do not have to be retrieved from TxDataSource, but to write source code that is not dependent on a data provider, connection, command, and parameter objects are created from Seasar.Extension.ADO.Impl.DataSourceImpl. When System.Transactions is used, a transaction is maintained even if a connection is closed after each query. Following is an example of DAO interface and DAO implementation class. #### EmployeeDao.cs C#
    using System;
    using System.Data;
    using Seasar.Extension.ADO;

    namespace Seasar.Examples.Reference.Tx
    {
        // DAO interface to use EMP
        public interface IEmployeeDao
        {
            void Insert();
        }

        // DAO implementation class to use EMP
        public class EmployeeDaoImpl : IEmployeeDao
        {
            private IDataSource dataSource;

            // property to inject DataSourceImpl
            public IDataSource DataSource
            {
                set { dataSource = value; }
            }

            #region IEmployeeDao member

            public void Insert()
            {
                using(IDbConnection cn = dataSource.GetConnection())
                {
                    cn.Open();
                    string sql = "insert into emp2 values(@empno, @ename, @deptnum)";
                    using(IDbCommand cmd = dataSource.GetCommand(sql,cn))
                    {
                        cmd.Parameters.Add(dataSource.GetParameter("@empno", 99));
                        cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"));
                        cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31));
                        cmd.ExecuteNonQuery();
                        Console.WriteLine("inserted employee");
                    }
                }
            }

            #endregion
        }
    }
VB.NET
    Imports System
    Imports System.Data
    Imports Seasar.Extension.ADO

    Namespace Seasar.Examples.Reference.Tx

       ' DAO interface to use EMP
       Public Interface IEmployeeDao
          Sub Insert()
       End Interface

       ' DAO implementation class to use EMP
       Public Class EmployeeDaoImpl
          Implements IEmployeeDao

          Private dataSource As IDataSource

          ' property to inject DataSourceImpl
          Public WriteOnly Property DataSource() As IDataSource
             Set(ByVal value As IDataSource)
                dataSource = value
             End Set
          End Property

          Public Sub Insert()

             Dim cn As IDbConnection = dataSource.GetConnection()
             Try
                cn.Open()
                Dim sql As String = "insert into emp2 values(@empno, @ename, @deptnum)"
                Dim cmd As IDbCommand = dataSource.GetCommand(sql, cn)
                Try
                   cmd.Parameters.Add(dataSource.GetParameter("@empno", 99))
                   cmd.Parameters.Add(dataSource.GetParameter("@ename", "Sugimoto"))
                   cmd.Parameters.Add(dataSource.GetParameter("@deptnum", 31))
                   cmd.ExecuteNonQuery()
                   Console.WriteLine("inserted employee")
                Finally
                   cmd.Dispose()
                End Try
             Finally
                cn.Dispose()
             End Try

          End Sub

       End Class

    End Namespace
Following is an example of a class to execute IEmployeeDao #### TxClient.cs C#
    using System;
    using Seasar.Framework.Container;
    using Seasar.Framework.Container.Factory;

    namespace Seasar.Examples.Reference.Tx
    {
        public class TxClient
        {
            private static readonly String PATH
                    = "Seasar.Examples/Reference/Tx/TxClient.dicon";

            public TxClient() {}

            public void Main()
            {
                // create S2Container
                IS2Container container = S2ContainerFactory.Create(PATH);
                // initialize S2Container
                container.Init();

                // retrieve component to implement IEmployeeDao from S2Container
                IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));

                // insert employee
                dao.Insert();
            }
        }
    }
VB.NET
    Imports System
    Imports Seasar.Framework.Container
    Imports Seasar.Framework.Container.Factory

    Namespace Seasar.Examples.Reference.Tx

       Public Class TxClient
          Private Shared PATH As [String] = _
             "Seasar.Examples/Reference/Tx/TxClient.dicon"

          Public Sub New()
          End Sub

          Public Sub Main()

             ' create S2Container
             Dim container As IS2Container = S2ContainerFactory.Create(PATH)
             ' initialize S2Container
             container.Init()

             ' retrieve component to implement IEmployeeDao from S2Container
             Dim dao As IEmployeeDao = _
                CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao)

             ' insert employee
             dao.Insert()

          End Sub

       End Class

    End Namespace
Following is an example of a dicon file. To apply Required attribute transaction, aspect in EmployeeDaoImpl is set to Tx.RequiredTx. #### TxClient.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components>
        <include path="Seasar.Examples/Tx.dicon" />

        <component name="TxClient" class="Seasar.Examples.Reference.Tx.TxClient" />

        <component class="Seasar.Examples.Reference.Tx.EmployeeDaoImpl">
            <aspect>Tx.RequiredTx</aspect>
        </component>

    </components>
#### Tx.dicon
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
    <components namespace="Tx">
        <include path="Seasar.Examples/Ado.dicon" />

        <component name="TransactionStateHandler"
                class="Seasar.Extension.Tx.Impl.TransactionStateHandler" />

        <component name="RequiredTx" class="Seasar.Extension.Tx.TransactionInterceptor">
            <arg>
                <component class="Seasar.Extension.Tx.Impl.RequiredTxHandler" />
            </arg>
        </component>

        ...

    </components>
Ado.dicon and execution result are the same as those in local transaction S2Container.NET by default provides Tx.dicon, LocalTx.dicon, and DTCTx.dicon (s2container.net/source/Seasar.Tests). It is only necessary to set component name of an Advice to an aspect tag. ## Exceptions When a component throws an exception, Advice defined in Tx.dicon and LocalTx.dicon and DTCTx.dion will rolled back the transaction. |
Trans. by H.Ozawa | Copyright© 2004-2007, The Seasar Foundation and the others. All rights reserved.