前言

前面学习了config.xml,下面就要进入MyBatis的核心SQL映射了,第一篇文章的时候,student.xml里面是这么写的:

<?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.xrq.StudentMapper">
<select id="selectStudentById" parameterType="int" resultType="Student">
<![CDATA[
select * from student where studentId = #{id}
]]>
</select>
</mapper>

基于这个xml,进行扩展和学习。

为什么要使用<![CDATA[ ... ]]>?

上面的配置文件中,大家一定注意到了一个细节,就是SQL语句用<![CDATA[ ... ]]>这对标签包含起来了,那么为什么要这么做呢?不妨把上面内容稍微修改一下:

<?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.xrq.StudentMapper">
<select id="selectStudentById" parameterType="int" resultType="Student">
select * from student where studentId = #{id} or studentAge < 10 or studentAge > 20;
</select>
</mapper>

当然这句SQL语句没有任何含义,只是瞎写的演示用而已,运行一下看一下结果:

Exception in thread "main" java.lang.ExceptionInInitializerError
at com.xrq.test.MyBatisTest.main(MyBatisTest.java:9)
Caused by: org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in student.xml
...

后面的异常信息就不列了。按理说很正常的一句SQL语句,怎么会报错呢?仔细想来,错误的根本原因就是student.xml本身是一个xml文件,它并不是专门为MyBatis服务的,它首先具有xml文件的语法。因此,"< 10 or studentAge >"这段,会先被解析为xml的标签,xml哪有这种形式的标签的?所以当然报错了。

所以,使用<![CDATA[ ... ]]>,它可以保证如论如何<![CDATA[ ... ]]>里面的内容都会被解析成SQL语句。因此,建议每一条SQL语句都使用<![CDATA[ ... ]]>包含起来,这也是一种规避错误的做法。

select

SQL映射中有几个顶级元素,其中最常见的四个就是insert、delete、update、select,分别对应于增、删、改、查,下面先对于select元素进行学习。

1、多条件查询查一个结果

前面的select语句只有一个条件,下面看一下多条件查询如何做,首先是student.xml:

<select id="selectStudentByIdAndName" parameterType="Student" resultType="Student">
<![CDATA[
select * from student where studentId = #{studentId} and studentName = #{studentName};
]]>
</select>

注意这里的parameter只能是一个实体类,然后参数要和实体类里面定义的一样,比如studentId、studentName,MyBatis将会自动查找这些属性,然后将它们的值传递到预处理语句的参数中去。

还有一个很重要的地方是,使用参数的时候使用了"#",另外还有一个符号"$"也可以引用参数,使用"#"最重要的作用就是防止SQL注入

接着看一下Java代码的写法:

public Student selectStudentByIdAndName(int studentId, String studentName)
{
SqlSession ss = ssf.openSession();
Student student = null;
try
{
student = ss.selectOne("com.xrq.StudentMapper.selectStudentByIdAndName",
new Student(studentId, studentName, 0, null));
}
finally
{
ss.close();
}
return student;
}

这里selectOne方法的第二个参数传入一个具体的Student进去就可以了,运行就不演示了,结果没有问题。

2、查询多个结果

上面的演示查询的是一个结果,对于select来说,重要的当然是查询多个结果,查询多个结果有相应的写法,看一下:

<select id="selectAll" parameterType="int" resultType="Student" flushCache="false" useCache="true"
timeout="10000" fetchSize="100" statementType="PREPARED" resultSetType="FORWARD_ONLY">
<![CDATA[
select * from student where studentId > #{id};
]]>
</select>

这里稍微玩了一些花样,select里面多放了一些属性,设置了每条语句的作用细节,分别解释下这些属性的作用:

  • id----不说了,用来和namespace唯一确定一条引用的SQL语句
  • parameterType----参数类型,如果SQL语句中的动态参数只有一个,这个属性可有可无
  • resultType----结果类型,注意如果返回结果是集合,应该是集合所包含的类型,而不是集合本身
  • flushCache----将其设置为true,无论语句什么时候被调用,都会导致缓存被清空,默认值为false
  • useCache----将其设置为true,将会导致本条语句的结果被缓存,默认值为true
  • timeout----这个设置驱动程序等待数据库返回请求结果,并抛出异常事件的最大等待值,默认这个参数是不设置的(即由驱动自行处理)
  • fetchSize----这是设置驱动程序每次批量返回结果的行数,默认不设置(即由驱动自行处理)
  • statementType----STATEMENT、PREPARED或CALLABLE的一种,这会让MyBatis选择使用Statement、PreparedStatement或CallableStatement,默认值为PREPARED。这个相信大多数朋友自己写JDBC的时候也只用过PreparedStatement
  • resultSetType----FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE中的一种,默认不设置(即由驱动自行处理)

