MyBatis(3):SQL映射
前面学习了config.xml,下面就要进入MyBatis的核心SQL映射了,第一篇文章的时候,student.xml里面是这么写的:
1
2
3
4
5
6
7
8
9
10
11
|
<? 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[ ... ]]>这对标签包含起来了,那么为什么要这么做呢?不妨把上面内容稍微修改一下:
1
2
3
4
5
6
7
8
9
|
<? 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语句没有任何含义,只是瞎写的演示用而已,运行一下看一下结果:
1
2
3
4
5
6
|
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:
1
2
3
4
5
|
< select id = "selectStudentByIdAndName" parameterType = "Student" resultType = "Student" > <![CDATA[ select * from student where studentId = #{studentId} and studentName = #{studentName}; ]]> </ select > |
注意这里的parameter只能是一个实体类,然后参数要和实体类里面定义的一样,比如studentId、studentName,MyBatis将会自动查找这些属性,然后将它们的值传递到预处理语句的参数中去。
还有一个很重要的地方是,使用参数的时候使用了”#”,另外还有一个符号”$”也可以引用参数,使用”#”最重要的作用就是防止SQL注入。
接着看一下Java代码的写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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来说,重要的当然是查询多个结果,查询多个结果有相应的写法,看一下:
1
2
3
4
5
6
|
< 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方法即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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中的属性名存在对应关系,如果名称不对应,也没关系,可以采用类似下面的方式:
1
2
3
4
5
6
7
|
< 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代码不需要动:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
< 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,我试了一下使用以下两种方式都可以:
1
2
3
4
5
|
< insert id = "insertOneStudent" parameterType = "Student" > <![CDATA[ insert into student values(null, #{studentName}, #{studentAge}, #{studentPhone}); ]]> </ insert > |
1
2
3
4
5
6
|
< 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代码比较容易:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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代码就不列了,首先是修改元素:
1
2
3
4
5
6
|
< update id = "updateStudentAgeById" parameterType = "Student" > <![CDATA[ update student set studentAge = #{studentAge} where studentId = #{studentId}; ]]> </ update > |
接着是删除元素:
1
2
3
4
5
|
< delete id = "deleteStudentById" parameterType = "int" > <![CDATA[ delete from student where studentId = #{studentId}; ]]> </ delete > |
这里我又发现一个问题,记录一下,update的时候Java代码是这么写的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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:
1
2
3
|
< sql id = "insertColumns" > studentName, studentAge, studentPhone </ sql > |
然后在修改一下insert:
1
2
3
4
|
< insert id = "insertOneStudent" parameterType = "Student" useGeneratedKeys = "true" keyProperty = "studentId" > insert into student(< include refid = "insertColumns" />) values(#{studentName}, #{studentAge}, #{studentPhone}); </ insert > |
注意这里要把”<![CDATA[ ... ]]>”给去掉,否则”<”和”>”就被当成SQL里面的小于和大于了,因此使用SQL的写法有一定限制,使用前要注意一下避免出错。
MyBatis(3):SQL映射的更多相关文章
- Mybatis(二) SQL映射文件
SQL映射文件 单条件查询 1. 在UserMapper接口添加抽象方法 //根据用户名模糊查询 List<User> getUserListByName(); 2. 在UserMappe ...
- 初始MyBatis、SQL映射文件
MyBatis入门 1.MyBatis前身是iBatis,是Apache的一个开源项目,2010年这个项目迁移到了Google Code,改名为MyBatis,2013年迁移到GitHub.是一个基于 ...
- mybatis的sql映射文件—增删改查
前提:需要的包log4j.jar,mybatis-3.4.1.jar,mysql-connector-java-5.1.37-bin.jar 1.基本类 员工类 package com.hand.my ...
- 传参在mybatis的sql映射文件中正确获取
1.单个参数: 非自定义对象 传参:getStuById(Integer id): 取值:#{id} 单个基本类型参数,随便取值都行:#{ok} 对象: 传参:saveStudent(Student ...
- 关于Mybatis的SQL映射文件中in关键字的用法
有一个需求是可以选择多个设备进行删除,于是想到将多个设备id拼成字符串作为参数,以逗号隔开,如:"123,234,456". SQL如下: <delete id=" ...
- mybatis的sql映射文件不能打包进目录解决办法
方法二: <build> <finalName>qwe</finalName> <plugins> <plugin> <groupId ...
- 关于mybatis中sql映射文件模糊查询的使用
1.从前台传递一个String类型的参数到后台进行查询,如果牵涉到模糊查询会报错,应该把参数封装到对象中再进行传递然后进行模糊查询 2.一个查询框,多个查询条件 <if test="c ...
- MyBatis 的基本要素—SQL 映射文件
MyBatis 真正的强大在于映射语句,相对于它强大的功能,SQL 映射文件的配置却是相当简单.对比 SQL 映射配置和 JDBC 代码,发现使用 SQL 映射文件配置可减少 50% 以上的代码,并且 ...
- MyBatis --- 动态SQL、缓存机制
有的时候需要根据要查询的参数动态的拼接SQL语句 常用标签: - if:字符判断 - choose[when...otherwise]:分支选择 - trim[where,set]:字符串截取,其中w ...
随机推荐
- Android 发送验证码 简易代码
效果 Activity ;//倒计时 private Timer timer; private Handler handler = new Handler() { public void handle ...
- APP长时间处于后台,再次调用时提示用户重新登录
第一步:当应用被处于后台时,调用计时器的start()方法,开始计时 在所有Activity继承的BaseSwiBackAct中的 public void onStop() { EventBus.ge ...
- Android虚拟机GenyMotion-- 遇到的问题
问题: android studio 检测不到 genymotion 原因:没有设置genymotion的adb,也就是sdk的路径. 解决方法:打开genymotion的主页面,设置sdk的位置为你 ...
- Linq 实现普通sql中 where in 的功能
user.ProjectIds 的值是使用逗号分隔的 例如:1,2,3 projectList = (from a in projectList where (user.ProjectIds.Spli ...
- StartCoroutine/StopCoroutineInvoke
本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/Unity_Coroutine.html using UnityEngine; us ...
- Android开发-解决 AIDL 中找不到couldn't find import for class错误
最近在使用AIDL做IPC的时候,在处理复杂的数据类型的时候,编译器总是报couldn't find import for class错误,所以在这里总结下AIDL使用的时候的一些注意事项,希望对你能 ...
- 网易DBA私享会分享会笔记1
1.mysql生态+DBA职业发展世界范围流行的开源关系型的数据库关系型数据库:mysql,oracle,sql server,access,postgresql,sqlite,sybase,info ...
- Dede 查询附加表
<!--使用dede:arclist取出信息 dede_archives 表 $sql="Select 字段 from dede_archivies",但是在默认情况下 de ...
- ASP.NET程序从IIS6移植到IIS7时出现500.22错误
最可能的原因: • 此应用程序在 system.web/httpModules 节中定义配置. 可尝试的操作: • 将配置迁移到 system.webServer/modules 节 ...
- [转] .NET 3.5中MSChart组件的ImageLocation属性含义
在.NET程序/网站中如果要生成统计图表/图形,以前可以采用OWC(Office Web Components),如OfficeXP组件OWC10.Office2003组件OWC11.OWC采用COM ...