S2Container.NETが標準で用意しているTx.dicon(System.Transactions用), LocalTx.dicon(ローカルトランザクション用), DTCTx.dicon(MS DTC用)には、 次のトランザクション属性に対応したAdviceが定義されています。 コンポーネント名がAdviceの名前です。
属性 | コンポーネント名 | 説明 |
---|---|---|
Required | LocalTx.RequiredTx (ローカルトランザクション用) |
トランザクションが存在する場合はこれを共有し、 必要に応じて新しいトランザクションを作成します。 |
DTCTx.RequiredTx (MS DTC用) |
||
Tx.RequiredTx (System.Transactions用) |
||
RequiresNew | LocalTx.RequiresNewTx (ローカルトランザクション用) |
現在のコンテキストの状態とは関係なく、新しいトランザクションでコンポーネントを作成します。 |
DTCTx.RequiresNewTx (MS DTC用) |
||
Tx.RequiresNewTx (System.Transactions用) |
||
Supported | LocalTx.SupportedTx (ローカルトランザクション用) |
トランザクションが存在する場合はこれを共有します。 |
DTCTx.SupportedTx (MS DTC用) |
||
NotSupported | LocalTx.NotSupportedTx (ローカルトランザクション用) |
制御するトランザクションがないコンテキストでコンポーネントを作成します。 |
DTCTx.NotSupportedTx (MS DTC用) |
||
Tx.NotSupportedTx (System.Transactions用) |
ローカルトランザクションを利用するためには、Seasar.Extension.Tx.Impl.TxDataSourceからコネクションを取得します。 コネクションのオープン、クローズはAdvice(MethodInterceptor)が管理するため、 DAO (Data Access Object)では行いません。 DAOにTxDataSourceをインジェクションしてもらうために Seasar.Extension.ADO.IDataSource型のプロパティを用意します。
コネクション、トランザクション、コマンド、パラメータのオブジェクトはdataSourceから作成します。 従業員を扱うためのDAOインターフェースとDAO実装クラスは次のようになります。
C#
using System; using System.Data; using Seasar.Extension.ADO; namespace Seasar.Examples.Reference.LocalTx { // 従業員を扱うためのDAOインターフェース public interface IEmployeeDao { void Insert(); } // 従業員を扱うためのDAO実装クラス public class EmployeeDaoImpl : IEmployeeDao { private IDataSource dataSource; // TxDataSourceをインジェクションしてもらうためのプロパティ public IDataSource DataSource { set { dataSource = value; } } #region IEmployeeDao メンバ 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("EMPを追加しました。"); } } #endregion } }
VB
Imports System Imports System.Data Imports Seasar.Extension.ADO Namespace Seasar.Examples.Reference.LocalTx ' 従業員を扱うためのDAOインターフェース Public Interface IEmployeeDao Sub Insert() End Interface 'IEmployeeDao ' 従業員を扱うためのDAO実装クラス Public Class EmployeeDaoImpl Implements IEmployeeDao Private dataSource As IDataSource ' 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("EMPを追加しました。") Finally cmd.Dispose() End Try End Sub End Class End Namespace
IEmployeeDaoを実行するクラスは次のようになります。
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() { // S2コンテナを作成します IS2Container container = S2ContainerFactory.Create(PATH); // S2コンテナを初期化します container.Init(); // S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します IEmployeeDao dao = (IEmployeeDao) container.GetComponent( typeof(IEmployeeDao)); // 従業員を追加します dao.Insert(); } } }
VB
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() ' S2コンテナを作成します Dim container As IS2Container = S2ContainerFactory.Create(PATH) ' S2コンテナを初期化します container.Init() ' S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します Dim dao As IEmployeeDao = _ CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao) ' 従業員を追加します dao.Insert() End Sub End Class End Namespace
diconファイルは次のようになります。Required属性のトランザクションを適用するために、 EmployeeDaoImplのaspectにLocalTx.RequiredTxを指定してします。
<?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>
<?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>
<?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"> <!-- .NET Framework Data Provider for SQL Server を使用する場合に必要です。 --> <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>
DEBUG トランザクションを開始しました EMPを追加しました。 DEBUG トランザクションをコミットしました
MS DTCによる分散トランザクションを利用するためには、MS DTCが利用できる環境でなければいけません。 ローカルトランザクションのようにTxDataSourceからコネクションをとらないといけないといった制限はありませんが、 データプロバイダに依存しないコーディングをするために、Seasar.Extension.ADO.Impl.DataSourceImpl からコネクション、コマンド、パラメータのオブジェクトを作成します。 MS DTCを利用する場合は、1回のクエリ発行毎にコネクションをクローズしても、トランザクションは維持されます。
分散トランザクションの注意点ですが、Seasar.dllをCOM+アプリケーションにインストールする必要があります。 COM+アプリケーションへのインストールは自動で行われますが、実行ユーザにその権限がない場合は、 レジストリキーへのアクセスが拒否されたという例外(System.UnauthorizedAccessException)が発生します。 このような例外が発生した場合は、権限を持ったユーザで実行するか、 あらかじめ権限を持ったユーザでCOM+アプリケーションへのインストールを手動で行ってください。
手動でSeasar.dllをCOM+アプリケーションにインストールするためには .NET サービス インストールツール(RegSvcs.exe)を使います。.NET 2.0 の場合は、 RegSvcs.exeは %windir%\Microsoft.NET\Framework\v2.0.50727\RegSvcs.exe に存在します。以下のようにRegSvcs.exeのパラメータにSeasar.dllへのフルパスを渡して、 Seasar.dllをCOM+アプリケーションにインストールすることができます。
従業員を扱うためのDAOインターフェースとDAO実装クラスは次のようになります。
C#
using System; using System.Data; using Seasar.Extension.ADO; namespace Seasar.Examples.Reference.DTCTx { // 従業員を扱うためのDAOインターフェース public interface IEmployeeDao { void Insert(); } // 従業員を扱うためのDAO実装クラス public class EmployeeDaoImpl : IEmployeeDao { private IDataSource dataSource; // DataSourceImplをインジェクションしてもらうためのプロパティ public IDataSource DataSource { set { dataSource = value; } } #region IEmployeeDao メンバ 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("EMPを追加しました。"); } } } #endregion } }
VB
Imports System Imports System.Data Imports Seasar.Extension.ADO Namespace Seasar.Examples.Reference.DTCTx ' 従業員を扱うためのDAOインターフェース Public Interface IEmployeeDao Sub Insert() End Interface ' 従業員を扱うためのDAO実装クラス Public Class EmployeeDaoImpl Implements IEmployeeDao Private dataSource As IDataSource ' 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("EMPを追加しました。") Finally cmd.Dispose() End Try Finally cn.Dispose() End Try End Sub End Class End Namespace
IEmployeeDaoを実行するクラスは次のようになります。
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() { // S2コンテナを作成します IS2Container container = S2ContainerFactory.Create(PATH); // S2コンテナを初期化します container.Init(); // S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao)); // 従業員を追加します dao.Insert(); } } }
VB
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() ' S2コンテナを作成します Dim container As IS2Container = S2ContainerFactory.Create(PATH) ' S2コンテナを初期化します container.Init() ' S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します Dim dao As IEmployeeDao = _ CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao) ' 従業員を追加します dao.Insert() End Sub End Class End Namespace
diconファイルは次のようになります。 Required属性のトランザクションを適用するために、 EmployeeDaoImplのaspectにDTCTx.RequiredTxを指定します。
<?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>
<?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と実行結果は、ローカルトランザクションの場合と同じです。
ローカルトランザクションのようにTxDataSourceからコネクションをとらないといけないといった制限はありませんが、 データプロバイダに依存しないコーディングをするために、Seasar.Extension.ADO.Impl.DataSourceImpl からコネクション、コマンド、パラメータのオブジェクトを作成します。
System.Transactionsによるトランザクションを利用する場合は、 1回のクエリ発行毎にコネクションをクローズしても、トランザクションは維持されます。
従業員を扱うためのDAOインターフェースとDAO実装クラスは次のようになります。
C#
using System; using System.Data; using Seasar.Extension.ADO; namespace Seasar.Examples.Reference.Tx { // 従業員を扱うためのDAOインターフェース public interface IEmployeeDao { void Insert(); } // 従業員を扱うためのDAO実装クラス public class EmployeeDaoImpl : IEmployeeDao { private IDataSource dataSource; // DataSourceImplをインジェクションしてもらうためのプロパティ public IDataSource DataSource { set { dataSource = value; } } #region IEmployeeDao メンバ 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("EMPを追加しました。"); } } } #endregion } }
VB
Imports System Imports System.Data Imports Seasar.Extension.ADO Namespace Seasar.Examples.Reference.Tx ' 従業員を扱うためのDAOインターフェース Public Interface IEmployeeDao Sub Insert() End Interface ' 従業員を扱うためのDAO実装クラス Public Class EmployeeDaoImpl Implements IEmployeeDao Private dataSource As IDataSource ' 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("EMPを追加しました。") Finally cmd.Dispose() End Try Finally cn.Dispose() End Try End Sub End Class End Namespace
IEmployeeDaoを実行するクラスは次のようになります。
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() { // S2コンテナを作成します IS2Container container = S2ContainerFactory.Create(PATH); // S2コンテナを初期化します container.Init(); // S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao)); // 従業員を追加します dao.Insert(); } } }
VB
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() ' S2コンテナを作成します Dim container As IS2Container = S2ContainerFactory.Create(PATH) ' S2コンテナを初期化します container.Init() ' S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します Dim dao As IEmployeeDao = _ CType(container.GetComponent(GetType(IEmployeeDao)), IEmployeeDao) ' 従業員を追加します dao.Insert() End Sub End Class End Namespace
diconファイルは次のようになります。Required属性のトランザクションを適用するために、 EmployeeDaoImplのaspectにTx.RequiredTxを指定します。
<?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>
<?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と実行結果は、ローカルトランザクションの場合と同じです。
S2Container.NETには、Tx.dicon, LocalTx.dicon, DTCTx.diconのサンプルがあらかじめ用意(s2container.net/source/Seasar.Tests)されています。 必要に応じて、ユーザアプリケーションのプロジェクトにコピーしてください。
Adviceのコンポーネント名をaspectタグのボディに指定するだけなので簡単です。 簡単にトランザクション管理機能が組み込めることがわかって頂けたと思います。