实现分布式事务管理
网上有很多都是配置2甚至多个一样的Dao去实现此操作,小弟修改了一下ibatis源代码使得dao层可以动态指定数据源。
Spring配置文件
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allManagerMethod"
expression="execution (* com.test.*.*.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" />
</aop:config>
<!--配置jta transactionManager-->
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref bean="atomikosTransactionManager" />
</property>
<property name="userTransaction">
<ref bean="atomikosUserTransaction" />
</property>
<property name="allowCustomIsolationLevels" value="true"/>
</bean>
<bean id="atomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown">
<value>true</value>
</property>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout">
<value>20000</value>
</property>
</bean>
<!--配置数据源 -->
<bean id="datasource1" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>oracle/read</value>
</property>
<property name="xaDataSourceClassName">
<value>oracle.jdbc.xa.client.OracleXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="user">customer</prop>
<prop key="password">123456</prop>
<prop key="URL">jdbc:oracle:thin:@localhost:1521:jddb</prop>
</props>
</property>
<property name="maxPoolSize"><value>10</value></property>
<property name="minPoolSize"><value>2</value></property>
<property name="loginTimeout"><value>30</value></property>
<property name="reapTimeout"><value>20000</value></property>
<property name="testQuery"> <value>select 1 from dual</value> </property>
</bean>
<bean id="datasource2" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>oracle/read</value>
</property>
<property name="xaDataSourceClassName">
<value>oracle.jdbc.xa.client.OracleXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="user">customer</prop>
<prop key="password">123456</prop>
<prop key="URL">jdbc:oracle:thin:@192.168.0.2:1521:jddb</prop>
</props>
</property>
<property name="maxPoolSize"><value>10</value></property>
<property name="minPoolSize"><value>2</value></property>
<property name="loginTimeout"><value>30</value></property>
<property name="reapTimeout"><value>20000</value></property>
<property name="testQuery"> <value>select 1 from dual</value> </property>
</bean>
<!--配置 sqlMapClient -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sqlMapConfig.xml"></property>
<property name="dataSource" ref="datasource1" />
</bean>
<bean id="sqlMapClient2" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sqlMapConfig2.xml"></property>
<property name="dataSource" ref="datasource2" />
</bean>
<!-- 增加此属性,为了在dao层和service动态分配sqlMapClient -->
<bean id="sqlMapClientMap" class="com.home.framework.dynamicds.SqlMapClientMap">
<property name="map">
<map key-type="java.lang.String">
<entry key="READ1" value-ref="sqlMapClient" />
<entry key="WRITE" value-ref="sqlMapClient2" />
</map>
</property>
</bean>
SqlMapClientMap.java源代码
public class SqlMapClientMap {
private LinkedHashMap<String,SqlMapClient> map = new LinkedHashMap<String,SqlMapClient>();
public LinkedHashMap<String,SqlMapClient> getMap() {
return map;
}
public void setMap(LinkedHashMap<String,SqlMapClient> map) {
this.map = map;
}
}
jta.properties配置文件
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = tm.out
com.atomikos.icatch.log_base_name = tmlog
com.atomikos.icatch.tm_unique_name = tm
com.atomikos.icatch.console_log_level=INFO
修改ibatis源文件SqlMapClientDaoSupport
1.增加属性(set get方法省略)
//当前调用sqlMap名称
protected String sqlMapClientName;
//配置文件注入sqlMap集合
private SqlMapClientMap sqlMapClientMap = new SqlMapClientMap();
2.修改方法
public final SqlMapClientTemplate getSqlMapClientTemplate() {
if(sqlMapClientName == null) {
} else {
SqlMapClient sqlMapClient = sqlMapClientMap.getMap().get(sqlMapClientName);
this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
}
return this.sqlMapClientTemplate;
}
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
return (String) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
public class DataSourceMap {
public static final String READ1 = "READ1";
public static final String WRITE = "WRITE";
}
Dao层代码
@Component("iFunocxDao")
public class FunocxDao extends SqlMapClientDaoSupport implements IFunocxDao {
public void insert(Object o) {
// TODO Auto-generated method stub
sqlMapClientName = DataSourceContextHolder.getCustomerType();
getSqlMapClientTemplate().insert(o)
}
}
Service层代码
@Service("iFunocxService")
public class FunocxService implements IFunocxService {
@Autowired
private IFunocxDao iFunocxDao;
public void insert(Funocx ocx) {
// TODO Auto-generated method stub
DataSourceContextHolder.setCustomerType(DataSourceMap.WRITE);
iFunocxDao.insert(ocx);
DataSourceContextHolder.setCustomerType(DataSourceMap.WRITE);
iFunocxDao.insert(ocx);
}
}