xml写完了,看一下如何写Java程序,比较简单,使用selectList方法即可:

public List<Student> selectStudentsById(int studentId)
{
SqlSession ss = ssf.openSession();
List<Student> list = null;
try
{
list = ss.selectList("com.xrq.StudentMapper.selectAll", studentId);
}
finally
{
ss.close();
}
return list;
}

同样,结果也就不演示了,查出来和数据库内的数据相符。

3、使用resultMap来接收查询结果

上面使用的是resultType来接收查询结果,下面来看另外一种方式----使用resultMap,被MyBatis称为MyBatis中最重要最强大的元素。

上面使用resultType的方式是有前提的,那就是假定列名和Java Bean中的属性名存在对应关系,如果名称不对应,也没关系,可以采用类似下面的方式:

<select id="selectAll" parameterType="int" resultType="Student" flushCache="false" useCache="true"
timeout="10000" fetchSize="100" statementType="PREPARED" resultSetType="FORWARD_ONLY">
<![CDATA[
select student_id as "studentId",student_name as "studentName",student_age as "studentAge",
      student_phone as "studentPhone" from student whehre restudentId > #{id};
]]>
</select>

毫无疑问,这样很繁琐,我们可以采用resultMap来解决列名不匹配的问题,把2由resultType的形式改成resultMap的形式,Java代码不需要动:

<resultMap type="Student" id="studentResultMap">
<id property="studentId" column="studentId" />
<result property="studentName" column="studentName" />
<result property="studentAge" column="studentAge" />
<result property="studentPhone" column="studentPhone" />
</resultMap> <select id="selectAll" parameterType="int" resultMap="studentResultMap" flushCache="false" useCache="true"
timeout="10000" fetchSize="100" statementType="PREPARED" resultSetType="FORWARD_ONLY">
<![CDATA[
select * from student where studentId > #{id};
]]>
</select>

这样就可以了,注意两点:

1、resultMap定义中主键要使用id

2、resultMap和resultType不可以同时使用

对resultMap有很好的理解的话,许多复杂的映射问题就很好解决了。

insert

select看完了,接着看一下插入的方法。首先是student.xml的配置方法,由于插入数据涉及一个主键问题,我用的是MySQL,我试了一下使用以下两种方式都可以:

