11.3XML映射文件
xml和dtd 部分是必须填写且不需要配置的部分每次使用时,只需要将这部分复制到文件顶部即可。
mapper 元素是整个映射文件的容器,所有的SQL映射都包含在这个元素中,mapper本身有一个参数namespace,即命名空间这个命名空间就是文件所对应的接口文件的Java类只有当这个命名空间被配置时,才可以直接通过访问Java接口的方法实现SOL调用。
映射器是MyBatis最复杂且最重要的组件它由一个接口加上XML文件(或者注解)组成。在映射器中可以配置参数、SOL 语句、存储过程、缓存等内容,并且通过简易的映射规则映射到指定的POJO或者其他对象上,映射器能有效消除JDBC底层的代码。
MyBatis的映射器也可以使用注解完成,但可读性较差,企业中应用不广,官方亦不推荐使用。
1.select
查询语句是 MyBatis 中最常用的元素之一,多数应用也都是查询比修改要频繁。对每个插入、更新或删除操作,通常对应多个查询操作。这是 MyBatis 的基本原则之一,也是将焦点和精力放到查询和结果映射的原因。对简单类别的查询元素是非常简单的。例如:
<select id="selectPerson" parameterType="int" resultType="hashmap"> SELECT *FROM PERSON WHERE ID=#{id} </select>
这个语句被称为selectPerson,使用一个int(或Integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值是列对应的值。
注意参数标识 #{id},其告诉 MyBatis创建一个PreparedStatement (预处理语)参数使用JDBC,这样的一个参数在SOL中会由一个“?”来标识,并被传递到一个新的预处理语句中,类似于以下的JDBC代码(不是MyBatis的代码):
String selectPerson ="SELECT* FROM PERSON WHEREID=?"; PreparedStatement ps = conn.prepareStatement(selectPerson); ps.setInt(1,id);
当然,这需要很多单独的JDBC 的代码来提取结果并将它们映射到对象实例中,这就是MyBatis 节省时间的原因。我们需要深入了解参数和结果映射。select 元素有很多属性允许用户配置,以决定每条语句的作用细节。关于select元素主要属性的描述参见表11-2。
表11-2select元素的主要属性描述
属性 |
描述 |
id |
在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType |
将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过TypeHandler 推断出具体传入语句的参数,默认值为unset |
resultMap |
外部resultMap的命名引用。结果集的映射是MyBatis 最强大的特性若能对其有一个很好地理解则许多复杂映射的情形都能迎刃而解。可以使用resultMap或resultType,但不能同时使用 |
flushCache |
如果设置为true,则任何时候只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值为false |
useCache |
如果设置为true,则将会导致本条语句的结果被二级缓存,select元素默认值为true |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为unset(依赖驱动) |
fetchSize |
这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动) |
statementType |
值为STATEMENT、PREPARED或CALLABLE之一。这会让MyBatis分别使用JDBC中的 Statement、PreparedStatement 或CallableStatement,默认值为PREPARED |
resultSetType |
值为FORWARDONLY、SCROLL SENSITIVE 或SCROLL INSENSITIVE 之一默认值为 umset(依赖驱动),是结果集的类型 |
databaseld |
如果配置了databaseIdProvider,则MyBatis会加载所有的不带databaseId 或匹配当前databaseId语句;如果带或者不带databaseId的语句都有,则不带的会被忽略 |
2.insert、update、delete
数据操纵语句 insert、update 和 delete 在它们的实现中非常相似。
<insert Id=“insertAuthor” parameterType=“domain.blogAuthor” flushCache=“true” statementType=“PREPARED”keyProperty=“”keyColumn=“”useGeneratedKeys=“” utimeout=“20”> <update id=“updateAuthor” parameterType=“domain.blog.Author” flushCache=“true” statementType=“PREPARED” timeout=“20”> <delete id=“deleteAuthorr” parameterType=“domain.blog.Author” flushCache=“true” statementType=“PREPARED” timeout=“20”>
insert、update和delete元素的主要属性描述如表11-3所示
表11-3 insert、update和delete 元素的主要属性描述
下面是insert、update和delete语句的示例
属性 |
描述 |
id |
命名空间中的唯一标识符,可被用来代表这条语句 |
parameterType |
将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过TypeHandler推断出具体传入语句的参数,默认值为unset |
parameterMap |
STATEMENT、PREPARED或CALLABLE之一。这会让MyBatis分别使用StatementPreparedStatement或CallableStatement,默认值为PREPARED |
flushCache |
将其设置为 tue,任何时候只要语句被调用,都会导致本地缓存和二级缓存都被清空,默认值为true(对应插入、更新和删除语句) |
statementType |
STATEMENT、PREPARED或CALLABLE之一。这会让MyBatis 分别使用 Statement PreparedStatement或CallableStatement,默认值为PREPARED |
useGeneratedKeys |
(仅对insert和update 有用)这会令MyBatis 使用JDBC的getGeneratedKeys 方法来获取由数据库内部生成的主键(如像MySOL和SOLServer 这样的关系数据管理系统的自动递增字段),默认值为false |
keyProperty |
(仅对insert 和update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys的返回值或者通过 insert 语的 selectKey 子元素设置其键值,默认为 unset。如果希望得到多个生成的列,则也可以是逗号分隔的属性名称列表 |
keyColumn |
(仅对msert和update 有用)通过生成的键值设置表中的列名这个设置在某些数据库(如PostgreSQL)中是必需的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,则也可以是逗号分隔的属性名称列表 |
下面是insert、update和delete语句的示例。
<insert id=“addStudent” parameterType=“student” insert into student(sno,name,sex,age,deptno) values(#{sno}#{name},#{sex},#{age},#{dept_no}) </insert> <update id=“updateStudent” parameterType=“student”> update student set name =#{name},sex=#{sex},age=#{lage},dept_no=#{dept_no} where sno=#{sno} </update> <delete id=“deletestudent” uparameterType=“String”> delete from student where sno=#{sno} </delete>
3.Sql
这个元素可以被用来定义可重用的 SOL代码段,可以包含在其他语句中。例如:
<sql id=“userColumns”> ${alias}.id,${alias}.username,${alias}.password </sq1>
这个SQL片段可以被包含在其他语句中。例如:
<select id=“selectUsers” resultType=“map”> Select <include>refid=“userColumns”><property name=“alias” value=“t1”/></include>, </select>
4.parameters(参数)
在MyBatis中,参数是非常强大的元素。类似于之前的语句,简单参数示例如下。
<select id=“selectUsers” parameterType=“int”resultType="User”> select id,username,password from users where id= #{id} </select>
这个示例说明了一个非常简单的命名参数映射。参数类型被设置为int,这里的参数名是id,也可以是其他名称。参数为简单数据类型的,都与此类似。以下示例中参数类型是一个对象,MyBatis的处理方式不同于简单数据类型。
<insert id="insertUser"parameterType="User"> Insert into users(id,username,password) values(#{id},#{username},#{password}) </insert>
如果User类型的参数对象传递到了语句中,则id、userame和password 属性将会被查找,它们的值就会被传递到预处理语句的参数中。
5.resultMap
resultMap是映射中最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。resultMap 定义的主要是一个结果集的映射关系,也就是SOL到Java Bean 的映射关系定义。
下面是简单映射语句的示例,但没有明确的resultMap。例如:
<select id=“selectUsers” resultType=“map”> select id,username, hashedPassword from some_table where id = #{id} </select>
resultType=“map”表示返回的数据是一个Map集合(使用列名作为key列值作为value)。虽然数据被封装成Map集合返回,但是Map ”集合并不能很好地描述一个领域模型。可以使用JavaBeans或POJOs来作为领域模型描述数据MyBatis对两者都支持来看下面这个JavaBean:
public class User { private int id; private String username; private String hashedPassword; public int setId(int id) { This.id=id; } public void getUsername() { return username; } public void setUsername(String username) { this.username=username; } public String getHashedPassword() { return hashedPassword; } public void setHashedPassword(String hashedPassword) { this.hashedPassword=hashedPassword; } }
基于JavaBean的规范,上面这个类有3个属性:id、username和hashedPassword。这些在select语句中会精确匹配到列名。
这样的一个JavaBean可以被映射到结果集,就像映射到HashMap一样简单。
<select id=“selectUsers” parameterType=“int” resultType=“com.someapp.model.User”> select id,username,hashedPassword from some table where id = #{id} </select>
以下使用了类型别名,使用它们时可以不输入类的全路径。例如:
<!--在XML配置文件中--> <typeAlias type=“com.someapp,model.User” alias=“User”/> <!--在SOL映射的XML文件中--> <select id=“selectUsers” parameterType=“int”resultType=“User”> select id,username hashedPassword from some table where id = #{id} </select>
在这些情况下,MyBatis会在幕后自动创建一个resultMap,基于属性名来映射列到JavaBean 的属性上。如果列名没有精确匹配,则可以在列名上使用 select 字句的别名(一个标准的SOL特性)来匹配标签。例如:
<select id=“selectUsers” parameterType=“int” resultType=“User”> select user_id as “id”, user_name as “userName”, hashed_password as “hashedPassword” from some_table where id = #{id} </select>
resultMap最常见的使用方式如下所示,这也是解决列名不匹配的另外一种方式。
<resultMap id=“userResultMap” type= “User”> <id property= “id” column= “user_id” /> <result property= “username” column= “user_name” /> <result property= “password” column= “hashed_password” /> </resultMap>
引用此语句时使用resultMap 属性即可(注意,这里去了resultType属性)。例如:
<select id= “selectUsers” parameterType= “int” resultMap= “userResultMap”> select user_id, user_name, hashed_password from some_table where id=#{id} </select>
6.resultMap 使用示例
(1)在先前创建的数据库stu中创建表student 2,并插入若干条数据,代码如下:
DROP TABLE IF EXISTS `student_2`; CREATE TABLE `student_2` ( `stu_sno` varchar(100) NOT NULL DEFAULT '', `stu_name` varchar(100) NOT NULL, `stu_sex` varchar(8) DEFAULT NULL, `stu_age` int(3) DEFAULT NULL, `stu_dept_no` varchar(60) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `student_2` VALUES ('20231505', 'Marry', '女', '18', '260'); INSERT INTO `student_2` VALUES ('20231506', '王宝宝', '男', '22', '2602'); INSERT INTO `student_2` VALUES ('20231508', '李勇', '男', '20', '2605'); INSERT INTO `student_2` VALUES ('20231509', '刘娟', '女', '19', '2605');
(2)创建工程mybatis_ResultMap_demo。
在idea 中创建Maven Project,在“GroupID”文本框中输入“com.mialab”,在“ArtifactID”文本框中输入“mybatis_ResultMap_demo”。最终完成的mybatis_ResultMap_demo工程目录及文件如图11-4所示,student2初始表数据如图11-5所示。
图11-4 mybatis_ResultMap_demo工程目录及文件
图11-5 student2表中的数据
(3)创建实体对象映射数据库表。
Student对象用于映射student _2 表,Student.java 主要代码如下(此处get方法、set方法和toString方法略:
public class Student { private String sno; private String name; private String sex; private int age; private String dept_no; ... }
(4)创建映射接口和映射文件。
接口StudentMapper.java的主要代码如下:
public interface StudentMapper { public List<Student> getSudentAll(); }
映射文件StudentMapper.xml的主要代码如下:
<mapper namespace="com.mialab.mybatis_ResultMap_demo.mapper.StudentMapper"> <resultMap id="studentResultMap" type="student"> <id property="sno" column="stu_sno" /> <result property="name" column="stu_name" /> <result property="sex" column="stu_sex" /> <result property="age" column="stu_age" /> <result property="dept_no" column="stu_dept_no" /> </resultMap> <select id="getSudentAll" resultMap="studentResultMap"> select * from student_2 </select> </mapper>
这里column属性表示数据库表的列名,property 表示数据库列映射到返回类型的属性。中的id 是resultMap 的唯一标识符,type则表示 resultMap的实际返回类型。“student”是类型别名,表示的是“com.mialab.mybatis_ResultMap_demo.domain.Student", 在mybatis-config.xml中有声明。
中的id表示这个对象的主键(或者唯一标识),property表示POJO的属性名称,column 表示数据库表的列名。这样,POJO就和数据库SQL的结果一一对应起来了 。
(5)测试。
main方法的主要测试代码如下:
StudentMapper mapper = session.getMapper(StudentMapper.class); List<Student> stu_list = mapper.getSudentAll(); for(Student stu:stu_list) { //System.out.println(stu); log.info(stu); }
运行ResultMap_ Main 的main方法,控制台显示内容如下:
DEBUG [main] - ==> Preparing: select * from student_2 DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 4 INFO [main] - Student [sno=20231505, name=Marry, sex=女, age=18, dept_no=260] INFO [main] - Student [sno=20231506, name=王宝宝, sex=男, age=22, dept_no=2602] INFO [main] - Student [sno=20231508, name=李勇, sex=男, age=20, dept_no=2605] INFO [main] - Student [sno=20231509, name=刘娟, sex=女, age=19, dept_no=2605]