不知道楼下的同学自己亲手验证过没有,帖子也竟然被投为"新手帖"
按照楼下同学说的,原来可以通过外围构造一个TransactionManager通过setTxManger()方法赋值过去....从而根本不需要更改ibatis的源码了...这个方法确实比原来的好..
String resource = "sql-map-config.xml";
Reader reader = Resources.getResourceAsReader (resource);
SqlMapClientImpl sqlMap = (SqlMapClientImpl) SqlMapClientBuilder.buildSqlMapClient(reader);
TransactionConfig transactionConfig = new ExternalTransactionConfig(); Properties properties = new Properties();
properties.setProperty("SetAutoCommitAllowed", "false");
transactionConfig.setDataSource(getDataSource());
transactionConfig.setProperties(properties);
TransactionManager txManager = new TransactionManager(transactionConfig);
sqlMap.getDelegate().setTxManager(txManager);
今天验证这个方案发现:
transactionConfig.setProperties(properties);
错误:The method setProperties(Properties) is undefined for the type TransactionConfig
以上方案修改如下:
把transactionConfig.setProperties(properties); 更改为transactionConfig.initialize(properties);
题记:
有时候在做项目的时候,Ds需要被其他应用监控,需要用到外部的DataSource,而不能用框架本身的DS..而修改IBATIS的XML配置文件也做不到,无奈今天只能更改源码了...
下面大概简单介绍下各种配置文件和源码.
ibatis的xml配置文件
类似很多dao框架一样, 这个配置有oscache配置,datasource数据库连接池配置,sqlMap映射文件配置,详细配置请看博客或者google吧,这里就不详述了..但重点说下datasource配置:ibatis2.3.0提供3类DS,分别为SIMPLE,DBCP,JNDI..配置方法大同小异.. 配置好后,这样在ibatis初始化的时候就会建立相应的ds和连接池了.
问题所在
1,ibatis可以读取任意一个xml文件,但xml的格式是规定死的..如配置文件必须以 打头等等.
2,xml配置可兼容jndi规范,但是有时候项目中并没有写成jndi,而是以另一种xml配置文件存在.
3,项目中需要用到其他ds,不允许新创建.
解决方案
基于以上的状况,我没有找到更好的解决方案,所以只能更改源码,思路是ibatis不构建自己的ds对象,而是公用其他模块的ds对象,思路很明确,所以代码也好改,原ibatis配置文件不配置ds,外部ds对象作为参数传入ibatis..
具体方法
总共修改2个类,主要是改下参数和赋值了ds对象而已,也没有仔细研究过源码,有不对的地方还请海涵``
//修改SqlMapClientBuilder.java
/** 新增方法,把外部的ds传进去**/
/**
* add ds parameter by cj.yangjun@gmail.com
* @param reader
* @param ds
* @param forceCommit
* @return
*/
public static SqlMapClient buildSqlMapClient(Reader reader,DataSource ds,boolean forceCommit) {
// return new XmlSqlMapClientBuilder().buildSqlMap(reader);
return new SqlMapConfigParser().parse(reader,ds,forceCommit);
}
//修改SqlMapConfigParser.java
/**parser是一个NodeletParser 类,The NodeletParser is a callback based parser similar to SAX.
vars是作者构建的Variables,这里有个疑问**/
public SqlMapClient parse(Reader reader) {
try {
if (vars.sqlMapConfigConv != null) {
System.out.println("null");
reader = vars.sqlMapConfigConv.convertXml(reader);
}
usingStreams = false;
parser.parse(reader);
return vars.client;
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
/**新增方法,把外围ds传进入,并且赋值**/
public SqlMapClient parse(Reader reader,DataSource ds,boolean forceCommit){
vars.dataSource=ds;
vars.errorCtx.setActivity("configuring the transaction manager");
String type = "jdbc";
type = vars.typeHandlerFactory.resolveAlias(type);
TransactionManager txManager = null;//ibatis的思路是要构造一个TransactionManager 对象
try {
vars.errorCtx.setMoreInfo("Check the transaction manager type or class.");
TransactionConfig config = (TransactionConfig) Resources.instantiate(type);//需要构造一个JDBC类型TransactionConfig我们的ds等部分信息去填充这个TransactionConfig,JDBC的其他属性由这个config初始化
config.setDataSource(vars.dataSource);
config.setMaximumConcurrentTransactions(vars.client.getDelegate().getMaxTransactions());
vars.errorCtx.setMoreInfo("Check the transactio nmanager properties or configuration.");
config.initialize(vars.txProps);
vars.errorCtx.setMoreInfo(null);
txManager = new TransactionManager(config);
txManager.setForceCommit(forceCommit);
} catch (Exception e) {
if (e instanceof SqlMapException) {
throw (SqlMapException) e;
} else {
throw new SqlMapException("Error initializing TransactionManager. Could not instantiate TransactionConfig. Cause: " + e, e);
}
}
vars.client.getDelegate().setTxManager(txManager);// 根据这个manager初始化一些事务控制的对象
return parse(reader);//parser是一个NodeletParser ,The NodeletParser is a callback based parser similar to SAX. 读取其他内容并初始化...
}
修改过,简单测试下,应该是可以用的..
疑问
在看的过程对有个地方有个疑问:
有如下结构关系:
public class SqlMapConfigParser extends BaseParser{
...
}
public abstract class BaseParser {
protected final Variables vars;
protected static class Variables {
public ExtendedSqlMapClient client;
public SqlMapExecutorDelegate delegate;
public TypeHandlerFactory typeHandlerFactory;
public DataSource dataSource;
......
}
}
其中Variables 的注释如下:
/**
* Variables the parser uses. This "struct" like class is necessary because
* anonymous inner classes do not have access to non-final member fields of the parent class.
* This way, we can make the Variables instance final, and use all of its public fields as
* variables for parsing state.
*/
我不明白作者精心设计这个"struct"的目的是什么呢?没看明白这里的because
* anonymous inner classes do not have access to non-final member fields of the parent class.