<insert id="insertOneStudent" parameterType="Student">
<![CDATA[
insert into student values(null, #{studentName}, #{studentAge}, #{studentPhone});
]]>
</insert>
<insert id="insertOneStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="studentId">
<![CDATA[
insert into student(studentName, studentAge, studentPhone)
values(#{studentName}, #{studentAge}, #{studentPhone});
]]>
</insert>

前一种是MySQL本身的语法,主键字段在insert的时候传入null,后者是MyBatis支持的生成主键方式,useGeneratedKeys表示让数据库自动生成主键,keyProperty表示生成主键的列。

Java代码比较容易:

public void insertOneStudent(String studentName, int studentAge, String studentPhone)
{
SqlSession ss = ssf.openSession();
try
{
ss.insert("com.xrq.StudentMapper.insertOneStudent",
new Student(0, studentName, studentAge, studentPhone));
ss.commit();
}
catch (Exception e)
{
ss.rollback();
}
finally
{
ss.close();
}
}

还是一样,insert方法比如传入Student的实体类,如果insertOneStudent方法要传入的参数比较多的话,建议不要把每个属性单独作为形参,而是直接传入一个Student对象,这样也比较符合面向对象的编程思想。

然后还有一个问题,这个我回头还得再看一下。照理说设置了transactionManager的type为JDBC,对事物的处理应该和底层JDBC是一致的,JDBC默认事物是自动提交的,这里事物却得手动提交,抛异常了得手动回滚才行。

修改、删除元素

修改和删除元素比较类似,就看一下student.xml文件怎么写,Java代码就不列了,首先是修改元素:

<update id="updateStudentAgeById" parameterType="Student">
<![CDATA[
update student set studentAge = #{studentAge} where
studentId = #{studentId};
]]>
</update>

接着是删除元素:

<delete id="deleteStudentById" parameterType="int">
<![CDATA[
delete from student where studentId = #{studentId};
]]>
</delete>

这里我又发现一个问题,记录一下,update的时候Java代码是这么写的:

public void updateStudentAgeById(int studentId, int studentAge)
{
SqlSession ss = ssf.openSession();
try
{
ss.update("com.xrq.StudentMapper.updateStudentAgeById",
new Student(studentId, null, studentAge, null));
ss.commit();
}
catch (Exception e)
{
ss.rollback();
}
finally
{
ss.close();
}
}

studentId和studentAge必须是这个顺序,互换位置就更新不了学生的年龄了,这个是为什么我还要后面去研究一下,也可能是写代码的问题。

SQL

SQL可以用来定义可重用的SQL代码段,可以包含在其他语句中,比如我把上面的插入换一下,先定义一个SQL:

<sql id="insertColumns">
studentName, studentAge, studentPhone
</sql>

然后在修改一下insert:

<insert id="insertOneStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="studentId">
insert into student(<include refid="insertColumns" />)
values(#{studentName}, #{studentAge}, #{studentPhone});
</insert>

注意这里要把"<![CDATA[ ... ]]>"给去掉,否则"<"和">"就被当成SQL里面的小于和大于了,因此使用SQL的写法有一定限制,使用前要注意一下避免出错。

MyBatis3:SQL映射的更多相关文章

  1. MyBatis 3 使用注解配置SQL映射器

    l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l 动态SQL @Sel ...

  2. 使用注解配置SQL映射器

    在上一章,我们看到了我们是怎样在映射器Mapper XML配置文件中配置映射语句的.MyBatis也支持使用注解来配置映射语句.当我们使用基于注解的映射器接口时,我们不再需要在XML配置文件中配置了. ...

  3. Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...

  4. MyBatis 3(中文版) 第四章 使用注解配置SQL映射器

    本章将涵盖以下话题: l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l ...

  5. Mybatis基于接口注解配置SQL映射器(一)

    上文已经讲解了基于XML配置的SQL映射器,在XML配置的基础上MyBatis提供了简单的Java注解,使得我们可以不配置XML格式的Mapper文件,也能方便的编写简单的数据库操作代码. Mybat ...

  6. SQL 映射的 XML 文件

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方. 对于所有的力量, SQL映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大 ...

  7. 五、SQL映射的XML文件

    MyBatis真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL映射的XML文件是相当的简单.当然如果你将它们和对等功能的JDBC代码来比较,你会发现映射文件节省了大约95%的代码 ...

  8. MyBatis(3):SQL映射

    前面学习了config.xml,下面就要进入MyBatis的核心SQL映射了,第一篇文章的时候,student.xml里面是这么写的: 1 2 3 4 5 6 7 8 9 10 11 <?xml ...

  9. 讲讲Linq to SQL映射(基础篇)

    讲讲Linq to SQL映射(基础篇) 这篇主要讲Linq to  SQL基于属性的映射.即映射数据库,映射表,映射列,映射关系,映射存储过程, 映射函数.然而创建这种映射有三种方法,他们分别是OR ...

随机推荐

  1. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  2. Npm包的开发

    个人开发包的目录结构 ├── coverage //istanbul测试覆盖率生成的文件 ├── index.js //入口文件 ├── introduce.md //说明文件 ├── lib │   ...

  3. ImageView缩放选项

    ImageView.ScaleType 将图片边界缩放到所在view边界时的缩放选项. Options for scaling the bounds of an image to the bounds ...

  4. sublime常用快捷键

    自己觉得比较实用的sublime快捷键: Ctrl + /  ---------------------注释 Ctrl + 滚动 --------------字体变大/缩小 Ctrl + N----- ...

  5. SQL Server 常用内置函数(built-in)持续整理

    本文用于收集在运维中经常使用的系统内置函数,持续整理中 一,常用Metadata函数 1,查看数据库的ID和Name db_id(‘DB Name’),db_name('DB ID') 2,查看对象的 ...

  6. 移动硬盘不能识别的常见7种解决方案 ~ By 逆天经验

    服务器汇总:http://www.cnblogs.com/dunitian/p/4822808.html#iis 服务器异常: http://www.cnblogs.com/dunitian/p/45 ...

  7. redux-undo

    简介 通过包装reducer,创建一个state History,保留历史state,可以做退一步,进一步操作 1.install npm install --save redux-undo@beta ...

  8. kafka学习笔记:知识点整理

    一.为什么需要消息系统 1.解耦: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余: 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险. ...

  9. setCapture、releasCapture 浅析

    1. setCapture 简介 setCapture可以将鼠标事件锁定在指定的元素上,当元素捕获了鼠标事件后,该事件只能作用在当前元素上. 以下情况会导致事件锁定失败: 当窗口失去焦点时,锁定的事件 ...

  10. 高德地图api实现地址和经纬度的转换(python)

    利用高德地图web服务api实现地理/逆地址编码 api使用具体方法请查看官方文档 文档网址:http://lbs.amap.com/api/webservice/guide/api/georegeo ...