引子:DAL作爲公司新架構獨立的數據訪問服務開始了研發。DALClient1.0暫基於mybatis3和spring3,實現了數據cache,sql攔截緩存,全局事務管理。後期將實現基於hibernate和OSGI的版本研發。
一、DALClient的配置
1. web.xml
<!-- Spring監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
2. applicationContext-datasource.xml
<!--將配置文件與數據源注入給DalSessionFactoryBean -->
<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>
<!-- Spring事務管理,管理service事務 -- >
<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>
<!-- 初始化Mapper-->
<bean class="com.hc360.dal.mapper.MapperScannerConfigurer">
<property name="basePackage"value="com.hc360.pay.hcpay.dal" />
</bean>
3. *-mapper.xml
<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>
二、DALClient初始化Mapper
1. MapperScannerConfigurer.Scanner內部類
protected Set<BeanDefinitionHolder>doScan(String... basePackages)
從basePackage目錄尋找mapper接口,給每個接口實現一個MapperFactoryBean類,相當於每個mapper實例是一個dalsession。
2. DalSessionDaoSupport
public final void setDalSessionFactory(DalSessionFactorydalSessionFactory)
加載完applicationContext-datasource.xml配置文件有,DalSessionFactoryBean注入創建dalsession
@Autowired(required = false)
this.dalSession = new MyDalSession(dalSessionFactory);
3. MapperFactoryBean
public T getObject()
相當於每個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);
三、DALClient的全局事務
1. MyDalSession.DalSessionInterceptor內部類
public Object invoke(Object proxy, Method method,Object[] args)
將事務交給spring全局事務代理
final DalSession dalSession = DalSessionUtils.getHolderSession(dalSessionFactory);
Object result = method.invoke(dalSession,args);
2. DalSessionUtils
public static DalSession getHolderSession(DalSessionFactorydalSessionFactory)
將事務交給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;
3. DalSessionUtils.DalSessionSynchronization 內部類
public voidbeforeCommit(boolean readOnly)
全局事務提交
public voidafterCompletion(int status)
全局事務關閉
四、DALClient數據訪問
1. insert插入
如果是插入,獲取一次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);
2. select查詢
if (SqlCommandType.SELECT == type) {
/**
* 從緩存取
*/
Object object =cache.getObject(args[0]);
result = dalSession.selectOne(ms,args);
}