Valid XHTML 1.0 Transitional集成演练路线图 (P9)

Page: [index.html] (v2017-03-01_19-30)

  1. 项目基础:……
  2. Servlet :……
  3. Spring Web MVC :
    1. 基本 Web 应用:……
    2. CRUD :
      1. Spring Web MVC + DataSource + 基本 JDBC :……
      2. Spring Web MVC + DataSource + Spring JDBC Template :……
      3. Spring Web MVC + DataSource + MyBatis :
        • 方式 - 人工编写 DAO 实现类:
          • 样例 - 用户管理:
            1. 环境准备:
              1. 修改 pom.xml ,添加需要的库 (并由 Eclipse 的 Maven 插件自动下载、导入) :
                <project ……>
                	……
                	<dependencies>
                		……
                		<dependency>
                			<!-- [MyBatis 3]. -->
                			<groupId>org.mybatis</groupId>
                			<artifactId>mybatis</artifactId>
                			<version>3.2.8</version>
                		</dependency>
                	</dependencies>
                </project>
                

                说明 / 注意事项:
                • 目前通过 Maven 引入的库有:
                  aopalliance-1.0.jar
                  commons-codec-1.10.0.jar
                  commons-codec-1.10.jar
                  commons-dbcp-1.4.jar
                  commons-logging-1.1.3.jar
                  commons-pool-1.5.4.jar
                  hamcrest-core-1.3.jar
                  junit-4.12.jar
                  mybatis-3.2.8.jar
                  ojdbc5-11.2.0.4.jar
                  spring-aop-3.2.8.RELEASE.jar
                  spring-beans-3.2.8.RELEASE.jar
                  spring-context-3.2.8.RELEASE.jar
                  spring-core-3.2.8.RELEASE.jar
                  spring-expression-3.2.8.RELEASE.jar
                  spring-jdbc-3.2.8.RELEASE.jar
                  spring-tx-3.2.8.RELEASE.jar
                  spring-web-3.2.8.RELEASE.jar
                  spring-webmvc-3.2.8.RELEASE.jar
              2. 编写 MyBatis 主配置文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/mybatis-config.xml
                由于当前方式下在 MyBatis 中使用第三方数据源过于麻烦,本样例暂时只考虑使用 MyBatis 自带的连接池:
                <?xml version="1.0" encoding="UTF-8" ?>
                <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
                		"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
                <configuration>
                	<!-- Connection and transaction parameters: -->
                	<environments default="environment">
                		<environment id="environment">
                			<transactionManager type="JDBC"/>
                			<dataSource type="POOLED">
                				<property name="driver" value="oracle.jdbc.OracleDriver"/>
                				<property name="url"
                						value="jdbc:oracle:thin:@127.0.0.1:1521:demo01"/>
                				<property name="username" value="scott"/>
                				<property name="password" value="tiger"/>
                			</dataSource>
                		</environment>
                	</environments>
                
                	<!-- Mappers: No mapper added currently.
                	<mappers>
                		<mapper resource=".../.../XXXMapping.xml"/>
                		<mapper resource=".../.../YYYMapping.xml"/>
                	</mappers>
                	-->
                </configuration>
                

              3. 编写测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,开启和关闭 SqlSession ,检查 MyBatis 主配置文件的正确性:
                ……
                public class TestCase
                {
                
                	private String strConfFile =
                			"src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/mybatis-config.xml";
                
                	@Test
                	public void testObjects() throws IOException
                	{
                		SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
                		System.out.println("SqlSessionFactoryBuilder:\n\t" + ssfb);
                
                		System.out.println("Configuration File:\n\t" + strConfFile);
                		InputStream isMyBatisCfg = new FileInputStream(strConfFile);
                		System.out.println("Configuration InputStream:\n\t" + isMyBatisCfg);
                
                		SqlSessionFactory ssf = ssfb.build(isMyBatisCfg);
                		System.out.println("SqlSessionFactory:\n\t" + ssf);
                		isMyBatisCfg.close();
                		System.out.println(
                				"Configuration InputStream Closed:\n\t" + isMyBatisCfg);
                
                		SqlSession session = ssf.openSession();
                		System.out.println("SqlSession:\n\t" + session);
                		session.close();
                		System.out.println("SqlSession Closed:\n\t" + session);
                	}
                
                }
                

                说明 / 注意事项:
                • 测试用例从 Eclipse 项目中启动,InputStream 构建时使需要使用从项目目录算起的相对路径src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/mybatis-config.xml”。
            2. 样例编写:
              1. 实体类:
                沿用“基本 JDBC CRUD”样例既有的实体类 tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User
              2. DAO 层:
                1. MyBatis 功能验证:
                  1. 环境准备:
                    1. 编写 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,但具体操作暂时留空:
                      <?xml version="1.0" encoding="UTF-8" ?>
                      <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
                      		"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
                      <mapper namespace="crud.mybatis.user">
                      	<!--
                      	<select id="create"/></select>
                      	<select id="findById"/></select>
                      	<select id="listByName"/></select>
                      	<select id="listAll"/></select>
                      	<select id="listByRange"/></select>
                      	<update id="update"/></update>
                      	<update id="discardById"/></update>
                      	-->
                      </mapper>
                      

                      说明 / 注意事项:
                      1. MyBatis 映射文件的路径和名称在技术上不必和实体相同或相关仅仅是为了好记、好找,本样例使用了相关的文件名。
                      2. MyBatis 映射文件需要在整个 SqlSession 范围内唯一的命名空间
                    2. 修改 MyBatis 主配置文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/mybatis-config.xml ,添加“mappers”节点,并在“mappers”节点下添加此映射文件:
                      <?xml version="1.0" encoding="UTF-8" ?>
                      <!DOCTYPE ……>
                      <configuration>
                      	<!-- Connection and transaction parameters: -->
                      	<environments ……>
                      		……
                      	</environments>
                      
                      	<!-- Mappers: -->
                      	<mappers>
                      		<!--
                      		<mapper resource=".../.../XXXMapping.xml"/>
                      		<mapper resource=".../.../YYYMapping.xml"/>
                      		-->
                      		<mapper resource="tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml"/>
                      	</mappers>
                      </configuration>
                      

                      说明 / 注意事项:
                      • resource 属性的值用映射文件相对于 CLASSPATH 的路径
                    3. MyBatis 主配置文件由主配置文件加载的映射文件中,任何一个有错误均可导致 SqlSession 加载失败;所以再次运行测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation 开启和关闭 SqlSession ,可检查 MyBatis 主配置文件及所有由主配置文件加载的映射文件的正确性。
                  2. 功能实现:
                    1. 单行数据插入 1 :
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“插入”操作,命名为“create”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper namespace="crud.mybatis.user">
                        	<insert id="create"
                        			parameterType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		<selectKey keyProperty="id" resultType="int" order="BEFORE">
                        				select tfw_seq_dash_user_id.nextval from dual
                        		</selectKey>
                        		insert into tfw_dash_user(
                        			id, name, passwd, stat, remark
                        		)
                        		values(
                        			#{id,    jdbcType=INTEGER},
                        			#{name,  jdbcType=VARCHAR},
                        			#{passwd,jdbcType=VARCHAR},
                        			#{status,jdbcType=TINYINT},
                        			#{remark,jdbcType=VARCHAR}
                        		)
                        	</insert>
                        	<!--
                        	<select id="findById"/></select>
                        	……
                        	-->
                        </mapper>
                        

                        说明 / 注意事项:
                        1. 执行顺序:
                          1. 执行“<selectKey ……>……</selectKey>”中的 SQL ,查出序列“tfw_seq_dash_user_id”的“下一个”值,作为 id 值,存入实体对象。
                          2. 从实体对象中取得包括 id 在内的所有 Map key 值或 bean 属性值,并用主 SQL 执行插入操作。
                        2. <insert ……>……</insert>”:
                          “插入”操作使用“insert”语句,在 MyBatis 映射文件中也用“<insert ……>……</insert>”标签声明;
                          使用和 SQL 语句不匹配的标签,操作执行时可能出现错误,却可能不会在语法上及配置加载时出错,不易排查,所以需要特别注意。
                        3. namespace="……”和“id="……”:
                          每一项操作在 MyBatis 映射文件的“mapper”节点范围内要有唯一的“id”属性
                          “mapper”节点的“namespace”属性值和此操作的“id”属性值结合,共同作为此操作在 SqlSession 范围内的唯一标识。
                        4. parameterType="……"”:
                          此操作的参数类型;
                          对于“插入”操作,参数多为数据对象,类型可以是 java.util.Map 或者专门编写的实体类;
                          MyBatis 从参数对象中按 Map 的 keybean 属性取值,并将值插入表中;
                          本样例的参数类型沿用“基本 JDBC CRUD”样例既有的实体类
                        5. <selectKey keyProperty="id" resultType="int" order="BEFORE">……</selectKey>”:
                          1. tfw_dash_userid 列的值来自序列 tfw_seq_dash_user_id
                            根据设计,此值需要返回给上层程序,所以在主 SQL 执行之前 (order="BEFORE") 先用此序列做一次单行单列选择,将选出的整数型结果 (resultType="int") 赋给参数对象中名为“id”的 Map 的 keybean 属性 (keyProperty="id") ,上层程序可由此 keybean 属性从参数对象中取值。
                          2. 经试验,无论此标签放置在主 SQL 前方还是后方,不妨碍两者的执行顺序;
                            由于要在主 SQL 之前执行,为便于理解、减少出错的机会,本样例将此标签放置在主 SQL 前方。
                        6. #{id, jdbcType=INTEGER}”、“#{name, dbcType=VARCHAR}”……:
                          1. #{id……}”、“#{name……}”……:
                            从参数对象中取相应的 Map key 值或 bean 属性值、自动转换成 MyBatis 对应的“jdbcType”,进行 SQL 操作;
                            MyBatis 的“jdbcType”见类 org.apache.ibatis.type.JdbcType
                          2. jdbcType=INTEGER”、“jdbcType=VARCHAR”……:
                            如果不指定“jdbcType”,MyBatis 将自行猜测和匹配数据类型,但当相应的 Map key 值或 bean 属性值为 null 时,MyBatis 无法判断向数据库写入何种类型的 null 值,导致运行出错;
                            检查程序中的数据类型和数据库中的字段类型,指定合适的“jdbcType”,MyBatis 将按照指定的数据类型工作、并在值为 null 时向数据库写入类型正确的 null 值。
                          经试验,使用后 #{……, jdbcType=……} 已可在“插入”操作中正确、方便地写入可能的 null 值。
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.create”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	private String strConfFile =
                        			"src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/mybatis-config.xml";
                        
                        	private SqlSession session;
                        
                        	private final String MYBATIS_NAMESPACE = "crud.mybatis.user";
                        
                        	@Test
                        	public void testObjects() throws IOException
                        	{
                        		……
                        	}
                        
                        	@Before
                        	public void init() throws IOException
                        	{
                        		SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
                        		System.out.println("SqlSessionFactoryBuilder:\n\t" + ssfb);
                        
                        		System.out.println("Configuration File:\n\t" + strConfFile);
                        		InputStream isMyBatisCfg = new FileInputStream(strConfFile);
                        		System.out.println("Configuration InputStream:\n\t" + isMyBatisCfg);
                        
                        		SqlSessionFactory ssf = ssfb.build(isMyBatisCfg);
                        		System.out.println("SqlSessionFactory:\n\t" + ssf);
                        		isMyBatisCfg.close();
                        		System.out.println(
                        				"Configuration InputStream Closed:\n\t" + isMyBatisCfg);
                        
                        		session = ssf.openSession();
                        		System.out.println("SqlSession:\n\t" + session);
                        	}
                        
                        	@After
                        	public void close()
                        	{
                        		session.close();
                        		System.out.println("SqlSession Closed:\n\t" + session);
                        	}
                        
                        	@Test
                        	public void testMyBatis_create()
                        	{
                        		// [S] Preparing.
                        		User user;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "create";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			String strDate = DateToolE.simpleFormat(new Date(), "HH-mm-ss.SSS");
                        			String strPasswd = null;
                        			// "Password";
                        			user = // null; // [!] May fail due to database constraints.
                        					new User(null, "MyBatis_N_" + strDate, strPasswd,
                        							new Byte((byte) 0), "MyBatis_R_" + strDate);
                        			System.out.println("User:\n\t" + user);
                        
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, user);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// [S] Main.
                        		{
                        			int intRtnCode = session.insert(MYBATIS_OPERATION, user);
                        			System.out.println("Return Code:\n\t" + intRtnCode);
                        
                        			session.commit();
                        			System.out.println("User:\n\t" + user);
                        		}
                        		// [E] Main.
                        	}
                        
                        }
                        

                        说明 / 注意事项:
                        • session.commit();”:
                          “insert”是写入操作;MyBatis 默认启用事务,需要专门提交才生效。
                    2. 单行数据插入 2 (“order="AFTER"”方式):
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“插入”操作,命名为“createAfter”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	<insert id="create"
                        			……>
                        		……
                        	</insert>
                        	<insert id="createAfter"
                        			parameterType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		insert into tfw_dash_user(
                        			id, name, passwd, stat, remark
                        		)
                        		values(
                        			tfw_seq_dash_user_id.nextval,
                        			#{name,  jdbcType=VARCHAR},
                        			#{passwd,jdbcType=VARCHAR},
                        			#{status,jdbcType=TINYINT},
                        			#{remark,jdbcType=VARCHAR}
                        		)
                        		<selectKey keyProperty="id" resultType="int" order="AFTER">
                        			select tfw_seq_dash_user_id.currval from dual
                        		</selectKey>
                        	</insert>
                        	<!--
                        	<select id="findById"/></select>
                        	……
                        	-->
                        </mapper>
                        

                        说明 / 注意事项:
                        1. 执行顺序:
                          1. 从实体对象中取得除了 id 之外的所有 Map key 值或 bean 属性值,并用主 SQL 执行插入操作;
                            主 SQL 查“tfw_seq_dash_user_id”的“下一个”值,得到 id 列的值。
                          2. 执行“<selectKey ……>……</selectKey>”中的 SQL ,查出序列“tfw_seq_dash_user_id”的“当前”值,作为 id 值,存入实体对象。
                        2. 可能的问题:
                          由于 Oracle 的序列不受“事务”管制,本操作可能导致 id 不准:
                          • 本操作的主 SQL 已经含有从序列中取值的操作,一定能完成数据插入;
                            但如果有其他外部操作在“<selectKey …… order="AFTER">……</selectKey>”之前导致序列发生“步进”,则“<selectKey ……>……</selectKey>”取到的是步进之后的“当前”值,而不再是主 SQL 执行“插入”操作时的值。
                          • 而“crud.mybatis.user.create”操中,“<selectKey …… order="BEFORE">……</selectKey>”和主 SQL 的执行次序之间,如果有外部操作令序列“步进”、并把从序列中取出的值差入表“tfw_dash_user”中、导致表中已含有“<selectKey ……>……</selectKey>”查得的值时,表上的唯一约束会阻止主 SQL 的“插入”操作;
                            即,“插入”操作会失败,但不会有不准确的 id 值。
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.createAfter”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	@Test
                        	public void testMyBatis_create()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_createAfter()
                        	{
                        		// [S] Preparing.
                        		User user;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "createAfter";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			String strDate = DateToolE.simpleFormat(new Date(), "HH-mm-ss.SSS");
                        			String strPasswd = null;
                        			// "Password";
                        			user = // null; // [!] May fail due to database constraints.
                        					new User(null, "MyBatis_N_" + strDate, strPasswd,
                        							new Byte((byte) 0), "MyBatis_R_" + strDate);
                        			System.out.println("User:\n\t" + user);
                        
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, user);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// [S] Main.
                        		{
                        			int intRtnCode = session.insert(MYBATIS_OPERATION, user);
                        			System.out.println("Return Code:\n\t" + intRtnCode);
                        
                        			session.commit();
                        			System.out.println("User:\n\t" + user);
                        		}
                        		// [E] Main.
                        	}
                        
                        }
                        

                    3. 按 ID 查询:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“查询”操作,命名为“findById”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<insert id="createAfter"
                        			……>
                        		……
                        	</insert>
                        	<select id="findById" parameterType="java.lang.Integer"
                        			resultType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		select id, name, passwd, stat as status, remark from tfw_dash_user
                        		where id
                        		<!-- =#{AbCdEfG,jdbcType=INTEGER} -->
                        		<choose>
                        			<when test="_parameter!=null">=#{AbCdEfG}</when>
                        			<otherwise> is null</otherwise>
                        		</choose>
                        	</select>
                        	<!--
                        	<select id="listByName"/></select>
                        	……
                        	-->
                        </mapper>
                        

                        说明 / 注意事项:
                        1. <select ……>……</select>”:
                          “查询”操作使用“select”语句,在 MyBatis 映射文件中也用“<select ……>……</select>”标签声明。
                        2. resultType="……"”:
                          此操作的结果类型;
                          对于“查询”操作,结果多为数据对象,类型可以是 java.util.Map 或者专门编写的实体类;
                          MyBatis 从表中查出记录行,按结果对象的 Map keybean 属性将值填入结果对象;
                          本样例的参数类型沿用先前样例中用过的实体类。
                        3. stat as status”:
                          实体类中有一个 bean 属性“status”,而相应数据库表中相应的字段名为“stat”; 两者不一致,使用“别名 (as)”是实现相互对应的简便办法
                        4. #{AbCdEfG……}
                          利用输入的参数值本身拼接 SQL 时,不需要按特定的名称从参数对象中提取 Map key 值或 bean 属性值,大括号内填写什么名称什么并不重要。
                        5. <!-- =#{……,jdbcType=……} --><choose><when test="……">……</when><otherwise>……</otherwise></choose>”:
                          (Oracle 的) SQL 对 null 值做判断的语法是“is null”,而对非 null 值做判断的语法是“=XXXX”;
                          jdbcType=……”可以在 Java 程序和数据库之间正确地做 null 值类型转换,但并不能产生在 null 值和非 null 值两种情况下自动切换 SQL 语句的效果 (所以注释掉了) ,所以需要“<choose><when test="……">……</when><otherwise>……</otherwise></choose>”标签组;
                          这组标签在逻辑上等同于“if (……) {……} else (……) {……}”;
                          本次需要考虑两种情况:
                          1. 如果送入的 ID 不为 null ,生成“…… where id=送入的 ID”;
                          2. 如果送入的 ID 为 null ,则生成“…… where id is null”。
                        6. _parameter”:
                          暂且记为参数的固定表示办法。
                        7. test="_parameter!=null"”:
                          以“_parameter=null”方式做判断似乎无效、导致拼接出奇怪的错误 SQL ;没时间深究了,直接用“_parameter!=null”判断。
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.findById”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	@Test
                        	public void testMyBatis_createAfter()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_findById()
                        	{
                        		// [S] Preparing.
                        		Integer itgUserId;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "findById";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			itgUserId = // null;
                        					new Integer(10000);
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, itgUserId);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// [S] Main.
                        		{
                        			User user = session.selectOne(MYBATIS_OPERATION, itgUserId);
                        			System.out.println("User:\n\t" + user);
                        
                        			List<User> lstUsers =
                        					session.selectList(MYBATIS_OPERATION, itgUserId);
                        			showUsers(lstUsers);
                        		}
                        		// [E] Main.
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                        说明 / 注意事项:
                        • User user = session.selectOne(...);”:
                          根据常规思路,ID 可以唯一标识一行记录,选出的结果应是单个对象。
                      3. 用“alter table tfw_dash_user drop constraint tfw_dash_user_id_pk;”暂时删除表上的主键约束,以确认 ID 为 null 的数据可以正确地插入和查出;
                        验证完成删除 ID 为 null 的数据,用“alter table tfw_dash_user add constraint tfw_dash_user_id_pk primary key(id);”重建主键约束。
                    4. 按名称查询:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“查询”操作,命名为“listByName”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<select id="findById" ……
                        			……>
                        		……
                        	</select>
                        	<select id="listByName" parameterType="string"
                        			resultType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		select id, name, passwd, stat as status, remark from tfw_dash_user
                        		where name
                        		<choose>
                        			<when test="_parameter!=null">=#{AbCdEfG}</when>
                        			<otherwise> is null</otherwise>
                        		</choose>
                        		order by name, id
                        	</select>
                        	<!--
                        	<select id="listAll"/></select>
                        	……
                        	-->
                        </mapper>
                        

                        说明 / 注意事项:
                        • parameterType="string"”:
                          MyBatis 内置支持部分参数 / 结果类型简写,常用类型简写如下:
                          • java.lang.Integer → int
                          • java.lang.String → string
                          • java.util.Map → map
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.listByName”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	@Test
                        	public void testMyBatis_findById()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_listByName()
                        	{
                        		// [S] Preparing.
                        		String strUserName;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "listByName";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			strUserName = // null;
                        					// "Name_AAA";
                        					"root";
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, strUserName);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// Main.
                        		List<User> lstUsers =
                        				session.selectList(MYBATIS_OPERATION, strUserName);
                        		showUsers(lstUsers);
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                        说明 / 注意事项:
                        • List<User> lstUsers = session.selectList(MYBATIS_OPERATION, strUserName);”:
                          根据表的设计,名称是可以重复的,选出的结果应对象列表。
                    5. 全部查询:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“查询”操作,命名为“findAll”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<select id="listByName" ……
                        			……>
                        		……
                        	</select>
                        	<select id="listAll"
                        			resultType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		select id, name, passwd, stat as status, remark from tfw_dash_user
                        		order by name, id
                        	</select>
                        	<!--
                        	<select id="listByRange"/></select>
                        	……
                        	-->
                        </mapper>
                        

                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.findAll”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	public void testMyBatis_listByName()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_listAll()
                        	{
                        		// [S] Preparing.
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "listAll";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// Main.
                        		List<User> lstUsers = session.selectList(MYBATIS_OPERATION);
                        		showUsers(lstUsers);
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                    6. 按指定的范围查询:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“查询”操作,命名为“listByRange”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<select id="listAll"
                        			……>
                        		……
                        	</select>
                        	<select id="listByRange" parameterType="map"
                        			resultType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		select id, name, passwd, stat as status, remark
                        		from (
                        			select rownum rn, t.*
                        			from (
                        				select id, name, passwd, stat, remark
                        				from tfw_dash_user
                        				order by name, id
                        			) t
                        			where rownum&lt;=(#{start_row_index}+#{select_row_count})
                        		)
                        		where rn&gt;=(#{start_row_index}+1)
                        	</select>
                        	<!--
                        	<select id="update"/></select>
                        	……
                        	-->
                        </mapper>
                        

                        说明 / 注意事项:
                        1. parameterType="map"”:
                          本次参数类型为 java.util.Map
                        2. #{start_row_index}”:
                          用 key “start_row_index”从 java.util.Map 型参数对象中提取起始行索引 (从 0 开始)
                        3. &lt;”、“&gt;”:
                          大于号和小于号破坏标签格式、导致 XML 文件错误,所以需要转义。
                        4. rn&gt;=(#{start_row_index}+1)”:
                          在 MyBatis 配置文件中做数学运算,根据起始行索引算出起始行序号 (从 1 开始)
                        5. #{start_row_index}”:
                          用 key “select_row_count”从 java.util.Map 型参数对象中提取要选取的行数
                        6. rownum&lt;=(#{start_row_index}+#{select_row_count})”:
                          计算结束行序号
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.listByRange”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	public void testMyBatis_listAll()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_listByRange()
                        	{
                        		// [S] Preparing.
                        		Map<String, Integer> mapRange;
                        		List<User> lstUsers;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "listByRange";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			lstUsers = session.selectList(MYBATIS_NAMESPACE + ".listAll");
                        			showUsers(lstUsers);
                        			System.out.println("----------------------------------------");
                        			mapRange = new HashMap<String, Integer>();
                        			mapRange.put("start_row_index", 15);
                        			mapRange.put("select_row_count", 10);
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, mapRange);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// Main.
                        		lstUsers = session.selectList(MYBATIS_OPERATION, mapRange);
                        		showUsers(lstUsers);
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                    7. 更新记录:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“更新”操作,命名为“update”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<select id="listByRange" ……
                        			……
                        		……
                        	</select>
                        	<update id="update"
                        			parameterType="tfw.integration_demo._04_spring_web_mvc._02_crud._01_basic_jdbc_crud.entity.User">
                        		<choose>
                        			<when test="_parameter!=null">
                        				update tfw_dash_user
                        				set
                        					name  =#{name,  jdbcType=VARCHAR},
                        					passwd=#{passwd,jdbcType=VARCHAR},
                        					stat  =#{status,jdbcType=TINYINT},
                        					remark=#{remark,jdbcType=VARCHAR}
                        				where id
                        				<choose>
                        					<when test="id!=null">=#{id}</when>
                        					<otherwise> is null</otherwise>
                        				</choose>
                        			</when>
                        			<otherwise>select -1 from dual</otherwise>
                        		</choose>
                        	</update>
                        	<!--
                        	<select id="discardById"/></select>
                        	-->
                        </mapper>
                        

                      2. 改造测试用例“tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation”,新增方法以测试“crud.mybatis.user.update”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	public void testMyBatis_listByRange()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_update()
                        	{
                        		// [S] Preparing.
                        		Integer itgUserId;
                        		User user;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "update";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			itgUserId = // null;
                        					10017;
                        			// 99999;
                        			user = session.selectOne(MYBATIS_NAMESPACE + ".findById",
                        					itgUserId);
                        			System.out.println("User (before):\n\t" + user);
                        
                        			String strDate = DateToolE.simpleFormat(new Date(),
                        					"yyyy-MM-ss_HH-mm-ss.SSS");
                        			String strPasswd = // null;
                        					"passwd";
                        			user = // null;
                        					new User(itgUserId, "Name_" + strDate, strPasswd, (byte) 2,
                        							"Remark_" + strDate);
                        			System.out.println("User (new):\n\t" + user);
                        
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, user);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// Main.
                        		int intRtnCode = session.update(MYBATIS_OPERATION, user);
                        		System.out.println("Return Code:\n\t" + intRtnCode);
                        		session.commit();
                        
                        		// Confirmation.
                        		user = session.selectOne(MYBATIS_NAMESPACE + ".findById", itgUserId);
                        		System.out.println("User (updated):\n\t" + user);
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                    8. 按 ID “废弃”:
                      1. 修改 MyBatis 映射文件 src/main/resources/tfw/integration_demo/_04_spring_web_mvc/_02_crud/_03_mybatis_crud/_01_manual_dao_way/dao/impl/oracle/User.mybatis_mapping.xml ,添加“更新”操作,命名为“discardById”:
                        <?xml version="1.0" encoding="UTF-8" ?>
                        <!DOCTYPE ……>
                        <mapper ……>
                        	……
                        	<update ……
                        			……>
                        		……
                        	</update>
                        	<update id="discardById" parameterType="int">
                        		update tfw_dash_user set stat=-1
                        		where id
                        		<choose>
                        			<when test="_parameter!=null">=#{AbCdEfG}</when>
                        			<otherwise> is null</otherwise>
                        		</choose>
                        	</update>
                        </mapper>
                        

                        说明 / 注意事项:
                        • <update ……>……</update>”:
                          按正常的思路,业务数据需要可以追溯,不应该被真正删除,而应该更新某个或某些字段的值,将其标记为“废弃”状态
                      2. 改造测试用例 tfw.integration_demo._04_spring_web_mvc._02_crud._03_mybatis_crud._01_manual_dao_way.user_mgr_testcase._01_MyBatis_Operation ,新增方法以测试“crud.mybatis.user.discardById”操作:
                        ……
                        public class _01_MyBatis_Operation
                        {
                        
                        	……
                        
                        	public void testMyBatis_update()
                        	{
                        		……
                        	}
                        
                        	@Test
                        	public void testMyBatis_discardById()
                        	{
                        		// [S] Preparing.
                        		Integer itgUserId;
                        		User user;
                        		String MYBATIS_OPERATION;
                        		{
                        			final String MYBATIS_OPERATION_ID = "discardById";
                        			MYBATIS_OPERATION = MYBATIS_NAMESPACE + "." + MYBATIS_OPERATION_ID;
                        			System.out.println(MYBATIS_OPERATION);
                        
                        			itgUserId = // null;
                        					10017;
                        			// 99999;
                        			user = session.selectOne(MYBATIS_NAMESPACE + ".findById",
                        					itgUserId);
                        			System.out.println("User (before):\n\t" + user);
                        
                        			String strSql = MyBatisSqlHelper.getNamespaceSql(session,
                        					MYBATIS_OPERATION, itgUserId);
                        			System.out.println(strSql);
                        		}
                        		// [E] Preparing.
                        
                        		// Main.
                        		int intRtnCode = session.update(MYBATIS_OPERATION, itgUserId);
                        		System.out.println("Return Code:\n\t" + intRtnCode);
                        		session.commit();
                        
                        		// Confirmation.
                        		user = session.selectOne(MYBATIS_NAMESPACE + ".findById", itgUserId);
                        		System.out.println("User (discarded):\n\t" + user);
                        	}
                        
                        	private void showUsers(List<User> lstUsers)
                        	{
                        		……
                        	}
                        
                        }
                        

                2. ……