S2Container.NET TOPページへ
S2Tx.NETの機能を使って、.NETオブジェクトに対して、
Aspectでトランザクションの自動管理機能を組み込むことができます。
Aspectを適用については、こちらの注意点を確認して下さい。
トランザクションの自動管理には、System.Transactionsによるトランザクション(1.2.0-rc1 for .NET 2.0以降), ローカルトランザクション,
Microsoft 分散トランザクション コーディネータ (MS DTC)の3つの種類のトランザクションをサポートしています。
組む込むことのできるトランザクション属性は次のとおりです。
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 |
Tx.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実装クラスは次のようになります。
EmployeeDao.cs
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.NET
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を実行するクラスは次のようになります。
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()
{
// S2コンテナを作成します
IS2Container container = S2ContainerFactory.Create(PATH);
// S2コンテナを初期化します
container.Init();
// S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します
IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));
// 従業員を追加します
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()
' 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を指定してします。
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">
<!-- .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回のクエリ発行毎にコネクションをクローズしても、トランザクションは維持されます。
従業員を扱うためのDAOインターフェースとDAO実装クラスは次のようになります。
EmployeeDao.cs
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.NET
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を実行するクラスは次のようになります。
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()
{
// S2コンテナを作成します
IS2Container container = S2ContainerFactory.Create(PATH);
// S2コンテナを初期化します
container.Init();
// S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します
IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));
// 従業員を追加します
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()
' 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を指定します。
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と実行結果は、ローカルトランザクションの場合と同じです。
ローカルトランザクションのようにTxDataSourceからコネクションをとらないといけないといった制限はありませんが、
データプロバイダに依存しないコーディングをするために、Seasar.Extension.ADO.Impl.DataSourceImpl
からコネクション、コマンド、パラメータのオブジェクトを作成します。
System.Transactionsによるトランザクションを利用する場合は、1回のクエリ発行毎にコネクションをクローズしても、トランザクションは維持されます。
従業員を扱うためのDAOインターフェースとDAO実装クラスは次のようになります。
EmployeeDao.cs
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.NET
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を実行するクラスは次のようになります。
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()
{
// S2コンテナを作成します
IS2Container container = S2ContainerFactory.Create(PATH);
// S2コンテナを初期化します
container.Init();
// S2コンテナからIEmployeeDaoを実装するコンポーネントを取り出します
IEmployeeDao dao = (IEmployeeDao) container.GetComponent(typeof(IEmployeeDao));
// 従業員を追加します
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()
' 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を指定します。
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と実行結果は、ローカルトランザクションの場合と同じです。
S2Container.NETには、Tx.dicon, LocalTx.dicon, DTCTx.diconのサンプルがあらかじめ用意(s2container.net/source/Seasar.Tests)されています。
必要に応じて、ユーザアプリケーションのプロジェクトにコピーしてください。
Adviceのコンポーネント名をaspectタグのボディに指定するだけなので簡単です。
簡単にトランザクション管理機能が組み込めることがわかって頂けたと思います。
Tx.dicon、LocalTx.dicon、DTCTx.dionに定義されているAdviceは、コンポーネントが例外をスローした場合はトランザクションをロールバックします.
|