MyBatis3:SQL映射
前言
前面学习了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映射的更多相关文章
- MyBatis 3 使用注解配置SQL映射器
l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l 动态SQL @Sel ...
- 使用注解配置SQL映射器
在上一章,我们看到了我们是怎样在映射器Mapper XML配置文件中配置映射语句的.MyBatis也支持使用注解来配置映射语句.当我们使用基于注解的映射器接口时,我们不再需要在XML配置文件中配置了. ...
- Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器
关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...
- MyBatis 3(中文版) 第四章 使用注解配置SQL映射器
本章将涵盖以下话题: l 在映射器Mapper接口上使用注解 l 映射语句 @Insert,@Update,@Delete,@SeelctStatements l 结果映射 一对一映射 一对多映射 l ...
- Mybatis基于接口注解配置SQL映射器(一)
上文已经讲解了基于XML配置的SQL映射器,在XML配置的基础上MyBatis提供了简单的Java注解,使得我们可以不配置XML格式的Mapper文件,也能方便的编写简单的数据库操作代码. Mybat ...
- SQL 映射的 XML 文件
MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方. 对于所有的力量, SQL映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大 ...
- 五、SQL映射的XML文件
MyBatis真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL映射的XML文件是相当的简单.当然如果你将它们和对等功能的JDBC代码来比较,你会发现映射文件节省了大约95%的代码 ...
- MyBatis(3):SQL映射
前面学习了config.xml,下面就要进入MyBatis的核心SQL映射了,第一篇文章的时候,student.xml里面是这么写的: 1 2 3 4 5 6 7 8 9 10 11 <?xml ...
- 讲讲Linq to SQL映射(基础篇)
讲讲Linq to SQL映射(基础篇) 这篇主要讲Linq to SQL基于属性的映射.即映射数据库,映射表,映射列,映射关系,映射存储过程, 映射函数.然而创建这种映射有三种方法,他们分别是OR ...
随机推荐
- C#给PDF文档添加文本和图片页眉
页眉常用于显示文档的附加信息,我们可以在页眉中插入文本或者图形,例如,页码.日期.公司徽标.文档标题.文件名或作者名等等.那么我们如何以编程的方式添加页眉呢?今天,这篇文章向大家分享如何使用了免费组件 ...
- 从I/O复用谈epoll为什么高效
上一篇文章中,谈了一些网络编程的基本概念.在现实使用中,用的最多的就是I/O复用了,无非就是select,poll,epoll 很多人提到网络就说epoll,认为epoll效率是最高的.单纯的这么认为 ...
- Java多线程基础——对象及变量并发访问
在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...
- ExtJS 4.2 Date组件扩展:添加清除按钮
ExtJS中除了提供丰富的组件外,我们还可以扩展他的组件. 在这里,我们将在Date日期组件上添加一个[清除]按钮,用于此组件已选中值的清除. 目录 1. Date组件介绍 2. 主要代码说明 3. ...
- 苹果强制使用HTTPS传输了怎么办?——关于HTTPS,APP开发者必须知道的事
WeTest 导读 2017年1月1日起,苹果公司将强制使用HTTPS协议传输.本文通过对HTTPS基础原理和通信过程内容的讲解,介绍APP开发者在这个背景下的应对办法. 几周前,我们在<htt ...
- Gradle 实现 Android 多渠道定制化打包
Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...
- 趣说游戏AI开发:曼哈顿街角的A*算法
0x00 前言 请叫我标题党!请叫我标题党!请叫我标题党!因为下面的文字既不发生在美国曼哈顿,也不是一个讲述美国梦的故事.相反,这可能只是一篇没有那么枯燥的关于算法的文章.A星算法,这个在游戏寻路开发 ...
- python之类介绍
python对象销毁(垃圾回收): 1>同Java语言一样,python使用了引用计数这一简单计数来追踪内存中的对象,也就是说,python内部记录着所有使用中的对象各有多少引用,一个内部跟踪变 ...
- AutoMapper(六)
返回总目录 List和数组 AutoMapper只要求元素类型的配置而不要求可能会用到的任何数组或者list类型.比如,我们有一个简单的源和目标类型: public class Source{ pub ...
- 腾讯云上免费部署HTTPS
接上篇<腾讯云下安装 nodejs + 实现 Nginx 反向代理>,想从头一步到位的同学建议从上篇文章开始阅读.本文将继续介绍如何通过 Nginx 免费部署HTTPS. 留意下,这里的“ ...