Ibatis源码分析.doc_第1页
Ibatis源码分析.doc_第2页
Ibatis源码分析.doc_第3页
Ibatis源码分析.doc_第4页
Ibatis源码分析.doc_第5页
免费预览已结束,剩余4页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

读ibatis源码为什么说SqlMapClient是线程安全的Ibatis做为一个半自动化的Orm框架有他的缺点和优点。在这里我就不宽泛的说这些了。就说说为什么SqlMapClient是线程安全的,他是怎么实现的。 提出问题: Java代码 1. privatestaticSqlMapClientsqlMapper;2. 3. /*4. *Itsnotagoodideatoputcodethatcanfailinaclassinitializer,5. *butforsakeofargument,hereshowyouconfigureanSQLMap.6. */7. static8. try9. Readerreader=Resources.getResourceAsReader(com/mydomain/data/SqlMapConfig.xml);10. sqlMapper=SqlMapClientBuilder.buildSqlMapClient(reader);11. reader.close();12. catch(IOExceptione)13. /Failfast.14. thrownewRuntimeException(SomethingbadhappenedwhilebuildingtheSqlMapClientinstance.+e,e);15. 16. private static SqlMapClient sqlMapper; /* * Its not a good idea to put code that can fail in a class initializer, * but for sake of argument, heres how you configure an SQL Map. */ static try Reader reader = Resources.getResourceAsReader(com/mydomain/data/SqlMapConfig.xml); sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); catch (IOException e) / Fail fast. throw new RuntimeException(Something bad happened while building the SqlMapClient instance. + e, e); 这是一段ibatis simple工程的代码,大家都能看明白这是一个单例,只有一个SqlMapClient对象存在,在多线程的情况下,SqlMapClient是怎么解决事务隔离呢,怎么共享资源的呢? 一、 SqlMapClient是怎么被创建的 打开SqlMapClientBuilder发现buildSqlMapClien一句话 Java代码 1. publicstaticSqlMapClientbuildSqlMapClient(Readerreader)2. /returnnewXmlSqlMapClientBuilder().buildSqlMap(reader);3. returnnewSqlMapConfigParser().parse(reader);4. public static SqlMapClient buildSqlMapClient(Reader reader) / return new XmlSqlMapClientBuilder().buildSqlMap(reader); return new SqlMapConfigParser().parse(reader); 我们顺着这条线一路看下去 SqlMapConfigParser类的做了两件事把reader交个一个NodeletParser去解析reader(也就是我们的配置文件),在一个就是XmlParserState的一个属性产生一个SqlMapClient对象 Java代码 1. publicclassSqlMapConfigParser2. 3. protectedfinalNodeletParserparser=newNodeletParser();4. privateXmlParserStatestate=newXmlParserState();5. publicSqlMapClientparse(Readerreader)6. try7. usingStreams=false;8. 9. parser.parse(reader);10. returnstate.getConfig().getClient();11. catch(Exceptione)12. thrownewRuntimeException(Erroroccurred.Cause:+e,e);13. 14. public class SqlMapConfigParser protected final NodeletParser parser = new NodeletParser(); private XmlParserState state = new XmlParserState();public SqlMapClient parse(Reader reader) try usingStreams = false; parser.parse(reader); return state.getConfig().getClient(); catch (Exception e) throw new RuntimeException(Error occurred. Cause: + e, e); 打开NodeletParser的parse方法,我们发现他就是解析xml配置文件的 Java代码 1. publicvoidparse(Readerreader)throwsNodeletException2. try3. Documentdoc=createDocument(reader);4. parse(doc.getLastChild();5. catch(Exceptione)6. thrownewNodeletException(ErrorparsingXML.Cause:+e,e);7. 8. public void parse(Reader reader) throws NodeletException try Document doc = createDocument(reader); parse(doc.getLastChild(); catch (Exception e) throw new NodeletException(Error parsing XML. Cause: + e, e); 最后这些文件被分门别类的放在了XmlParserState的这些属性里 Java代码 1. privateSqlMapConfigurationconfig=newSqlMapConfiguration();2. 3. privatePropertiesglobalProps=newProperties();4. privatePropertiestxProps=newProperties();5. privatePropertiesdsProps=newProperties();6. privatePropertiescacheProps=newProperties();7. privatebooleanuseStatementNamespaces=false;8. privateMapsqlIncludes=newHashMap();9. 10. privateParameterMapConfigparamConfig;11. privateResultMapConfigresultConfig;12. privateCacheModelConfigcacheConfig;13. 14. privateStringnamespace;15. privateDataSourcedataSource;private SqlMapConfiguration config = new SqlMapConfiguration(); private Properties globalProps = new Properties(); private Properties txProps = new Properties(); private Properties dsProps = new Properties(); private Properties cacheProps = new Properties(); private boolean useStatementNamespaces = false; private Map sqlIncludes = new HashMap(); private ParameterMapConfig paramConfig; private ResultMapConfig resultConfig; private CacheModelConfig cacheConfig; private String namespace;private DataSource dataSource;现在我们回过头看return state.getConfig().getClient(); 是这句话获得了SqlMapClient对象,这个对象是怎么创建的呢,在SqlMapConfiguration的构造方法里面就已经创建好了。 Java代码 1. publicSqlMapConfiguration()2. errorContext=newErrorContext();3. delegate=newSqlMapExecutorDelegate();4. typeHandlerFactory=delegate.getTypeHandlerFactory();5. client=newSqlMapClientImpl(delegate);6. registerDefaultTypeAliases();7. public SqlMapConfiguration() errorContext = new ErrorContext(); delegate = new SqlMapExecutorDelegate(); typeHandlerFactory = delegate.getTypeHandlerFactory(); client = new SqlMapClientImpl(delegate); registerDefaultTypeAliases(); 原来我们的到的并不是SqlMapClient(接口不能实现)对象,而是他的一个实现SqlMapClientImpl 二、 深入SqlMapClientImpl内部 SqlMapClientImpl类中只有三个字段 Java代码 1. privatestaticfinalLoglog=LogFactory.getLog(SqlMapClientImpl.class);2. 3. publicSqlMapExecutorDelegatedelegate;4. 5. protectedThreadLocallocalSqlMapSession=newThreadLocal(); private static final Log log = LogFactory.getLog(SqlMapClientImpl.class);public SqlMapExecutorDelegate delegate;protected ThreadLocal localSqlMapSession = new ThreadLocal();log是一个日志记录的对象,与线程安全肯定是无关的 SqlMapExecutorDelegate这个类里面有什么东西呢 Java代码 1. privatestaticfinalProbePROBE=ProbeFactory.getProbe();2. 3. privatebooleanlazyLoadingEnabled;4. privatebooleancacheModelsEnabled;5. privatebooleanenhancementEnabled;6. privatebooleanuseColumnLabel=true;7. privatebooleanforceMultipleResultSetSupport;8. 9. privateTransactionManagertxManager;10. 11. privateHashMapmappedStatements;12. privateHashMapcacheModels;13. privateHashMapresultMaps;14. privateHashMapparameterMaps;15. 16. protectedSqlExecutorsqlExecutor;17. privateTypeHandlerFactorytypeHandlerFactory;18. privateDataExchangeFactorydataExchangeFactory;19. 20. privateResultObjectFactoryresultObjectFactory;21. privatebooleanstatementCacheEnabled;private static final Probe PROBE = ProbeFactory.getProbe(); private boolean lazyLoadingEnabled; private boolean cacheModelsEnabled; private boolean enhancementEnabled; private boolean useColumnLabel = true; private boolean forceMultipleResultSetSupport; private TransactionManager txManager; private HashMap mappedStatements; private HashMap cacheModels; private HashMap resultMaps; private HashMap parameterMaps; protected SqlExecutor sqlExecutor; private TypeHandlerFactory typeHandlerFactory; private DataExchangeFactory dataExchangeFactory; private ResultObjectFactory resultObjectFactory; private boolean statementCacheEnabled;这些属性都是一些关于跟sqlMap配置的一些信息,这些信息和线程安全也没有很大的关系。 最后就剩下localSqlMapSession字段了,其实有经验的同学一眼就能看出来这点的,ThreadLocal就是为处理线程安全而来 的,他的实质为每个线程保存一个副本。他的实现就是存在一个全局的Map存放localSqlMapSession,key是线程的id号value值是 一个localSqlMapSession的副本。 SqlMapClientImpl里面的方法: Java代码 1. publicObjectinsert(Stringid,Objectparam)throwsSQLException2. returngetLocalSqlMapSession().insert(id,param);3. 4. 5. publicObjectinsert(Stringid)throwsSQLException6. returngetLocalSqlMapSession().insert(id);7. 8. 9. publicintupdate(Stringid,Objectparam)throwsSQLException10. returngetLocalSqlMapSession().update(id,param);11. 12. 13. publicintupdate(Stringid)throwsSQLException14. returngetLocalSqlMapSession().update(id);15. 16. 17. publicintdelete(Stringid,Objectparam)throwsSQLException18. returngetLocalSqlMapSession().delete(id,param);19. 20. 21. publicintdelete(Stringid)throwsSQLException22. returngetLocalSqlMapSession().delete(id);23. 24. 25. publicObjectqueryForObject(Stringid,ObjectparamObject)throwsSQLException26. returngetLocalSqlMapSession().queryForObject(id,paramObject);27. public Object insert(String id, Object param) throws SQLException return getLocalSqlMapSession().insert(id, param); public Object insert(String id) throws SQLException return getLocalSqlMapSession().insert(id); public int update(String id, Object param) throws SQLException return getLocalSqlMapSession().update(id, param); public int update(String id) throws SQLException return getLocalSqlMapSession().update(id); public int delete(String id, Object param) throws SQLException return getLocalSqlMapSession().delete(id, param); public int delete(String id) throws SQLException return getLocalSqlMapSession().delete(id); public Object queryForObject(String id, Object paramObject) throws SQLException return getLocalSqlMapSession().queryForObject(id, paramObject); 多么熟悉的方法啊,这就是我们经常用的curd的方法。从代码上证明了我们的推测,线程安全就是和localSqlMapSession有关 虽然找到了相关的属性,但是他们是怎么实现的呢。 三、 线程安全的实现。 就dao部分的线程安全来说一个是主要是事务的完成性。如果事务能够保证完整性,那么就可以说是线程安全的。 localSqlMapSession存的是什么什么东西呢,我们打开代码看看。 Java代码 1. protectedSqlMapSessionImplgetLocalSqlMapSession()2. SqlMapSessionImplsqlMapSession=(SqlMapSessionImpl)localSqlMapSession.get();3. if(sqlMapSession=null|sqlMapSession.isClosed()4. sqlMapSession=newSqlMapSessionImpl(this);5. localSqlMapSession.set(sqlMapSession);6. 7. returnsqlMapSession;8. protected SqlMapSessionImpl getLocalSqlMapSession() SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get(); if (sqlMapSession = null | sqlMapSession.isClosed() sqlMapSession = new SqlMapSessionImpl(this); localSqlMapSession.set(sqlMapSession); return sqlMapSession; 再研究一下SqlMapSessionImpl,这个类只有三个字段 protected SqlMapExecutorDelegate delegate; protected SessionScope sessionScope; protected boolean closed; 很明显SessionScope这是我们要找的东西 Java代码 1. privatestaticlongnextId;2. privatelongid;3. /UsedbyAny4. privateSqlMapClientsqlMapClient;5. privateSqlMapExecutorsqlMapExecutor;6. privateSqlMapTransactionManagersqlMapTxMgr;7. privateintrequestStackDepth;8. /UsedbyTransactionManager9. privateTransactiontransaction;10. privateTransactionStatetransactionState;11. /UsedbySqlMapExecutorDelegate.setUserProvidedTransaction()12. privateTransactionStatesavedTransactionState;13. /UsedbyStandardSqlMapClientandGeneralStatement14. privatebooleaninBatch;15. /UsedbySqlExecutor16. privateObjectbatch;17. privatebooleancommitRequired;18. privateMappreparedStatements;private static long nextId; private long id; / Used by Any private SqlMapClient sqlMapClient; private SqlMapExecutor sqlMapExecutor; private SqlMapTransactionManager sqlMapTxMgr; private int requestStackDepth; / Used by TransactionManager private Transaction transaction; private TransactionState transactionState; / Used by SqlMapExecutorDelegate.setUserProvidedTransaction() private TransactionState savedTransactionState; / Used by StandardSqlMapClient and GeneralStatement private boolean inBatch; / Used by SqlExecutor private Object batch; private boolean commitRequired; private Map preparedStatements;根据我们的分析事务的完整性足以保证dao层的线程安全。Transaction保存在ThreadLocal里面证明了SqlMapClient是线程安全的,我们在整个工程中只要一个SqlMapClient对象就够了。 再来看下SessionScope这个类的字段 private SqlMapClient sqlMapClient;保存的是一个SqlMapClient private SqlMapExecutor sqlMapExecutor; 执行sql用的 private SqlMapTransactionManager sqlMapTxMgr; 管理事务的 private int requestStackDepth; / Used by TransactionManager private Transaction transaction; 事务 private TransactionState transactionState; 事务的状态 / Used by SqlMapExecutorDelegate.setUserProvidedTransaction() private TransactionState savedTransactionState; 事务的保存状态 / Used by StandardSqlMapClient and GeneralStatement private boolean inBatch;是否批处理 / Used by SqlExecutor private Object batch; private boolean commitRequired;是否用提交 private Map preparedStatements;这个应该是保存批处理的PreparedStatement 我们突然发现没有连接类Connection,如果用jdbc的话Connection是多么重要的一个对象啊,在这里没有保存Connection呢。打开JdbcTransaction(一个Transaction的实现) Java代码 1. privatestaticfinalLogconnectionLog=LogFactory.getLog(Connection.class);2. 3. privateDataSourcedataSource;4. privateConnectionconnection;5. privateIsolationLevelisolationLevel=newIsolationLevel();6. 7. publicJdbcTransaction(DataSourceds,intisolationLevel)throwsTransactionException8. /CheckParameters9. dataSource=ds;10. if(dataSource=null)11. thrownewTransactionException(JdbcTransactioninitializationfailed.DataSourcewasnull.);12. 13. this.isolationLevel.setIsolationLevel(isolationLevel);14. 15. 16. privatevoidinit()throwsSQLException,TransactionException17. /OpenJDBCTransaction18. connection=dataSource.getConnection();19. if(connection=null)20. thrownewTransactionException(JdbcTransactioncouldnotstarttransaction.Cause:TheDataSourcereturnedanullconnection.);21. 22. /IsolationLevel23. isolationLevel.applyIsolationLevel(connection);24. /AutoCommit25. if(connection.getAutoCommit()26. connection.setAutoCommit(false);27. 28. /Debug29. if(connectionLog.isDebugEnabled()30. connection=ConnectionLogProxy.newInstance(connection);31. 32. 33. 34. publicvoidcommit()throwsSQLException,TransactionException35. if(connection!=null)36. mit();37. 38. 39. 40. publicvoidrollback()throwsSQLException,TransactionException41. if(connection!=null)42. connection.rollback();43. 44. 45. 46. publicvoidclose()throwsSQLException,TransactionException47. if(connection!=null)48. try49. isolationLevel.restoreIsolationLevel(connection);50. finally51. connection.close();52. connection=null;53. 54. 55. 56. 57. publicConnectiongetConnection()throwsSQLException,TransactionException58. if(connection=null)59. init();60. 61. returnconnection;62. private static final Log connectionLog = LogFactory.getLog(Connection.class); private DataSource dataSource; private Connection connection; private IsolationLevel isolationLevel = new IsolationLevel(); public JdbcTransaction(DataSource ds, int isolationLevel) throws TransactionException / Check Parameters dataSource = ds; if (dataSource = null) throw new TransactionException(JdbcTransaction

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论