トランザクション
C#
共通メソッド
private void AddParameter(SqlCommand cmd)
{
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@AddressID", SqlDbType.Int, 3),
new SqlParameter("@City", SqlDbType.NVarChar, 20),
new SqlParameter("@PostCD", SqlDbType.NVarChar, 30),
new SqlParameter("@Name", SqlDbType.NVarChar, 25)
};
paras[0].Value = "101";
paras[1].Value = "東京";
paras[2].Value = "125-0001";
paras[3].Value = "Andy";
foreach (var para in paras)
{
cmd.Parameters.Add(para);
}
}
ストアド(トランザクションあり)
CREATE PROCEDURE dbo.sp_Tran
(
@City nvarchar(20),
@AddressID int,
@PostCD nvarchar(30),
@Name nvarchar(25)
)
AS
BEGIN TRANSCATION tran;
UPDATE
Address
SET
City = @City,
PostalCode = @PostalCode,
Name = @Name
WHERE
AddressID = @AddressID;
IF(@@error = 0)
COMMIT TRANSCATION tran;
ELSE
ROLLBACK TRANSCATION tran;
GO
ストアド(トランザクションなし)
CREATE PROCEDURE dbo.sp_NoTran
(
@City nvarchar(20),
@AddressID int,
@PostCD nvarchar(30),
@Name nvarchar(25)
)
AS
UPDATE
Address
SET
City = @City,
PostalCode = @PostalCode,
Name = @Name
WHERE
AddressID = @AddressID;
GO
1.SQL Transaction
効率よいが、複雑な業務に適用できない。
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "sp_Tran";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
conn.Open();
this.AddParameter(cmd);
cmd.ExecuteNonQuery();
}//using
2.ADO.NET Transaction
簡単だが、一つのDBしか使えない。
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
using (SqlTransaction tran = conn.BeginTransaction())
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "sp_NoTran";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
cmd.Transaction = tran;
conn.Open();
this.AddParameter(cmd);
try
{
cmd.ExecuteNonQuery();
tran.Commit();
}
catch (Exception e)
{
tran.Rollback();
throw;
}//try-catch
}//using
3.TransactionScope
分散トランザクション
※MSDTCサービスが開始
net start msdtc
netsh firewall set allowedprogram %windir%\system32\msdtc.exe MSDTC enable
//TransactionScopeはSystem.Transactions.dll中
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
using (TransactionScope ts = new TransactionScope())
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "sp_NoTran";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
conn.Open();
this.AddParameter(cmd);
try
{
cmd.ExecuteNonQuery();
ts.Complete();
}
catch (Exception)
{
throw;
}//try-catch
}//using
4.COM+ Transaction
分散型設計で複数DBに対するトランザクション
//ServiceConfigはSystem.EnterpriseServices.dll中
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "sp_NoTran";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
ServiceConfig sc = new ServiceConfig()
{
Transaction = TransactionOption.Required,
TrackingEnabled = true
};
ServiceDomain.Enter(sc);
conn.Open();
this.AddParameter(cmd);
try
{
cmd.ExecuteNonQuery();
ContextUtil.SetComplete();
}
catch (Exception)
{
ContextUtil.SetAbort();
throw;
}
finally
{
ServiceDomain.Leave();
}//try-catch-finally
}//using
Java
プログラミングモデル
1.Java API
単一データベースに向け
java.sql.Connection
setAutoCommit commit rollback
Connection conn = getConnection();
conn.setAutoCommit(false);
boolean isSuccess = doSomething();
if(isSuccess){
conn.commit();
}else{
conn.rollback();
}
2.JTA(Java Transaction API)
分散データベースに向け
JPA実現
java.transaction.UserTransaction
begin commit rollback setRollbackOnly setTransactionTimeout getStatus
InitialContext ctx = new InitialContext();
UserTransaction ut = (UserTransaction)
ctx.lookup("javax.transaction.UserTransaction");
ut.begin();
boolean isSuccess = doSomething();
if(isSuccess){
ut.commit();
}else{
ut.rollback();
}
Spring実現
org.springframework.transaction.PlatformTransactionManager
getTransaction commit rollback
JTAを含む(JtaTransactionManager)
ApplicationContext context = getApplicationContext();
TransactionTemplate transactionTemplate =
(TransactionTemplate)context.getBean("TransactionTemplate");
transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status){
boolean isSuccess = doSomething();
if(isSuccess){
...
}else{
status.setRollbackOnly();
}
return isSuccess;
}
});
宣言モデル
XML設定ファイル
Anotation
SpringのAOP
<bean id="xxxService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="xxxServiceTarget"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_SUPPORTS</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
</props>
</property>
★S2AOPによるトランザクション制御
j2ee.diconに定義済みのインターセプター
トランザクション設定
<component class="example.dao.SampleDao">
<aspect pointcut="insert.*,update.*,delete.*">
j2ee.requiredTx
</aspect>
</component>
例外はストーしてもトランザクションはコミットしたい場合の設定
j2ee.dicon
<components namespace="j2ee">
<include path="jta.dicon" />
<include path="jdbc.dicon" />
<component name="requiredTx" class="org.seasar.extension.tx.RequiredInterceptor">
<initMethod name="addCommitRule">
<arg>@example.exception.CommitException@class</arg>
</initMethod>
</component>
...
</components>
1アクションで複数のトランザクションを実行する
public class SampleAction {
@Resource
protected AService aService;
@Resource
protected BService bService;
@Execute(validator=false)
public String index() {
aService.insert();
bService.update();
...
}
}
public class AService {
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void insert() {
...
}
}
トランザクションの手動制御
public class SampleAction {
@Resource
protected UserTransaction userTransaction;
@Execute(validator=false)
@TransactionAttribute(TransactionAttributeType.NEVER)
public String index() {
userTransaction.begin();
try {
...
} catch(Exception e) {
// 例外をスローせず
userTransaction.setRollbackOnly();
} finally {
if(userTransaction.getStatus() = Status.STATUS_ACTIVE) {
userTransaction.commit();
return "index.jsp";
}
userTransaction.rollback();
return "error.jsp";
}
}
}
★Spring事务失效的具体场景
1.注解@Transactional配置的方法非public权限修饰
2.注解@Transactional所在类非Spring容器管理的bean
3.注解@Transactional所在类中,注解修饰的方法被类内部方法调用
4.业务代码抛出异常类型非RuntimeException,事务失效
5.业务代码中存在异常时,catch语句块没有throw new RuntimeExecption异常
6.注解@Transactional中Propagation属性值设置Propagation.NOT_SUPPORTED
7.mysql关系型数据库,且存储引擎是MyISAM而非InnoDB,则事务会不起作用