2015年9月17日木曜日

MySQLでフルテーブルスキャンが発生していた話

テーブルA
==============
id INT PK
code1 VARCHAR(4)
code2 VARCHAR(4)
 
テーブルB
==============
code1 VARCHAR(4) PK
name1 VARCHAR(4)
 
テーブルC
==============
code2 VARCHAR(4) PK
name2 VARCHAR(4)
 
のようなテーブルがあり、
 
select 1
from A 
inner join B
on A.code1 = B.code1
inner join C
on A.code2 = C.code2 
 
 をexplainするとテーブルBは主キーで検索されていたが、テーブルCはなぜかフルテーブルスキャンされていた。実際はもっと複雑なSQLでヒント文をつけたり、SQLをこねくり回したが結果は変わらず。
数時間たっても分からず、その日はあきらめて定時で帰り、眠りにつこうとした時に「もしかして・・・」と突然閃いた。予想は的中していた。
原因はテーブルCだけ文字コードが異なっていたためだった。

2014年5月31日土曜日

SpringでprivateメソッドにもTransactionalアノテーションを適用させる

SpringでprivateメソッドにもTransactionalアノテーションを適用させるにはAspectJを使う必要がある。
以下設定例。

 ■XML
  <tx:annotation-driven mode="aspectj"/>
  <context:annotation-config/>
  <context:load-time-weaver/>

■VM arguments
-javaagent:/path/spring-instrument-4.0.5.RELEASE.jar 

■必要なJAR(以下はcradleの例)
compile 'org.springframework:spring-core:4.0.5.RELEASE'
compile 'org.springframework:spring-context:4.0.5.RELEASE'
compile 'org.springframework:spring-jdbc:4.0.5.RELEASE'
compile 'org.springframework:spring-aspects:4.0.5.RELEASE'
compile 'org.springframework:spring-instrument:4.0.5.RELEASE'
compile 'org.aspectj:aspectjrt:1.8.0'
compile 'org.aspectj:aspectjweaver:1.8.0'

Springで自身のクラスを注入する

Springで以下のように自身のクラスを注入すると実行時に例外が発生する。
@Service
public class SpringBean {

    @Autowired
    private SpringBean self;

}
以下のように@Autowiredでなく@Resource使うことで回避できる。 nameをつけるのがポイント。
@Service
public class SpringBean {

    @Resource(name = "springBean")
    private SpringBean self;

}

Spring+Mirage+JTA(Atomikos)の例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
Atomikos3.9.3でAtomikosNonXADataSourceBeanを使用するとメモリリークしているようでOutOfMemoryErrorが発生したため非推奨
  <bean id="dataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean" init-method="init" destroy-method="close">
  <property name="uniqueResourceName" value="dataSource" />
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://localhost:3306/test1" />
  <property name="user" value="root" />
  <property name="password" value="password" />
  </bean>
-->
  <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
  init-method="init" destroy-method="close">
  <property name="uniqueResourceName" value="dataSource" />
  <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
  <property name="xaProperties">
  <props>
    <prop key="user">root</prop>
    <prop key="password">password</prop>
    <prop key="url">jdbc:mysql://localhost:3306/test1</prop>
  </props>
  </property>
  </bean>
  <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
  <property name="forceShutdown" value="false" />
  </bean>
  <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
  <property name="transactionTimeout" value="300" />
  </bean>
  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" depends-on="atomikosTransactionManager,atomikosUserTransaction">
  <property name="transactionManager" ref="atomikosTransactionManager" />
  <property name="userTransaction" ref="atomikosUserTransaction" />
  <property name="allowCustomIsolationLevels" value="true" />
  </bean>
  <bean id="connectionProvider" class="jp.sf.amateras.mirage.provider.DataSourceConnectionProvider">
  <property name="dataSource" ref="dataSource" />
  </bean>
  <bean id="dialect" class="jp.sf.amateras.mirage.dialect.MySQLDialect"/>
  <bean id="sqlManager" class="jp.sf.amateras.mirage.SqlManagerImpl">
  <property name="connectionProvider" ref="connectionProvider" />
  <property name="dialect" ref="dialect" />
  </bean>
</beans>

2013年12月27日金曜日

[xcode5]リリース時にNSAssertを実行しないようにする

xcode5でリリース時にNSAssertを実行しないようにするには以下を行う。
  1. Build Settingsタブを選択し、検索フィールドに「processor」 と入力して検索
  2. Preprocessor MacrosのReleaseの値を「NS_BLOCK_ASSERTIONS」と入力
 
■確認方法
  1. メニューのProduct⇒Scheme⇒Edit Scheme...を選択
  2.  ▶️Run (プロジェクト名)を選択し、infoタブをクリック
  3. Build Configurationで「Release」を選択し、OKボタンをクリック
  4. ⌘Rでプログラムを実行しNSAssertで止まらないこと確認

 ■参考文献
COCOA PROGRAMMING FOR MAC OS X(4TH EDITION)の位置No.1454/10487

2012年12月24日月曜日

正規表現の先読み

msdnを見ていたら、こんなソースを見つけた。

public void OnValidatePassword(object sender,
                              ValidatePasswordEventArgs args)
{
  System.Text.RegularExpressions.Regex r =
    new System.Text.RegularExpressions.Regex(@"(?=.{6,})(?=(.*\d){1,})(?=(.*\W){1,})");


  if (!r.IsMatch(args.Password))
  {
    args.FailureInformation =
      new HttpException("Password must be at least 6 characters long and " +
                        "contain at least one number and one special character.");
    args.Cancel = true;
  }
}
パスワードの入力チェックで
  • 長さが6文字以上
  • 数字が1つ以上含まれている
  • 英数字以外の文字が1つ以上含まれている
という3つの用件を
(?=.{6,})(?=(.*\d){1,})(?=(.*\W){1,})
という一つの正規表現でチェックしていた。 正規表現の『(?=)』は先読みと呼ばれるもので、正規表現の先読みについて解説してみる がとても参考になった。

2012年9月9日日曜日

最近接偶数への丸め(偶数丸め、JIS丸め)について勘違いしていた

最近接偶数への丸め(偶数丸め、JIS丸め)について勘違いしていた話。
最近接偶数への丸めについての仕様は http://www.jisc.go.jp/app/JPS/JPSO0020.html を開き「Z8401」で検索。

当初、小数点以下を丸めて整数にする場合、
  • 小数第一位が4以下ならば切り捨て
  • 小数第一位が6以上ならば切り上げ
  • 小数第一位が5で一の位が偶数ならば切り捨て
  • 小数第一位が5で一の位が奇数ならば切り上げ
と思っていた。
1.50 ⇒ 2     1.51 ⇒ 2
2.50 ⇒ 2     2.51 ⇒ 2
になると思っていたが、正しくは
1.50 ⇒ 2     1.51 ⇒ 2
2.50 ⇒ 2     2.51 ⇒ 3
である。
最近接偶数への丸め(偶数丸め、JIS丸め)は、与えられた数値を近い方へ丸める。
与えられた数値が切り上げた数値の方が近い場合は切り上げ、切り下げた数値の方が近い場合は切り下げとなる。距離が同じ場合は、偶数の方へ丸める。
2.51 ⇒ 3になるのは切り下げた数値(=2)よりも切り上げた数値(=3)の方が近いためである。