引子:DAL作为公司新架构独立的数据访问服务开始了研发。DALClient1.0暂基于mybatis3和spring3,实现了数据cache,sql拦截缓存,全局事务管理。后期将实现基于hibernate和OSGI的版本研发。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<bean id="dalSessionFactory" class="com.hc360.dal.DalSessionFactoryBean">
<property name="configLocation"value="/WEB-INF/conf/mybatis/mybatis-config.xml"></property>
<property name="dataSource"ref="dataSource" />
<property name="mapperLocations">
<list>
<value>classpath:com/hc360/pay/hcpay/dalmapper/*-mapper.xml</value>
</list>
</property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"ref="dataSource" />
</bean>
<!-- 事务配置-->
<tx:annotation-driven transaction-manager="txManager"/>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*"propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*"propagation="REQUIRED"
rollback-for="Exception" />
<tx:method name="del*"propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*"read-only="true" />
</tx:attributes>
</tx:advice>
<bean class="com.hc360.dal.mapper.MapperScannerConfigurer">
<property name="basePackage"value="com.hc360.pay.hcpay.dal" />
</bean>
<mapper namespace="com.hc360.pay.hcpay.dal.AccountRemoteMapper">
<!-- ORM PO -->
<resultMap id="accountMap" type="account">
<result column="id"property="id" />
<result column="name"property="name" />
<result column="pwd"property="pwd" />
<result column="address"property="address" />
<result column="zip"property="zip" />
<result column="phone"property="phone" />
</resultMap>
<!-- sql -->
<insert id="insert" parameterType="account">
<selectKey keyProperty="id"resultType="long" order="BEFORE">
select
PAY_TRADE_ACCOUNT_SEQ.nextval as id from dual
</selectKey>
<![CDATA[
insert into PAY_TRADE_ACCOUNT (id, name,pwd, address, zip, phone)
values ( #{id}, #{name}, #{pwd},#{address}, #{zip}, #{phone})
]]>
</insert>
<!-- 使用缓存 -->
<cache type="com.hc360.dal.cache.MapperCache"/>
</mapper>
从basePackage目录寻找mapper接口,给每个接口实现一个MapperFactoryBean类,相当于每个mapper实例是一个dalsession。
加载完applicationContext-datasource.xml配置文件有,DalSessionFactoryBean注入创建dalsession
@Autowired(required = false)
this.dalSession = new MyDalSession(dalSessionFactory);
相当于每个mapperbean是一个被mapperproxy代理了的dalsession
ClassLoader classLoader = this.mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{this.mapperInterface};
MapperProxy proxy = new MapperProxy(this.getDalSession());
return (T) Proxy.newProxyInstance(classLoader,interfaces,proxy);
将事务交给spring全局事务代理
final DalSession dalSession = DalSessionUtils.getHolderSession(dalSessionFactory);
Object result = method.invoke(dalSession,args);
将事务交给spring全局事务,holder缓冲着basedalsession,这块比较绕:mapper实例化为mydalsession,但被DalSessionUtils代理了,完了还从全局DalSessionHolder缓存中得到BaseDalSession
DalSessionHolder holder = (DalSessionHolder)TransactionSynchronizationManager.getResource(dalSessionFactory);
DalSession dalSession = null;
if (holder != null && holder.isSynchronizedWithTransaction()) {
holder.requested();
return holder.getDalSession();
}
if (TransactionSynchronizationManager.isSynchronizationActive()){
/**
* Holder
*/
dalSession = new BaseDalSession(dalSessionFactory.getConfiguration());
holder = newDalSessionHolder(dalSession);
TransactionSynchronizationManager.bindResource(dalSessionFactory,holder);
TransactionSynchronizationManager.registerSynchronization(newDalSessionSynchronization(holder,dalSessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
}
return dalSession;
全局事务提交
全局事务关闭
如果是插入,获取一次seq,保存入cache
Configuration configuration = dalSession.getConfiguration();
String commandName =declaringInterface.getName() + "." + method.getName();
MappedStatement ms =configuration.getMappedStatement(commandName);
KeyGenerator keyGenerator = ms.getKeyGenerator();
if (SqlCommandType.INSERT == type) {
if (keyGenerator instanceofSelectKeyGenerator) {
if(cache != null){
/**
* 得到获得key的sql
*/
String keysql =((SelectKeyGenerator)keyGenerator).keyStatement.getSqlSource().getBoundSql(null).getSql();
Object object= dalSession.selectKey(keysql);
/**
* 保存入缓存
*/
cache.putObject(key, object);
}
}
result = dalSession.insert(ms,args);
if (SqlCommandType.SELECT == type) {
/**
* 从缓存取
*/
Object object =cache.getObject(args[0]);
result = dalSession.selectOne(ms,args);
}