Mybatis系列(四)映射文件
来源:互联网 发布:如何摆脱网络成瘾 编辑:程序博客网 时间:2024/05/27 20:40
Mybatis系列(四)映射文件
引言
Mybatis的真正强大,在于她对SQL的映射,这也是她吸引人的地方。实现相同的功能,她要比直接使用JDBC省去95%的代码量。而且将SQL语句独立在Java代码之外,为程序的修改和纠错提供了更大的灵活性,可以直接修改SQL语句,而无需重新编译Java程序。
本文将在上一篇《Mybatis系列之简单示例》的基础上,对映射文件进行详细的讨论学习。
SQL映射文件也是XML格式,其顶级元素有以下几个:
- select - 映射sql查询语句
- insert - 映射sql插入语句
- update - 映射sql更新语句
- delete - 映射sql删除语句
- sql - 就像程序中可以复用的函数一样,这个元素下放置可以被其他语句重复引用的sql语句
- resultMap - 用来描述如何从数据库查询结果集中来加载对象
- cache - 给定命名空间的缓存配置
- cache-ref - 其他命名空间缓存配置引用
查询语句映射
查询语句,是sql中使用频率最高的语句,Mybatis中的查询语句映射也是很简单的。如:
- <select id="getById" parameterType="int" resultType="User">
- SELECT <span style="font-family: Arial, Helvetica, sans-serif;">user_name, user_password, nick_name, email, user_type_id, </span><span style="font-family: Arial, Helvetica, sans-serif;">is_valid, created_time</span>
- FROM sys_user WHERE user_id = #{id}
- </select>
这是一条被称作getById的查询,需要一个类型为int或是Integer的参数,查询返回一个User类型对象,对象的属性名称就是查询语句中的列名,属性值就是查询结果行中对应的值。
请注意,上句话中斜体加粗部分,“查询语句中的列名”意味着在对查询结果进行实体映射时,使用的是查询语句中的列名进行映射的,而非数据表中的。举例说明:select user_name .....,那么对应的实体对象属性名称就是user_name;如果在查询时使用了别名,如select user_name as userName,那么对应的实体对象的属性名称就是userName。
通常情况下,数据表对字段命名规则使用下划线进行分词的,而Java中却是使用驼峰式的命名规则,那么是不是意味着我们在数据表中也要使用驼峰式命名规则,或是在查询语句中都要使用别名方式呢?其实完全不必,Mybatis早早就替我们考虑到这点的,在Mybatis核心配置文件中,只需要添加以下代码,Mybatis就可以自动的将a_column转换为aColumn。
- <settings>
- <!-- 将数据库字段命名规则A_COLUMN转换为Java使用的驼峰式命名规则aCloumn -->
- <setting name="mapUnderscoreToCamelCase" value="true" />
- </settings>
请注意select元素中#{id}的用法,这里就是告诉Mybatis创建一个预处理语句参数,通过JDBC,这样的参数在sql中会是用一个"?"来标识,并被传递到预处理语句中。就像下面这段代码:
- // Similar JDBC code, NOT MyBatis…
- String getById = "SELECT user_name, user_password, nick_name, email, user_type_id, is_valid, created_time FROM sys_user WHERE user_id=?";
- PreparedStatement ps = conn.prepareStatement(getById);
- ps.setInt(1,id);
当然,在获得结果集后,我们还需要额外编写很多代码,将结果集的中数据映射到一个Java对象上。如果使用Mybatis,这些全部省去了,想想都很让人兴奋。(Mybatis会将#{与}之间的内容转换为预处理语句中的"?")
select语句有,有很多属性允许我们来配置,以决定每条sql语句的作用细节。
<select id="getById" parameterType="int" parameterMap="deprecated" resultType="User" resultMap="userResultMap" flushCache="false" useCache="true" timeout="10000" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY">
在映射文件中定义好查询语句之后,就可以在Java代码中做如下调用:(这里插播个预告,在后面的《Mybatis系列之接口方式编程》中,我们会使用一个更简洁的方式来调用映射文件中的sql语句)
- @Test
- public void testGetById() {
- SqlSession session = sqlSessionFactory.openSession();
- try {
- User user;
- Object obj = session.selectOne("com.emerson.learning.mapping.user.getByID", 1);
- if (null == obj) {
- System.out.println("the result is null.");
- } else {
- user = (User) obj;
- System.out.println(user);
- }
- } finally {
- session.close();
- }
- }
插入语句映射
插入语句和查询语句类似,也需要定义唯一的id,指定传入参数类型。
- <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
- <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
- keyProperty="userId">
- INSERT INTO sys_user(user_name, user_password, nick_name,
- user_type_id, is_valid, created_time)
- VALUES(#{userName},
- #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
- #{createdTime})
- </insert>
针对插入语句,这里有一点需要进行特别说明,那就是如何获得新插入数据的主键值。
在允许使用自增长字段做为主键的数据库中(如MSSQL,MySQL),我们只需要在insert元素中增加两个属性值即可。如:
- <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="userId">
在不允许有自增字段的数据库中(如Oracle数据库),Mybatis有另外一种方法生成数据表主键,即在insert元素内部增加一个selectKey元素,用于生成数据表主键。如
- <insert id="insertUser" parameterType="User">
- <selectKey keyProperty="userId" resultType="int" order="BEFORE">
- select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
- </selectKey>
- INSERT INTO sys_user(user_name, user_password, nick_name,
- user_type_id, is_valid, created_time)
- VALUES(#{userName},
- #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
- #{createdTime})
- </insert>
- @Test
- public void testInsertUser() {
- SqlSession session = sqlSessionFactory.openSession();
- try {
- User user = new User();
- user.setEmail("chris.mao.zb@163.com");
- user.setNickName("Chris Mao");
- user.setUserName("cmzb");
- user.setIsValid(1);
- user.setUserPassword("5f4dcc3b5aa765d61d8327deb882cf99");
- <span class="s1" style="font-family: Arial, Helvetica, sans-serif;">int</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> </span><span style="font-family: Arial, Helvetica, sans-serif;">effectedRows</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> = </span><span style="font-family: Arial, Helvetica, sans-serif;">session.insert("com.emerson.learning.mapping.user.insertUser", user); </span><span style="font-family: Arial, Helvetica, sans-serif;">assertEquals(</span><span class="s1" style="font-family: Arial, Helvetica, sans-serif;">effectedRows</span><span style="font-family: Arial, Helvetica, sans-serif;">, 1);</span><span style="font-family: Arial, Helvetica, sans-serif;">
- lt;/span> System.out.println("New Id is " + user.getUserId());
- session.commit();
- } finally {
- session.close();
- }
- }
更新语句映射
- <update id="udpateUser" parameterType="User">
- UPDATE sys_user
- SET user_name = #{userName}, user_password = #{userPassword},nick_name = #{nickName},user_type_id = #{userTypeId},is_valid = #{isValid}
- WHERE user_id = #{<span style="font-family: Arial, Helvetica, sans-serif;">userId</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span>
- </update>
删除语句映射
这
- <delete id="deleteById" parameterType="int">
- DELETE FROM sys_user WHERE user_id = #{id}
- </delete>
SQL
这个元素用来定义可以重复使用的sql语句。可复用的不一定要是一个完整的sql语句,也可以是sql语句中的一部分,如字段名称等。
以查询和插入为例,我们在查询语句中会写出好多的列名称;同样,在插入语句时也要写出这些字段名称,那么这时,我们就可以把这部分重复的sql语句单独拿出来定义。如
- <sql id="columns">user_name, user_password, nick_name, email, user_type_id,
- is_valid, created_time</sql>
- <!-- 根据传入的Id值,到数据库中查询记录 -->
- <select id="getByID" parameterType="int" resultType="User">
- SELECT
- <include refid="columns"></include>
- FROM sys_user WHERE user_id = #{id}
- </select>
- <!-- 按用户名进行模糊查询 -->
- <select id="queryByName" parameterType="User" resultType="User">
- SELECT
- <include refid="columns"></include>
- FROM sys_user
- <where>
- <if test="userName != null">user_name like '%' #{userName} '%'</if>
- </where>
- </select>
- <!-- 创建新用户,并写入到数据表中 -->
- <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
- <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
- keyProperty="userId">
- INSERT INTO sys_user(<include refid="columns"></include>)
- VALUES(#{userName},
- #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
- #{createdTime})
- </insert>
查询参数
通过上面部分的讲解,细心的朋友已经发现了,Mybatis是使用#{}来定义参数的,出现在sql语句中的#{}都会为转换为预处理语句中的"?"。
如果参数是简单类型,如int, string等,则#{}中写什么名称什么名称都可以,或是写成通用的#{_parameter}。这种写法仅限于简单数据类型。
如果参数是一个自定义类型,则#{}中写的就是相应的属性名称,如#{userName},#{nickName}。
Mybatis还定义了另外一种参数形式,就是${}。这个可以理解成一个占位符,她会被替找成传入的值。
默认情况下,使用#{}格式的语法会导致Mybatis创建预处理语句属性,并安全地设置传入值(比如会自动对字符型数据两边加上引号等)。这样做更安全、更迅速,也是道选做法。不过有时只是想直接在sql语句中原样不变地插入一个字符串,比如ORDER BY ${COLUMN}。
查询结果集
ResultMap是Mybatis最重要、最强大,也是相对最复杂的一个元素。这里就不多做说明,待后续文章《Mybatis系列之一对多关系》时再做具体讲解。
缓存
- <cache />
这个简单语句效果如下:
- 映射文件中所有的select语句都将会被缓存
- 映射文件中所有的insert / update / delete语句会刷新缓存
- 缓存默认使用LRU最近最少使用算法来回收
- 根据时间表,缓存不会以作何时间顺序来刷新
- 缓存最多会存储列表集合或是对象的1024个引用
- 缓存被视为可读、写缓存,这意味着对象检索不是共享的,且可以安全地被调用者修改,而不干拢其他调用过或线程所做的潜在修改。
- <cache
- eviction="FIFO"
- flushInterval="60000"
- size="512"
- readOnly="true"/>
- LRU - 最近最少使用的:移除最长时间不被使用的对象
- FIFO - 先进先出:按对象进入缓存的时间顺序来移除
- SOFT - 软引用:移除基于垃圾回收器状态和软引用规则的对象
- WEAK - 弱引用:更积极地移除基于垃圾回收器状态和弱引用规则的对象
名称空间
每个sql映射文件的要元素中,都需要指定一个名称空间,用以确保每个映射语句的id属性不会重复。如
- <mapper namespace="com.emerson.learning.mapping.user">
- session.update("com.emerson.learning.mapping.user.udpateUser", user);
代码示例
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.emerson.learning.mapping.user">
- <sql id="columns">user_name, user_password, nick_name, email, user_type_id,
- is_valid, created_time</sql>
- <!-- 根据传入的Id值,到数据库中查询记录 -->
- <select id="getByID" parameterType="int" resultType="User">
- SELECT
- <include refid="columns"></include>
- FROM sys_user WHERE user_id = #{id}
- </select>
- <!-- 按用户名进行模糊查询 -->
- <select id="queryByName" parameterType="User" resultType="User">
- SELECT
- <include refid="columns"></include>
- FROM sys_user
- <where>
- <if test="userName != null">user_name like '%' #{userName} '%'</if>
- </where>
- </select>
- <!-- 创建新用户,并写入到数据表中 -->
- <!-- 写入新记录并返回主键值,注意,这里的KeyProperty应该是Java类里的属性名称,而非数据表中的字段名 -->
- <insert id="insertUser" parameterType="User" useGeneratedKeys="true"
- keyProperty="userId">
- INSERT INTO sys_user(<include refid="columns"></include>)
- VALUES(#{userName},
- #{userPassword}, #{nickName}, #{userTypeId}, #{isValid},
- #{createdTime})
- </insert>
- <!-- 更新用户信息,并写回到数据表中 -->
- <update id="udpateUser" parameterType="User">
- UPDATE sys_user
- <set>
- <if test="userName != null">user_name = #{userName},</if>
- <if test="userPassword != null">user_password = #{userPassword},</if>
- <if test="nickName != null">nick_name = #{nickName},</if>
- <if test="userTypeId != null">user_type_id = #{userTypeId},</if>
- <if test="isValid != null">is_valid = #{isValid}</if>
- </set>
- WHERE user_id = #{userId}
- </update>
- <!-- 根据传入的Id值,删除单条记录 -->
- <delete id="deleteById" parameterType="int">
- DELETE FROM sys_user WHERE
- user_id = #{id}
- </delete>
- <!-- 根据传入的Id值列表,删除多条记录 -->
- <delete id="deleteBatch" parameterType="java.util.List">
- DELETE FROM sys_user WHERE user_id in
- <foreach collection="list" item="item" index="index" open="("
- close=")" separator=",">
- #{item}
- </foreach>
- </delete>
- </mapper>
- Mybatis系列(四)映射文件
- Mybatis系列(四)映射文件
- Mybatis系列(四)映射文件
- Mybatis(四)映射文件
- mybatis-XML映射文件(四)
- J2EE系列之MyBatis学习笔记(四)-- mybatis关系映射(一对一映射)
- Mybatis学习总结(四).Mapper映射文件
- 【MyBatis】mybatis配置文件祥解(mybatis.xml)与映射文件祥解(StudentMapper.xml)(四)
- Mybatis深入了解(四)----输入输出映射
- Mybatis深入了解(四)----输入输出映射
- MyBatis四映射器
- Mybatis系列(七)关联映射
- Mybatis系列(八)集合映射
- mybatis系列-XML 映射配置文件(二)
- 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
- 深入浅出Mybatis系列(八)---mapper映射文件配置之select、resultMap
- 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
- 深入浅出Mybatis系列(七)---mapper映射文件配置之insert、update、delete
- spring boot 字段校验异常设计
- Mybatis Generator自动生成对应的文件
- Ubutun主账户登不上,输入密码后又回到输入密码界面
- 【图像处理】特征描述子
- CANOpenID分布及快速SDO通讯
- Mybatis系列(四)映射文件
- 机器人与贝叶斯准则
- golang fmt格式“占位符”
- 数据库修改主键类型
- Uncaught SyntaxError: Unexpected token o in JSON at position 1
- spring框架学习(3)
- 使用Maven管理项目jar包
- 【PythonDjango后台实例 第六章】Django实现简单的登陆验证功能
- unity中lightProbe的使用