mysqlプライマリデータベースからの読み書き分離
会社のプロジェクトはmysqlの主従構造を使用しており、もともとslaveはバックアップとして使用されていたが、後でslaveから取れるように読み取りたいが、masterに書くのは効率を高めるためだ.ネットで調べたところ、現在の読み書き分離には2つの方法があります.
一つはmysql proxyを使うことです
二つ目はプログラム端制御
実は私はmysql proxyのほうが好きです.アプリケーションに完全に透明だからです.しかし、プログラム側の分離も可能であり、mysql自体はReplicationConnectionを提供しており、データベースがconnection.setReadonly=trueに接続されている場合、slaveデータベースからデータを取得します.詳細は以下を参照してください.http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-replication-connection.html
これではspringのトランザクションのreadonly特性を利用してプロジェクトを改造し,アプリケーションへの侵入も許容できる.jpaを使用している場合は、トランザクション構成内のjpa Dialectを利用して構成できます
jdbcトランザクションの場合:
最後に、対応するすべてのサービスメソッドがデータを読み出すだけであれば、トランザクションにreadonlyプロパティを追加する必要があります.これは面倒です.私たちが使用している注釈でトランザクションを構成しているので、xmlアダプタを使用すると簡単です.
このシナリオの欠点は、トランザクションに書かれた操作があれば、トランザクション全体がmasterデータベースを操作するので、分離の効果はもう少しで低下することです.
一つはmysql proxyを使うことです
二つ目はプログラム端制御
実は私はmysql proxyのほうが好きです.アプリケーションに完全に透明だからです.しかし、プログラム側の分離も可能であり、mysql自体はReplicationConnectionを提供しており、データベースがconnection.setReadonly=trueに接続されている場合、slaveデータベースからデータを取得します.詳細は以下を参照してください.http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-replication-connection.html
これではspringのトランザクションのreadonly特性を利用してプロジェクトを改造し,アプリケーションへの侵入も許容できる.jpaを使用している場合は、トランザクション構成内のjpa Dialectを利用して構成できます
<!-- transactionManager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect">
<bean class="xxx.support.hibernate.HibernateJpaReadonlySupportDialect" />
</property>
</bean>
H i bernateJpaReadonlyspportDialectの中はbeginの中にある限り:@Override
public Object beginTransaction(final EntityManager entityManager,
final TransactionDefinition definition)
throws PersistenceException, SQLException, TransactionException {
...
ConnectionHandle connHandle = getJdbcConnection(entityManager, definition.isReadOnly());
Connection conn = connHandle.getConnection();
conn.setReadOnly(definition.isReadOnly());
...
}
これを加えると、hibernateまたはjdbcを使用する場合はspringが提供するトランザクションクラスを直接継承し、connのreadOnlyプロパティを設定することもできます.jdbcトランザクションの場合:
public class DataSourceReadonlyTransactionManager extends DataSourceTransactionManager{
private static final long serialVersionUID = 6611124435285107181L;
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
super.doBegin(transaction, definition);
try {
Method getConnectionHolder = transaction.getClass().getMethod("getConnectionHolder", null);
ConnectionHolder connectionHolder = (ConnectionHolder)getConnectionHolder.invoke(transaction, null);
Connection con = null;
con = connectionHolder.getConnection();
if(null != con)
con.setReadOnly(definition.isReadOnly());
} catch (Exception ignore) {
}
}
}
hibernateの話はjdbcと似ています.最後に、対応するすべてのサービスメソッドがデータを読み出すだけであれば、トランザクションにreadonlyプロパティを追加する必要があります.これは面倒です.私たちが使用している注釈でトランザクションを構成しているので、xmlアダプタを使用すると簡単です.
このシナリオの欠点は、トランザクションに書かれた操作があれば、トランザクション全体がmasterデータベースを操作するので、分離の効果はもう少しで低下することです.