{"id":10006636,"date":"2022-09-30T14:02:51","date_gmt":"2022-09-30T06:02:51","guid":{"rendered":"https:\/\/ityet.com\/?p=10006636"},"modified":"2022-09-30T14:02:51","modified_gmt":"2022-09-30T06:02:51","slug":"%e6%ba%90%e7%a0%81%e5%ad%a6%e4%b9%a0%e4%b9%8bmybatis%e7%9a%84%e5%ba%95%e5%b1%82%e6%9f%a5%e8%af%a2%e5%8e%9f%e7%90%86","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10006636","title":{"rendered":"\u6e90\u7801\u5b66\u4e60\u4e4bMyBatis\u7684\u5e95\u5c42\u67e5\u8be2\u539f\u7406"},"content":{"rendered":"<h2>\u5bfc\u8bfb<\/h2>\n<p>\u672c\u6587\u901a\u8fc7MyBatis\u4e00\u4e2a\u4f4e\u7248\u672c\u7684bug\uff083.4.5\u4e4b\u524d\u7684\u7248\u672c\uff09\u5165\u624b\uff0c\u5206\u6790MyBatis\u7684\u4e00\u6b21\u5b8c\u6574\u7684\u67e5\u8be2\u6d41\u7a0b\uff0c\u4ece\u914d\u7f6e\u6587\u4ef6\u7684\u89e3\u6790\u5230\u4e00\u4e2a\u67e5\u8be2\u7684\u5b8c\u6574\u6267\u884c\u8fc7\u7a0b\u8be6\u7ec6\u89e3\u8bfbMyBatis\u7684\u4e00\u6b21\u67e5\u8be2\u6d41\u7a0b\uff0c\u901a\u8fc7\u672c\u6587\u53ef\u4ee5\u8be6\u7ec6\u4e86\u89e3MyBatis\u7684\u4e00\u6b21\u67e5\u8be2\u8fc7\u7a0b\u3002\u5728\u5e73\u65f6\u7684\u4ee3\u7801\u7f16\u5199\u4e2d\uff0c\u53d1\u73b0\u4e86MyBatis\u4e00\u4e2a\u4f4e\u7248\u672c\u7684bug\uff083.4.5\u4e4b\u524d\u7684\u7248\u672c\uff09\uff0c\u7531\u4e8e\u73b0\u5728\u5f88\u591a\u5de5\u7a0b\u4e2d\u7684\u7248\u672c\u90fd\u662f\u4f4e\u4e8e3.4.5\u7684\uff0c\u56e0\u6b64\u5728\u8fd9\u91cc\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u4f8b\u5b50\u590d\u73b0\u95ee\u9898\uff0c\u5e76\u4e14\u4ece\u6e90\u7801\u89d2\u5ea6\u5206\u6790MyBatis\u4e00\u6b21\u67e5\u8be2\u7684\u6d41\u7a0b\uff0c\u8ba9\u5927\u5bb6\u4e86\u89e3MyBatis\u7684\u67e5\u8be2\u539f\u7406\u3002<\/p>\n<h2>1 \u95ee\u9898\u73b0\u8c61<\/h2>\n<p><strong>1.1 \u573a\u666f\u95ee\u9898\u590d\u73b0<\/strong><\/p>\n<p>\u5982\u4e0b\u56fe\u6240\u793a\uff0c\u5728\u793a\u4f8bMapper\u4e2d\uff0c\u4e0b\u9762\u63d0\u4f9b\u4e86\u4e00\u4e2a\u65b9\u6cd5queryStudents,\u4ecestudent\u8868\u4e2d\u67e5\u8be2\u51fa\u7b26\u5408\u67e5\u8be2\u6761\u4ef6\u7684\u6570\u636e\uff0c\u5165\u53c2\u53ef\u4ee5\u4e3astudent\/_name\u6216\u8005student\/_name\u7684\u96c6\u5408\uff0c\u793a\u4f8b\u4e2d\u53c2\u6570\u53ea\u4f20\u5165\u7684\u662fstudentName\u7684List\u96c6\u5408<\/p>\n<pre><code> List&lt;String&gt; studentNames = new LinkedList&lt;&gt;();\n studentNames.add(&quot;lct&quot;);\n studentNames.add(&quot;lct2&quot;);\n condition.setStudentNames(studentNames);<\/code><\/pre>\n<pre><code>  &lt;select id=&quot;queryStudents&quot; parameterType=&quot;mybatis.StudentCondition&quot; resultMap=&quot;resultMap&quot;&gt;\n\n\n        select * from student\n        &lt;where&gt;\n            &lt;if test=&quot;studentNames != null and studentNames.size &gt; 0 &quot;&gt;\n                AND student_name IN\n                &lt;foreach collection=&quot;studentNames&quot; item=&quot;studentName&quot; open=&quot;(&quot; separator=&quot;,&quot; close=&quot;)&quot;&gt;\n                    #{studentName, jdbcType=VARCHAR}\n                &lt;\/foreach&gt;\n            &lt;\/if&gt;\n\n\n            &lt;if test=&quot;studentName != null and studentName != '' &quot;&gt;\n                AND student_name = #{studentName, jdbcType=VARCHAR}\n            &lt;\/if&gt;\n        &lt;\/where&gt;\n    &lt;\/select&gt;<\/code><\/pre>\n<p>\u671f\u671b\u8fd0\u884c\u7684\u7ed3\u679c\u662f<\/p>\n<pre><code>select * from student WHERE student_name IN ( 'lct' , 'lct2' )<\/code><\/pre>\n<p>\u4f46\u662f\u5b9e\u9645\u4e0a\u8fd0\u884c\u7684\u7ed3\u679c\u662f<\/p>\n<p>==\/&gt; Preparing: select * from student WHERE student\/_name IN ( ? , ? ) AND student\/_name = ?<\/p>\n<p>==\/&gt; Parameters: lct(String), lct2(String), lct2(String)<\/p>\n<p>&lt;== Columns: id, student_name, age<\/p>\n<p>&lt;== Row: 2, lct2, 2<\/p>\n<p>&lt;== Total: 1<\/p>\n<p>\u901a\u8fc7\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u5230\uff0c\u6ca1\u6709\u7ed9student\/_name\u5355\u72ec\u8d4b\u503c\uff0c\u4f46\u662f\u7ecf\u8fc7MyBatis\u89e3\u6790\u4ee5\u540e\uff0c\u5355\u72ec\u7ed9student\/_name\u8d4b\u503c\u4e86\u4e00\u4e2a\u503c\uff0c\u53ef\u4ee5\u63a8\u65ad\u51faMyBatis\u5728\u89e3\u6790SQL\u5e76\u5bf9\u53d8\u91cf\u8d4b\u503c\u7684\u65f6\u5019\u662f\u6709\u95ee\u9898\u7684\uff0c\u521d\u6b65\u731c\u6d4b\u662fforeach\u5faa\u73af\u4e2d\u7684\u53d8\u91cf\u7684\u503c\u5e26\u5230\u4e86foreach\u5916\u8fb9\uff0c\u5bfc\u81f4SQL\u89e3\u6790\u51fa\u73b0\u5f02\u5e38\uff0c\u4e0b\u9762\u901a\u8fc7\u6e90\u7801\u8fdb\u884c\u5206\u6790\u9a8c\u8bc1<\/p>\n<h2>2 MyBatis\u67e5\u8be2\u539f\u7406<\/h2>\n<p><strong>2.1 MyBatis\u67b6\u6784<\/strong><\/p>\n<p><strong>2.1.1 \u67b6\u6784\u56fe<\/strong><\/p>\n<p>\u5148\u7b80\u5355\u6765\u770b\u770bMyBatis\u6574\u4f53\u4e0a\u7684\u67b6\u6784\u6a21\u578b\uff0c\u4ece\u6574\u4f53\u4e0a\u770bMyBatis\u4e3b\u8981\u5206\u4e3a\u56db\u5927\u6a21\u5757:<\/p>\n<p><strong>\u63a5\u53e3\u5c42<\/strong>\uff1a\u4e3b\u8981\u4f5c\u7528\u5c31\u662f\u548c\u6570\u636e\u5e93\u6253\u4ea4\u9053<\/p>\n<p><strong>\u6570\u636e\u5904\u7406\u5c42<\/strong>\uff1a\u6570\u636e\u5904\u7406\u5c42\u53ef\u4ee5\u8bf4\u662fMyBatis\u7684\u6838\u5fc3\uff0c\u5b83\u8981\u5b8c\u6210\u4e24\u4e2a\u529f\u80fd\uff1a<\/p>\n<ul>\n<li>\u901a\u8fc7\u4f20\u5165\u53c2\u6570\u6784\u5efa\u52a8\u6001SQL\u8bed\u53e5\uff1b<\/li>\n<li>SQL\u8bed\u53e5\u7684\u6267\u884c\u4ee5\u53ca\u5c01\u88c5\u67e5\u8be2\u7ed3\u679c\u96c6\u6210List&lt;E&gt;<\/li>\n<\/ul>\n<p><strong>\u6846\u67b6\u652f\u6491\u5c42<\/strong>\uff1a\u4e3b\u8981\u6709\u4e8b\u52a1\u7ba1\u7406\u3001\u8fde\u63a5\u6c60\u7ba1\u7406\u3001\u7f13\u5b58\u673a\u5236\u548cSQL\u8bed\u53e5\u7684\u914d\u7f6e\u65b9\u5f0f<\/p>\n<p><strong>\u5f15\u5bfc\u5c42<\/strong>\uff1a\u5f15\u5bfc\u5c42\u662f\u914d\u7f6e\u548c\u542f\u52a8MyBatis \u914d\u7f6e\u4fe1\u606f\u7684\u65b9\u5f0f\u3002MyBatis \u63d0\u4f9b\u4e24\u79cd\u65b9\u5f0f\u6765\u5f15\u5bfcMyBatis \uff1a\u57fa\u4e8eXML\u914d\u7f6e\u6587\u4ef6\u7684\u65b9\u5f0f\u548c\u57fa\u4e8eJava API \u7684\u65b9\u5f0f<\/p>\n<p><strong>2.1.2 MyBatis\u56db\u5927\u5bf9\u8c61<\/strong><\/p>\n<p>\u8d2f\u7a7fMyBatis\u6574\u4e2a\u6846\u67b6\u7684\u6709\u56db\u5927\u6838\u5fc3\u5bf9\u8c61\uff0cParameterHandler\u3001ResultSetHandler\u3001StatementHandler\u548cExecutor\uff0c\u56db\u5927\u5bf9\u8c61\u8d2f\u7a7f\u4e86\u6574\u4e2a\u6846\u67b6\u7684\u6267\u884c\u8fc7\u7a0b\uff0c\u56db\u5927\u5bf9\u8c61\u7684\u4e3b\u8981\u4f5c\u7528\u4e3a\uff1a<\/p>\n<ul>\n<li>ParameterHandler\uff1a\u8bbe\u7f6e\u9884\u7f16\u8bd1\u53c2\u6570<\/li>\n<li>ResultSetHandler\uff1a\u5904\u7406SQL\u7684\u8fd4\u56de\u7ed3\u679c\u96c6<\/li>\n<li>StatementHandler\uff1a\u5904\u7406sql\u8bed\u53e5\u9884\u7f16\u8bd1\uff0c\u8bbe\u7f6e\u53c2\u6570\u7b49\u76f8\u5173\u5de5\u4f5c<\/li>\n<li>Executor\uff1aMyBatis\u7684\u6267\u884c\u5668\uff0c\u7528\u4e8e\u6267\u884c\u589e\u5220\u6539\u67e5\u64cd\u4f5c<\/li>\n<\/ul>\n<p><strong>2.2 \u4ece\u6e90\u7801\u89e3\u8bfbMyBatis\u7684\u4e00\u6b21\u67e5\u8be2\u8fc7\u7a0b<\/strong><\/p>\n<p>\u9996\u5148\u7ed9\u51fa\u590d\u73b0\u95ee\u9898\u7684\u4ee3\u7801\u4ee5\u53ca\u76f8\u5e94\u7684\u51c6\u5907\u8fc7\u7a0b<\/p>\n<p><strong>2.2.1 \u6570\u636e\u51c6\u5907<\/strong><\/p>\n<pre><code>CREATE TABLE `student`  (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `student_name` varchar(255) NULL DEFAULT NULL,\n  `age` int(11) NULL DEFAULT NULL,\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 1;\n\n\n-- ----------------------------\n-- Records of student\n-- ----------------------------\nINSERT INTO `student` VALUES (1, 'lct', 1);\nINSERT INTO `student` VALUES (2, 'lct2', 2);<\/code><\/pre>\n<p><strong>2.2.2 \u4ee3\u7801\u51c6\u5907<\/strong><\/p>\n<p>1.mapper\u914d\u7f6e\u6587\u4ef6<\/p>\n<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;!DOCTYPE mapper PUBLIC &quot;-\/\/mybatis.org\/\/DTD Mapper 3.0\/\/EN&quot; &quot;http:\/\/mybatis.org\/dtd\/mybatis-3-mapper.dtd&quot; &gt;\n\n\n&lt;mapper namespace=&quot;mybatis.StudentDao&quot;&gt;\n    &lt;!-- \u6620\u5c04\u5173\u7cfb --&gt;\n    &lt;resultMap id=&quot;resultMap&quot; type=&quot;mybatis.Student&quot;&gt;\n        &lt;id column=&quot;id&quot; property=&quot;id&quot; jdbcType=&quot;BIGINT&quot; \/&gt;\n        &lt;result column=&quot;student_name&quot; property=&quot;studentName&quot; jdbcType=&quot;VARCHAR&quot; \/&gt;\n        &lt;result column=&quot;age&quot; property=&quot;age&quot; jdbcType=&quot;INTEGER&quot; \/&gt;\n\n\n    &lt;\/resultMap&gt;\n\n\n    &lt;select id=&quot;queryStudents&quot; parameterType=&quot;mybatis.StudentCondition&quot; resultMap=&quot;resultMap&quot;&gt;\n\n\n        select * from student\n        &lt;where&gt;\n            &lt;if test=&quot;studentNames != null and studentNames.size &gt; 0 &quot;&gt;\n                AND student_name IN\n                &lt;foreach collection=&quot;studentNames&quot; item=&quot;studentName&quot; open=&quot;(&quot; separator=&quot;,&quot; close=&quot;)&quot;&gt;\n                    #{studentName, jdbcType=VARCHAR}\n                &lt;\/foreach&gt;\n            &lt;\/if&gt;\n\n\n            &lt;if test=&quot;studentName != null and studentName != '' &quot;&gt;\n                AND student_name = #{studentName, jdbcType=VARCHAR}\n            &lt;\/if&gt;\n        &lt;\/where&gt;\n    &lt;\/select&gt;\n\n\n&lt;\/mapper&gt;<\/code><\/pre>\n<p>2.\u793a\u4f8b\u4ee3\u7801<\/p>\n<pre><code>public static void main(String[] args) throws IOException {\n        String resource = &quot;mybatis-config.xml&quot;;\n        InputStream inputStream = Resources.getResourceAsStream(resource);\n        \/\/1.\u83b7\u53d6SqlSessionFactory\u5bf9\u8c61\n        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n        \/\/2.\u83b7\u53d6\u5bf9\u8c61\n        SqlSession sqlSession = sqlSessionFactory.openSession();\n        \/\/3.\u83b7\u53d6\u63a5\u53e3\u7684\u4ee3\u7406\u7c7b\u5bf9\u8c61\n        StudentDao mapper = sqlSession.getMapper(StudentDao.class);\n        StudentCondition condition = new StudentCondition();\n        List&lt;String&gt; studentNames = new LinkedList&lt;&gt;();\n        studentNames.add(&quot;lct&quot;);\n        studentNames.add(&quot;lct2&quot;);\n        condition.setStudentNames(studentNames);\n        \/\/\u6267\u884c\u65b9\u6cd5\n        List&lt;Student&gt; students = mapper.queryStudents(condition);\n    }<\/code><\/pre>\n<p><strong>2.2.3 \u67e5\u8be2\u8fc7\u7a0b\u5206\u6790<\/strong><\/p>\n<p>1.SqlSessionFactory\u7684\u6784\u5efa<\/p>\n<p>\u5148\u770bSqlSessionFactory\u7684\u5bf9\u8c61\u7684\u521b\u5efa\u8fc7\u7a0b<\/p>\n<pre><code>\/\/1.\u83b7\u53d6SqlSessionFactory\u5bf9\u8c61\nSqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);<\/code><\/pre>\n<p>\u4ee3\u7801\u4e2d\u9996\u5148\u901a\u8fc7\u8c03\u7528SqlSessionFactoryBuilder\u4e2d\u7684build\u65b9\u6cd5\u6765\u83b7\u53d6\u5bf9\u8c61\uff0c\u8fdb\u5165build\u65b9\u6cd5<\/p>\n<pre><code> public SqlSessionFactory build(InputStream inputStream) {\n    return build(inputStream, null, null);\n  }<\/code><\/pre>\n<p>\u8c03\u7528\u81ea\u8eab\u7684build\u65b9\u6cd5<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564261\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe1 build\u65b9\u6cd5\u81ea\u8eab\u8c03\u7528\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u5728\u8fd9\u4e2a\u65b9\u6cd5\u91cc\u4f1a\u521b\u5efa\u4e00\u4e2aXMLConfigBuilder\u7684\u5bf9\u8c61\uff0c\u7528\u6765\u89e3\u6790\u4f20\u5165\u7684MyBatis\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u7136\u540e\u8c03\u7528parse\u65b9\u6cd5\u8fdb\u884c\u89e3\u6790<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564262\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe2 parse\u89e3\u6790\u5165\u53c2\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u4f1a\u4eceMyBatis\u7684\u914d\u7f6e\u6587\u4ef6\u7684\u6839\u76ee\u5f55\u4e2d\u83b7\u53d6xml\u7684\u5185\u5bb9\uff0c\u5176\u4e2dparser\u8fd9\u4e2a\u5bf9\u8c61\u662f\u4e00\u4e2aXPathParser\u7684\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u662f\u4e13\u95e8\u7528\u6765\u89e3\u6790xml\u6587\u4ef6\u7684\uff0c\u5177\u4f53\u600e\u4e48\u4ecexml\u6587\u4ef6\u4e2d\u83b7\u53d6\u5230\u5404\u4e2a\u8282\u70b9\u8fd9\u91cc\u4e0d\u518d\u8fdb\u884c\u8bb2\u89e3\u3002\u8fd9\u91cc\u53ef\u4ee5\u770b\u5230\u89e3\u6790\u914d\u7f6e\u6587\u4ef6\u662f\u4ececonfiguration\u8fd9\u4e2a\u8282\u70b9\u5f00\u59cb\u7684\uff0c\u5728MyBatis\u7684\u914d\u7f6e\u6587\u4ef6\u4e2d\u8fd9\u4e2a\u8282\u70b9\u4e5f\u662f\u6839\u8282\u70b9<\/p>\n<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;\n&lt;!DOCTYPE configuration\n        PUBLIC &quot;-\/\/mybatis.org\/\/DTD Config 3.0\/\/EN&quot;\n        &quot;http:\/\/mybatis.org\/dtd\/mybatis-3-config.dtd&quot;&gt;\n&lt;configuration&gt;\n\n\n    &lt;properties&gt;\n        &lt;property name=&quot;dialect&quot; value=&quot;MYSQL&quot; \/&gt;  &lt;!-- SQL\u65b9\u8a00 --&gt;\n    &lt;\/properties&gt;<\/code><\/pre>\n<p>\u7136\u540e\u5c06\u89e3\u6790\u597d\u7684xml\u6587\u4ef6\u4f20\u5165parseConfiguration\u65b9\u6cd5\u4e2d\uff0c\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\u4f1a\u83b7\u53d6\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u5404\u4e2a\u8282\u70b9\u7684\u914d\u7f6e<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564263\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe3 \u89e3\u6790\u914d\u7f6e\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u4ee5\u83b7\u53d6mappers\u8282\u70b9\u7684\u914d\u7f6e\u6765\u770b\u5177\u4f53\u7684\u89e3\u6790\u8fc7\u7a0b<\/p>\n<pre><code> &lt;mappers&gt;\n        &lt;mapper resource=&quot;mappers\/StudentMapper.xml&quot;\/&gt;\n    &lt;\/mappers&gt;<\/code><\/pre>\n<p>\u8fdb\u5165mapperElement\u65b9\u6cd5<\/p>\n<pre><code>mapperElement(root.evalNode(&quot;mappers&quot;));<\/code><\/pre>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564264\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe4 mapperElement\u65b9\u6cd5\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u770b\u5230MyBatis\u8fd8\u662f\u901a\u8fc7\u521b\u5efa\u4e00\u4e2aXMLMapperBuilder\u5bf9\u8c61\u6765\u5bf9mappers\u8282\u70b9\u8fdb\u884c\u89e3\u6790\uff0c\u5728parse\u65b9\u6cd5\u4e2d<\/p>\n<pre><code>public void parse() {\n  if (!configuration.isResourceLoaded(resource)) {\n    configurationElement(parser.evalNode(&quot;\/mapper&quot;));\n    configuration.addLoadedResource(resource);\n    bindMapperForNamespace();\n  }\n\n\n  parsePendingResultMaps();\n  parsePendingCacheRefs();\n  parsePendingStatements();\n}<\/code><\/pre>\n<p>\u901a\u8fc7\u8c03\u7528configurationElement\u65b9\u6cd5\u6765\u89e3\u6790\u914d\u7f6e\u7684\u6bcf\u4e00\u4e2amapper\u6587\u4ef6<\/p>\n<pre><code>private void configurationElement(XNode context) {\n  try {\n    String namespace = context.getStringAttribute(&quot;namespace&quot;);\n    if (namespace == null || namespace.equals(&quot;&quot;)) {\n      throw new BuilderException(&quot;Mapper's namespace cannot be empty&quot;);\n    }\n    builderAssistant.setCurrentNamespace(namespace);\n    cacheRefElement(context.evalNode(&quot;cache-ref&quot;));\n    cacheElement(context.evalNode(&quot;cache&quot;));\n    parameterMapElement(context.evalNodes(&quot;\/mapper\/parameterMap&quot;));\n    resultMapElements(context.evalNodes(&quot;\/mapper\/resultMap&quot;));\n    sqlElement(context.evalNodes(&quot;\/mapper\/sql&quot;));\n    buildStatementFromContext(context.evalNodes(&quot;select|insert|update|delete&quot;));\n  } catch (Exception e) {\n    throw new BuilderException(&quot;Error parsing Mapper XML. Cause: &quot; + e, e);\n  }\n}<\/code><\/pre>\n<p>\u4ee5\u89e3\u6790mapper\u4e2d\u7684\u589e\u5220\u6539\u67e5\u7684\u6807\u7b7e\u6765\u770b\u770b\u662f\u5982\u4f55\u89e3\u6790\u4e00\u4e2amapper\u6587\u4ef6\u7684<\/p>\n<p>\u8fdb\u5165buildStatementFromContext\u65b9\u6cd5<\/p>\n<pre><code>private void buildStatementFromContext(List&lt;XNode&gt; list, String requiredDatabaseId) {\n  for (XNode context : list) {\n    final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);\n    try {\n      statementParser.parseStatementNode();\n    } catch (IncompleteElementException e) {\n      configuration.addIncompleteStatement(statementParser);\n    }\n  }\n}<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u5230MyBatis\u8fd8\u662f\u901a\u8fc7\u521b\u5efa\u4e00\u4e2aXMLStatementBuilder\u5bf9\u8c61\u6765\u5bf9\u589e\u5220\u6539\u67e5\u8282\u70b9\u8fdb\u884c\u89e3\u6790\uff0c\u901a\u8fc7\u8c03\u7528\u8fd9\u4e2a\u5bf9\u8c61\u7684parseStatementNode\u65b9\u6cd5\uff0c\u5728\u8fd9\u4e2a\u65b9\u6cd5\u91cc\u4f1a\u83b7\u53d6\u5230\u914d\u7f6e\u5728\u8fd9\u4e2a\u6807\u7b7e\u4e0b\u7684\u6240\u6709\u914d\u7f6e\u4fe1\u606f\uff0c\u7136\u540e\u8fdb\u884c\u8bbe\u7f6e<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564265\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe5 parseStatementNode\u65b9\u6cd5\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u89e3\u6790\u5b8c\u6210\u4ee5\u540e\uff0c\u901a\u8fc7\u65b9\u6cd5addMappedStatement\u5c06\u6240\u6709\u7684\u914d\u7f6e\u90fd\u6dfb\u52a0\u5230\u4e00\u4e2aMappedStatement\u4e2d\u53bb\uff0c\u7136\u540e\u518d\u5c06mappedstatement\u6dfb\u52a0\u5230configuration\u4e2d\u53bb<\/p>\n<pre><code>builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,\n    fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,\n    resultSetTypeEnum, flushCache, useCache, resultOrdered, \n    keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);<\/code><\/pre>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564266\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u53ef\u4ee5\u770b\u5230\u4e00\u4e2amappedstatement\u4e2d\u5305\u542b\u4e86\u4e00\u4e2a\u589e\u5220\u6539\u67e5\u6807\u7b7e\u7684\u8be6\u7ec6\u4fe1\u606f<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564267\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe7 mappedstatement\u5bf9\u8c61\u65b9\u6cd5\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u800c\u4e00\u4e2aconfiguration\u5c31\u5305\u542b\u4e86\u6240\u6709\u7684\u914d\u7f6e\u4fe1\u606f\uff0c\u5176\u4e2dmapperRegistertry\u548cmappedStatements<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564268\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe8 config\u5bf9\u8c61\u65b9\u6cd5\u8c03\u8bd5\u56fe\u4f8b<\/p>\n<p>\u5177\u4f53\u7684\u6d41\u7a0b<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564269\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe9 SqlSessionFactory\u5bf9\u8c61\u7684\u6784\u5efa\u8fc7\u7a0b \u56fe9 SqlSessionFactory\u5bf9\u8c61\u7684\u6784\u5efa\u8fc7\u7a0b<\/p>\n<p>2.SqlSession\u7684\u521b\u5efa\u8fc7\u7a0b<\/p>\n<p>SqlSessionFactory\u521b\u5efa\u5b8c\u6210\u4ee5\u540e\uff0c\u63a5\u4e0b\u6765\u770b\u770bSqlSession\u7684\u521b\u5efa\u8fc7\u7a0b<\/p>\n<pre><code>SqlSession sqlSession = sqlSessionFactory.openSession();<\/code><\/pre>\n<p>\u9996\u5148\u4f1a\u8c03\u7528DefaultSqlSessionFactory\u7684openSessionFromDataSource\u65b9\u6cd5<\/p>\n<pre><code>@Override\npublic SqlSession openSession() {\n  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);\n}<\/code><\/pre>\n<p>\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u9996\u5148\u4f1a\u4ececonfiguration\u4e2d\u83b7\u53d6DataSource\u7b49\u5c5e\u6027\u7ec4\u6210\u5bf9\u8c61Environment\uff0c\u5229\u7528Environment\u5185\u7684\u5c5e\u6027\u6784\u5efa\u4e00\u4e2a\u4e8b\u52a1\u5bf9\u8c61TransactionFactory<\/p>\n<pre><code>private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {\n  Transaction tx = null;\n  try {\n    final Environment environment = configuration.getEnvironment();\n    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);\n    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);\n    final Executor executor = configuration.newExecutor(tx, execType);\n    return new DefaultSqlSession(configuration, executor, autoCommit);\n  } catch (Exception e) {\n    closeTransaction(tx); \/\/ may have fetched a connection so lets call close()\n    throw ExceptionFactory.wrapException(&quot;Error opening session.  Cause: &quot; + e, e);\n  } finally {\n    ErrorContext.instance().reset();\n  }\n}<\/code><\/pre>\n<p>\u4e8b\u52a1\u521b\u5efa\u5b8c\u6210\u4ee5\u540e\u5f00\u59cb\u521b\u5efaExecutor\u5bf9\u8c61\uff0cExecutor\u5bf9\u8c61\u7684\u521b\u5efa\u662f\u6839\u636e executorType\u521b\u5efa\u7684\uff0c\u9ed8\u8ba4\u662fSIMPLE\u7c7b\u578b\u7684\uff0c\u6ca1\u6709\u914d\u7f6e\u7684\u60c5\u51b5\u4e0b\u521b\u5efa\u4e86SimpleExecutor\uff0c\u5982\u679c\u5f00\u542f\u4e8c\u7ea7\u7f13\u5b58\u7684\u8bdd\uff0c\u5219\u4f1a\u521b\u5efaCachingExecutor<\/p>\n<pre><code>public Executor newExecutor(Transaction transaction, ExecutorType executorType) {\n  executorType = executorType == null ? defaultExecutorType : executorType;\n  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;\n  Executor executor;\n  if (ExecutorType.BATCH == executorType) {\n    executor = new BatchExecutor(this, transaction);\n  } else if (ExecutorType.REUSE == executorType) {\n    executor = new ReuseExecutor(this, transaction);\n  } else {\n    executor = new SimpleExecutor(this, transaction);\n  }\n  if (cacheEnabled) {\n    executor = new CachingExecutor(executor);\n  }\n  executor = (Executor) interceptorChain.pluginAll(executor);\n  return executor;\n}<\/code><\/pre>\n<p>\u521b\u5efaexecutor\u4ee5\u540e\uff0c\u4f1a\u6267\u884cexecutor = (Executor)  <br \/>interceptorChain.pluginAll(executor)\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u5bf9\u5e94\u7684\u542b\u4e49\u662f\u4f7f\u7528\u6bcf\u4e00\u4e2a\u62e6\u622a\u5668\u5305\u88c5\u5e76\u8fd4\u56deexecutor\uff0c\u6700\u540e\u8c03\u7528DefaultSqlSession\u65b9\u6cd5\u521b\u5efaSqlSession<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564270\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe10 SqlSession\u5bf9\u8c61\u7684\u521b\u5efa\u8fc7\u7a0b<\/p>\n<p>3.Mapper\u7684\u83b7\u53d6\u8fc7\u7a0b<\/p>\n<p>\u6709\u4e86SqlSessionFactory\u548cSqlSession\u4ee5\u540e\uff0c\u5c31\u9700\u8981\u83b7\u53d6\u5bf9\u5e94\u7684Mapper\uff0c\u5e76\u6267\u884cmapper\u4e2d\u7684\u65b9\u6cd5<\/p>\n<pre><code>StudentDao mapper = sqlSession.getMapper(StudentDao.class);<\/code><\/pre>\n<p>\u5728\u7b2c\u4e00\u6b65\u4e2d\u77e5\u9053\u6240\u6709\u7684mapper\u90fd\u653e\u5728MapperRegistry\u8fd9\u4e2a\u5bf9\u8c61\u4e2d\uff0c\u56e0\u6b64\u901a\u8fc7\u8c03\u7528  <br \/>org.apache.ibatis.binding.MapperRegistry#getMapper\u65b9\u6cd5\u6765\u83b7\u53d6\u5bf9\u5e94\u7684mapper<\/p>\n<pre><code>public &lt;T&gt; T getMapper(Class&lt;T&gt; type, SqlSession sqlSession) {\n  final MapperProxyFactory&lt;T&gt; mapperProxyFactory = (MapperProxyFactory&lt;T&gt;) knownMappers.get(type);\n  if (mapperProxyFactory == null) {\n    throw new BindingException(&quot;Type &quot; + type + &quot; is not known to the MapperRegistry.&quot;);\n  }\n  try {\n    return mapperProxyFactory.newInstance(sqlSession);\n  } catch (Exception e) {\n    throw new BindingException(&quot;Error getting mapper instance. Cause: &quot; + e, e);\n  }\n}<\/code><\/pre>\n<p>\u5728MyBatis\u4e2d\uff0c\u6240\u6709\u7684mapper\u5bf9\u5e94\u7684\u90fd\u662f\u4e00\u4e2a\u4ee3\u7406\u7c7b\uff0c\u83b7\u53d6\u5230mapper\u5bf9\u5e94\u7684\u4ee3\u7406\u7c7b\u4ee5\u540e\u6267\u884cnewInstance\u65b9\u6cd5\uff0c\u83b7\u53d6\u5230\u5bf9\u5e94\u7684\u5b9e\u4f8b\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u5b9e\u4f8b\u8fdb\u884c\u65b9\u6cd5\u7684\u8c03\u7528<\/p>\n<pre><code>public class MapperProxyFactory&lt;T&gt; {\n\n\n  private final Class&lt;T&gt; mapperInterface;\n  private final Map&lt;Method, MapperMethod&gt; methodCache = new ConcurrentHashMap&lt;Method, MapperMethod&gt;();\n\n\n  public MapperProxyFactory(Class&lt;T&gt; mapperInterface) {\n    this.mapperInterface = mapperInterface;\n  }\n\n\n  public Class&lt;T&gt; getMapperInterface() {\n    return mapperInterface;\n  }\n\n\n  public Map&lt;Method, MapperMethod&gt; getMethodCache() {\n    return methodCache;\n  }\n\n\n  @SuppressWarnings(&quot;unchecked&quot;)\n  protected T newInstance(MapperProxy&lt;T&gt; mapperProxy) {\n    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);\n  }\n\n\n  public T newInstance(SqlSession sqlSession) {\n    final MapperProxy&lt;T&gt; mapperProxy = new MapperProxy&lt;T&gt;(sqlSession, mapperInterface, methodCache);\n    return newInstance(mapperProxy);\n  }\n\n\n}<\/code><\/pre>\n<p>\u83b7\u53d6mapper\u7684\u6d41\u7a0b\u4e3a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564271\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe11 Mapper\u7684\u83b7\u53d6\u8fc7\u7a0b<\/p>\n<p>4.\u67e5\u8be2\u8fc7\u7a0b<\/p>\n<p>\u83b7\u53d6\u5230mapper\u4ee5\u540e\uff0c\u5c31\u53ef\u4ee5\u8c03\u7528\u5177\u4f53\u7684\u65b9\u6cd5<\/p>\n<pre><code>\/\/\u6267\u884c\u65b9\u6cd5\nList&lt;Student&gt; students = mapper.queryStudents(condition);<\/code><\/pre>\n<p>\u9996\u5148\u4f1a\u8c03\u7528  <br \/>org.apache.ibatis.binding.MapperProxy#invoke\u7684\u65b9\u6cd5\uff0c\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u4f1a\u8c03\u7528org.apache.ibatis.binding.MapperMethod#execute<\/p>\n<pre><code>public Object execute(SqlSession sqlSession, Object[] args) {\n  Object result;\n  switch (command.getType()) {\n    case INSERT: {\n   Object param = method.convertArgsToSqlCommandParam(args);\n      result = rowCountResult(sqlSession.insert(command.getName(), param));\n      break;\n    }\n    case UPDATE: {\n      Object param = method.convertArgsToSqlCommandParam(args);\n      result = rowCountResult(sqlSession.update(command.getName(), param));\n      break;\n    }\n    case DELETE: {\n      Object param = method.convertArgsToSqlCommandParam(args);\n      result = rowCountResult(sqlSession.delete(command.getName(), param));\n      break;\n    }\n    case SELECT:\n      if (method.returnsVoid() &amp;&amp; method.hasResultHandler()) {\n        executeWithResultHandler(sqlSession, args);\n        result = null;\n      } else if (method.returnsMany()) {\n        result = executeForMany(sqlSession, args);\n      } else if (method.returnsMap()) {\n        result = executeForMap(sqlSession, args);\n      } else if (method.returnsCursor()) {\n        result = executeForCursor(sqlSession, args);\n      } else {\n        Object param = method.convertArgsToSqlCommandParam(args);\n        result = sqlSession.selectOne(command.getName(), param);\n      }\n      break;\n    case FLUSH:\n      result = sqlSession.flushStatements();\n      break;\n    default:\n      throw new BindingException(&quot;Unknown execution method for: &quot; + command.getName());\n  }\n  if (result == null &amp;&amp; method.getReturnType().isPrimitive() &amp;&amp; !method.returnsVoid()) {\n    throw new BindingException(&quot;Mapper method '&quot; + command.getName() \n        + &quot; attempted to return null from a method with a primitive return type (&quot; + method.getReturnType() + &quot;).&quot;);\n  }\n  return result;\n}<\/code><\/pre>\n<p>\u9996\u5148\u6839\u636eSQL\u7684\u7c7b\u578b\u589e\u5220\u6539\u67e5\u51b3\u5b9a\u6267\u884c\u54ea\u4e2a\u65b9\u6cd5\uff0c\u5728\u6b64\u6267\u884c\u7684\u662fSELECT\u65b9\u6cd5\uff0c\u5728SELECT\u4e2d\u6839\u636e\u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u7c7b\u578b\u51b3\u5b9a\u6267\u884c\u54ea\u4e2a\u65b9\u6cd5\uff0c\u53ef\u4ee5\u770b\u5230\u5728select\u4e2d\u6ca1\u6709selectone\u5355\u72ec\u65b9\u6cd5\uff0c\u90fd\u662f\u901a\u8fc7selectList\u65b9\u6cd5\uff0c\u901a\u8fc7\u8c03\u7528  <br \/>org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object)\u65b9\u6cd5\u6765\u83b7\u53d6\u5230\u6570\u636e<\/p>\n<pre><code>@Override\npublic &lt;E&gt; List&lt;E&gt; selectList(String statement, Object parameter, RowBounds rowBounds) {\n  try {\n    MappedStatement ms = configuration.getMappedStatement(statement);\n    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);\n  } catch (Exception e) {\n    throw ExceptionFactory.wrapException(&quot;Error querying database.  Cause: &quot; + e, e);\n  } finally {\n    ErrorContext.instance().reset();\n  }\n}<\/code><\/pre>\n<p>\u5728selectList\u4e2d\uff0c\u9996\u5148\u4ececonfiguration\u5bf9\u8c61\u4e2d\u83b7\u53d6MappedStatement,\u5728statement\u4e2d\u5305\u542b\u4e86Mapper\u7684\u76f8\u5173\u4fe1\u606f\uff0c\u7136\u540e\u8c03\u7528  <br \/>org.apache.ibatis.executor.CachingExecutor#query()\u65b9\u6cd5<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564272\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe12 query()\u65b9\u6cd5\u8c03\u8bd5\u56fe\u793a<\/p>\n<p>\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u9996\u5148\u5bf9SQL\u8fdb\u884c\u89e3\u6790\u6839\u636e\u5165\u53c2\u548c\u539f\u59cbSQL\uff0c\u5bf9SQL\u8fdb\u884c\u62fc\u63a5<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564273\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe13 SQL\u62fc\u63a5\u8fc7\u7a0b\u4ee3\u7801\u56fe\u793a<\/p>\n<p>\u8c03\u7528MapperedStatement\u91cc\u7684getBoundSql\u6700\u7ec8\u89e3\u6790\u51fa\u6765\u7684SQL\u4e3a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564274\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe14 SQL\u62fc\u63a5\u8fc7\u7a0b\u7ed3\u679c\u56fe\u793a<\/p>\n<p>\u63a5\u4e0b\u6765\u8c03\u7528  <br \/>org.apache.ibatis.parsing.GenericTokenParser#parse\u5bf9\u89e3\u6790\u51fa\u6765\u7684SQL\u8fdb\u884c\u89e3\u6790<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564275\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe15 SQL\u89e3\u6790\u8fc7\u7a0b\u56fe\u793a<\/p>\n<p>\u6700\u7ec8\u89e3\u6790\u7684\u7ed3\u679c\u4e3a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564276\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe16 SQL\u89e3\u6790\u7ed3\u679c\u56fe\u793a<\/p>\n<p>\u6700\u540e\u4f1a\u8c03\u7528SimpleExecutor\u4e2d\u7684doQuery\u65b9\u6cd5\uff0c\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u4f1a\u83b7\u53d6StatementHandler\uff0c\u7136\u540e\u8c03\u7528  <br \/>org.apache.ibatis.executor.statement.PreparedStatementHandler#parameterize\u8fd9\u4e2a\u65b9\u6cd5\u8fdb\u884c\u53c2\u6570\u548cSQL\u7684\u5904\u7406\uff0c\u6700\u540e\u8c03\u7528statement\u7684execute\u65b9\u6cd5\u83b7\u53d6\u5230\u7ed3\u679c\u96c6\uff0c\u7136\u540e \u5229\u7528resultHandler\u5bf9\u7ed3\u8fdb\u884c\u5904\u7406<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564277\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe17 SQL\u5904\u7406\u7ed3\u679c\u56fe\u793a<\/p>\n<p>\u67e5\u8be2\u7684\u4e3b\u8981\u6d41\u7a0b\u4e3a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564278\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564279\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe18 \u67e5\u8be2\u6d41\u7a0b\u5904\u7406\u56fe\u793a<\/p>\n<p>5.\u67e5\u8be2\u6d41\u7a0b\u603b\u7ed3<\/p>\n<p>\u603b\u7ed3\u6574\u4e2a\u67e5\u8be2\u6d41\u7a0b\u5982\u4e0b<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564280\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe19 \u67e5\u8be2\u6d41\u7a0b\u62bd\u8c61<\/p>\n<p><strong>2.3 \u573a\u666f\u95ee\u9898\u539f\u56e0\u53ca\u89e3\u51b3\u65b9\u6848<\/strong><\/p>\n<p><strong>2.3.1 \u4e2a\u4eba\u6392\u67e5<\/strong><\/p>\n<p>\u8fd9\u4e2a\u95eebug\u51fa\u73b0\u7684\u5730\u65b9\u5728\u4e8e\u7ed1\u5b9aSQL\u53c2\u6570\u7684\u65f6\u5019\u518d\u6e90\u7801\u4e2d\u4f4d\u7f6e\u4e3a<\/p>\n<pre><code> @Override\n public &lt;E&gt; List&lt;E&gt; query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {\n   BoundSql boundSql = ms.getBoundSql(parameter);\n   CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);\n   return query(ms, parameter, rowBounds, resultHandler, key, boundSql);\n}<\/code><\/pre>\n<p>\u7531\u4e8e\u6240\u5199\u7684SQL\u662f\u4e00\u4e2a\u52a8\u6001\u7ed1\u5b9a\u53c2\u6570\u7684SQL\uff0c\u56e0\u6b64\u6700\u7ec8\u4f1a\u8d70\u5230  <br \/>org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\u53bb<\/p>\n<pre><code>public BoundSql getBoundSql(Object parameterObject) {\n  BoundSql boundSql = sqlSource.getBoundSql(parameterObject);\n  List&lt;ParameterMapping&gt; parameterMappings = boundSql.getParameterMappings();\n  if (parameterMappings == null || parameterMappings.isEmpty()) {\n    boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);\n  }\n\n\n  \/\/ check for nested result maps in parameter mappings (issue #30)\n  for (ParameterMapping pm : boundSql.getParameterMappings()) {\n    String rmId = pm.getResultMapId();\n    if (rmId != null) {\n      ResultMap rm = configuration.getResultMap(rmId);\n      if (rm != null) {\n        hasNestedResultMaps |= rm.hasNestedResultMaps();\n      }\n    }\n  }\n\n\n  return boundSql;\n}<\/code><\/pre>\n<p>\u5728\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\uff0c\u4f1a\u8c03\u7528 rootSqlNode.apply(context)\u65b9\u6cd5\uff0c\u7531\u4e8e\u8fd9\u4e2a\u6807\u7b7e\u662f\u4e00\u4e2aforeach\u6807\u7b7e\uff0c\u56e0\u6b64\u8fd9\u4e2aapply\u65b9\u6cd5\u4f1a\u8c03\u7528\u5230  <br \/>org.apache.ibatis.scripting.xmltags.ForEachSqlNode#apply\u8fd9\u4e2a\u65b9\u6cd5\u4e2d\u53bb<\/p>\n<pre><code>@Override\npublic boolean apply(DynamicContext context) {\n  Map&lt;String, Object&gt; bindings = context.getBindings();\n  final Iterable&lt;?&gt; iterable = evaluator.evaluateIterable(collectionExpression, bindings);\n  if (!iterable.iterator().hasNext()) {\n    return true;\n  }\n  boolean first = true;\n  applyOpen(context);\n  int i = 0;\n  for (Object o : iterable) {\n    DynamicContext oldContext = context;\n    if (first) {\n      context = new PrefixedContext(context, &quot;&quot;);\n    } else if (separator != null) {\n      context = new PrefixedContext(context, separator);\n    } else {\n        context = new PrefixedContext(context, &quot;&quot;);\n    }\n    int uniqueNumber = context.getUniqueNumber();\n    \/\/ Issue #709 \n    if (o instanceof Map.Entry) {\n      @SuppressWarnings(&quot;unchecked&quot;) \n      Map.Entry&lt;Object, Object&gt; mapEntry = (Map.Entry&lt;Object, Object&gt;) o;\n      applyIndex(context, mapEntry.getKey(), uniqueNumber);\n      applyItem(context, mapEntry.getValue(), uniqueNumber);\n    } else {\n      applyIndex(context, i, uniqueNumber);\n      applyItem(context, o, uniqueNumber);\n    }\n    contents.apply(new FilteredDynamicContext(configuration, context, index, item, uniqueNumber));\n    if (first) {\n      first = !((PrefixedContext) context).isPrefixApplied();\n    }\n    context = oldContext;\n    i++;\n  }\n  applyClose(context);\n  return true;\n}<\/code><\/pre>\n<p>\u5f53\u8c03\u7528appItm\u65b9\u6cd5\u7684\u65f6\u5019\u5c06\u53c2\u6570\u8fdb\u884c\u7ed1\u5b9a\uff0c\u53c2\u6570\u7684\u53d8\u91cf\u95ee\u9898\u90fd\u4f1a\u5b58\u5728bindings\u8fd9\u4e2a\u53c2\u6570\u4e2d\u533a<\/p>\n<pre><code>private void applyItem(DynamicContext context, Object o, int i) {\n  if (item != null) {\n    context.bind(item, o);\n    context.bind(itemizeItem(item, i), o);\n  }\n}<\/code><\/pre>\n<p>\u8fdb\u884c\u7ed1\u5b9a\u53c2\u6570\u7684\u65f6\u5019\uff0c\u7ed1\u5b9a\u5b8c\u6210foreach\u7684\u65b9\u6cd5\u7684\u65f6\u5019\uff0c\u53ef\u4ee5\u770b\u5230bindings\u4e2d\u4e0d\u6b62\u7ed1\u5b9a\u4e86foreach\u4e2d\u7684\u4e24\u4e2a\u53c2\u6570\u8fd8\u989d\u5916\u6709\u4e00\u4e2a\u53c2\u6570\u540d\u5b57studentName-&gt;lct2,\u4e5f\u5c31\u662f\u8bf4\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u4e5f\u662f\u4f1a\u51fa\u73b0\u5728bindings\u8fd9\u4e2a\u53c2\u6570\u4e2d\u7684\uff0c<\/p>\n<pre><code>private void applyItem(DynamicContext context, Object o, int i) {\n  if (item != null) {\n    context.bind(item, o);\n    context.bind(itemizeItem(item, i), o);\n  }\n}<\/code><\/pre>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564281\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe20 \u53c2\u6570\u7ed1\u5b9a\u8fc7\u7a0b<\/p>\n<p>\u6700\u540e\u5224\u5b9a<\/p>\n<p>org.apache.ibatis.scripting.xmltags.IfSqlNode#apply<\/p>\n<pre><code>@Override\npublic boolean apply(DynamicContext context) {\n  if (evaluator.evaluateBoolean(test, context.getBindings())) {\n    contents.apply(context);\n    return true;\n  }\n  return false;\n}\n\n<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u5230\u5728\u8c03\u7528evaluateBoolean\u65b9\u6cd5\u7684\u65f6\u5019\u4f1a\u628acontext.getBindings()\u5c31\u662f\u524d\u8fb9\u63d0\u5230\u7684bindings\u53c2\u6570\u4f20\u5165\u8fdb\u53bb\uff0c\u56e0\u4e3a\u73b0\u5728\u8fd9\u4e2a\u53c2\u6570\u4e2d\u6709\u4e00\u4e2astudentName,\u56e0\u6b64\u5728\u4f7f\u7528Ognl\u8868\u8fbe\u5f0f\u7684\u65f6\u5019\uff0c\u5224\u5b9a\u4e3a\u8fd9\u4e2aif\u6807\u7b7e\u662f\u6709\u503c\u7684\u56e0\u6b64\u5c06\u8fd9\u4e2a\u6807\u7b7e\u8fdb\u884c\u4e86\u89e3\u6790<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564282\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe21 \u5355\u4e2a\u53c2\u6570\u7ed1\u5b9a\u8fc7\u7a0b<\/p>\n<p>\u6700\u7ec8\u7ed1\u5b9a\u7684\u7ed3\u679c\u4e3a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564283\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe22 \u5168\u90e8\u53c2\u6570\u7ed1\u5b9a\u8fc7\u7a0b<\/p>\n<p>\u56e0\u6b64\u8fd9\u4e2a\u5730\u65b9\u7ed1\u5b9a\u53c2\u6570\u7684\u5730\u65b9\u662f\u6709\u95ee\u9898\u7684\uff0c\u81f3\u6b64\u627e\u51fa\u4e86\u95ee\u9898\u7684\u6240\u5728\u3002<\/p>\n<p><strong>2.3.2 \u5b98\u65b9\u89e3\u91ca<\/strong><\/p>\n<p>\u7ffb\u9605MyBatis\u5b98\u65b9\u6587\u6863\u8fdb\u884c\u6c42\u8bc1\uff0c\u53d1\u73b0\u57283.4.5\u7248\u672c\u53d1\u884c\u4e2dbug fixes\u4e2d\u6709\u8fd9\u6837\u4e00\u53e5<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564284\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe23 \u6b64\u95ee\u9898\u5b98\u65b9\u4fee\u590dgithub\u8bb0\u5f55 \u56fe23 \u6b64\u95ee\u9898\u5b98\u65b9\u4fee\u590dgithub\u8bb0\u5f55<\/p>\n<p>\u4fee\u590d\u4e86foreach\u7248\u672c\u4e2d\u5bf9\u4e8e\u5168\u5c40\u53d8\u91cfcontext\u7684\u4fee\u6539\u7684bug<\/p>\n<p>issue\u5730\u5740\u4e3a<a href=\"https:\/\/link.segmentfault.com\/?enc=Hs%2FpvE8yJhkgOqzFucYkCQ%3D%3D.DLJun0awTTNN81FPLAcHwY42%2B7xoOLy%2BS%2Bx3nLXjZEmrJDnjS%2Fi0v35BhKQ2RfOP\" rel=\"nofollow\">https:\/\/github.com\/mybatis\/my&#8230;<\/a><\/p>\n<p>\u4fee\u590d\u65b9\u6848\u4e3a<a href=\"https:\/\/link.segmentfault.com\/?enc=3terMXY2o1GzoPtmb76eWA%3D%3D.PQhDkY5Xz421tjt%2BxSXs4%2F0dcChKrUM%2F3TX3P5jfAoYp63b%2Fr1LXv2wLP7xO7fPIhrDNklXyubvIA9FO8MEH69NCskgNik6g3Vdglm2Pih7AN3GgSa%2B3cGkDU9KiKkOb\" rel=\"nofollow\">https:\/\/github.com\/mybatis\/my&#8230;<\/a><\/p>\n<p>\u53ef\u4ee5\u770b\u5230\u5b98\u65b9\u7ed9\u51fa\u7684\u4fee\u6539\u65b9\u6848\uff0c\u91cd\u65b0\u5b9a\u4e49\u4e86\u4e00\u4e2a\u5bf9\u8c61\uff0c\u5206\u522b\u5b58\u50a8\u5168\u5c40\u53d8\u91cf\u548c\u5c40\u90e8\u53d8\u91cf\uff0c\u8fd9\u6837\u5c31\u4f1a\u89e3\u51b3foreach\u4f1a\u6539\u53d8\u5168\u5c40\u53d8\u91cf\u7684\u95ee\u9898\u3002<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564285\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe24 \u6b64\u95ee\u9898\u5b98\u65b9\u4fee\u590d\u4ee3\u7801\u793a\u4f8b<\/p>\n<p><strong>2.3.3 \u4fee\u590d\u65b9\u6848<\/strong><\/p>\n<ul>\n<li>\u5347\u7ea7MyBatis\u7248\u672c\u81f33.4.5\u4ee5\u4e0a<\/li>\n<li>\u5982\u679c\u4fdd\u6301\u7248\u672c\u4e0d\u53d8\u7684\u8bdd\uff0c\u5728foreach\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u540d\u4e0d\u8981\u548c\u5916\u90e8\u7684\u4e00\u81f4<\/li>\n<\/ul>\n<h2>3 \u6e90\u7801\u9605\u8bfb\u8fc7\u7a0b\u603b\u7ed3<\/h2>\n<p>MyBatis\u6e90\u4ee3\u7801\u7684\u76ee\u5f55\u662f\u6bd4\u8f83\u6e05\u6670\u7684\uff0c\u57fa\u672c\u4e0a\u6bcf\u4e2a\u76f8\u540c\u529f\u80fd\u7684\u6a21\u5757\u90fd\u5728\u4e00\u8d77\uff0c\u4f46\u662f\u5982\u679c\u76f4\u63a5\u53bb\u9605\u8bfb\u6e90\u7801\u7684\u8bdd\uff0c\u53ef\u80fd\u8fd8\u662f\u6709\u4e00\u5b9a\u7684\u96be\u5ea6\uff0c\u6ca1\u6cd5\u7406\u89e3\u5b83\u7684\u8fd0\u884c\u8fc7\u7a0b\uff0c\u672c\u6b21\u901a\u8fc7\u4e00\u4e2a\u7b80\u5355\u7684\u67e5\u8be2\u6d41\u7a0b\u4ece\u5934\u5230\u5c3e\u8ddf\u4e0b\u6765\uff0c\u53ef\u4ee5\u770b\u5230MyBatis\u7684\u8bbe\u8ba1\u4ee5\u53ca\u5904\u7406\u6d41\u7a0b\uff0c\u4f8b\u5982\u5176\u4e2d\u7528\u5230\u7684\u8bbe\u8ba1\u6a21\u5f0f\uff1a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000042564286\" alt=\"\" title=\"\" loading=\"lazy\"><\/p>\n<p>\u56fe25 MyBatis\u4ee3\u7801\u7ed3\u6784\u56fe<\/p>\n<ul>\n<li>\u7ec4\u5408\u6a21\u5f0f\uff1a\u5982ChooseSqlNode\uff0cIfSqlNode\u7b49<\/li>\n<li>\u6a21\u677f\u65b9\u6cd5\u6a21\u5f0f\uff1a\u4f8b\u5982BaseExecutor\u548cSimpleExecutor\uff0c\u8fd8\u6709BaseTypeHandler\u548c\u6240\u6709\u7684\u5b50\u7c7b\u4f8b\u5982IntegerTypeHandler<\/li>\n<li>Builder\u6a21\u5f0f\uff1a\u4f8b\u5982 SqlSessionFactoryBuilder\u3001XMLConfigBuilder\u3001XMLMapperBuilder\u3001XMLStatementBuilder\u3001CacheBuilder<\/li>\n<li>\u5de5\u5382\u6a21\u5f0f\uff1a\u4f8b\u5982SqlSessionFactory\u3001ObjectFactory\u3001MapperProxyFactory<\/li>\n<li>\u4ee3\u7406\u6a21\u5f0f\uff1aMyBatis\u5b9e\u73b0\u7684\u6838\u5fc3\uff0c\u6bd4\u5982MapperProxy\u3001ConnectionLogger<\/li>\n<\/ul>\n<h2>4 \u6587\u6863\u53c2\u8003<\/h2>\n<p><a href=\"https:\/\/link.segmentfault.com\/?enc=sJyh2JJ4ZxiOEwElvHEv6w%3D%3D.zUeKZXXFSUySZOkdDeoeX31Dj0hhXiQVpn3ya8dsMB2H%2BggIawdTxrjz0KyupxgS\" rel=\"nofollow\">https:\/\/mybatis.org\/mybatis-3&#8230;<\/a><\/p>\n<p>\u4f5c\u8005\uff1a\u674e\u6625\u5ef7<\/p>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000042564259\">https:\/\/segmentfault.com\/a\/1190000042564259<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5bfc\u8bfb \u672c\u6587\u901a\u8fc7MyBatis\u4e00\u4e2a\u4f4e\u7248\u672c\u7684bug\uff083.4.5\u4e4b\u524d\u7684\u7248\u672c\uff09\u5165\u624b\uff0c\u5206\u6790MyBatis\u7684\u4e00\u6b21\u5b8c\u6574\u7684\u67e5\u8be2 [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[],"tags":[],"class_list":["post-10006636","post","type-post","status-publish","format-standard","hentry"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10006636","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10006636"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10006636\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10006636"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10006636"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10006636"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}