##概述
MyBatis是java项目持久层框架中比较优秀的一个,几乎满足项目中的一切需求。
MyBatis的核心是Mapper文件,Mapper文件中接收java对象参数,写sql语句,返回Java对象结果,所以下面讲解的知识都是在Mapper文件中的操作。
主要内容有:
- 基本使用说明。
- 传递参数。
- 返回值。
- insert时返回主键。
- jdbcType属性的使用。
- resultMap的使用。
- sql片段的使用。
- mapper.xml文件中特殊字符的处理。
##基本使用说明
在MyBatis的基本使用中,根据id查找对象的xml片段是:
<select id="queryOne" parameterType="int" resultType="studentModel">
select name,age
from student WHERE id=#{id}
</select>
说明:
- select:select是xml标签,表示查询。插入对应insert,更新对应update,删除对应delete.
- id:id是该xml片段的唯一标识,在同一个mapper文件中id不能重复。java程序根据该id找到对应的sql语句。
- parameterType:参数数据类型,参数类型需要写全类名或者写别名,int是框架自定义的别名。
- resultType:返回值数据类型,此与参数数据类型使用方法项目。
- sql语句:select标签中是sql语句。注意接收参数的形式:#{id}。
##传递参数
传递参数需要注意两点,一是设置参数类型,二是怎么接收参数。
一,设置参数类型
参数类型使用parameterType属性指定,参数类型需要写全类名或者写别名。
如果参数类型是int,全类名的写法如下:
parameterType="java.lang.Integer"
框架定义了常用类型的别名,java.lang.Integer的别名是int,所以int数据可以可以直接这么写:
parameterType="int"
##框架中定义的别名有:
8个基本数据类型,string,map。
注意:java.util.List不是默认别名,需要写全类名。
二,自定义别名
如果参数是我们自定义的类,比如:com.honor.mybatis.model.StudentModel写法如下:
parameterType="com.honor.mybatis.model.StudentModel"
这种写法比较麻烦,且此时是字符串,容易出错。所以此时需要自定义别名,然后使用别名即可。
MyBatis框架定义别名写在全局配置文件中(SqlMapConfig.xml)即可,如下:
<typeAliases>
<typeAlias type="com.honor.mybatis.model.StudentModel" alias="studentModel"/>
</typeAliases>
此时在Mapper文件中使用别名即可,如下:
parameterType="studentModel"
三,传递基本数据参数
接收int参数示例如下:
<select id="queryOne" parameterType="int" resultType="studentModel">
select name,age
from student WHERE id=#{id}
</select>
说明:
- parameterType指定数据类型为int。
- 在sql中使用#{id}接收参数,此时id是行参,可以自定义,即可以是任意变量。
三,对象参数
接收com.honor.mybatis.model.StudentModel参数示例如下:
<select id="queryList" parameterType="com.honor.mybatis.model.StudentModel" resultType="studentModel">
select name,age
from student WHERE name=#{name} AND age=#{age}
</select>
说明:
- parameterType指定数据类型为com.honor.mybatis.model.StudentModel。如果定义了别名此时也可以使用别名。。
- 在sql中使用#{name}和#{age}接收参数,此时name和age必须与StudentModel的字段名对应,不能自定义。
四,List参数
1,接收List<int>参数示例如下:
<select id="getObjectByIds" parameterType="java.util.List" resultType="studentModel">
select name,age
from student
where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</select>
说明:
- 此时是根据id集合查询student对象,所以要传递list参数。
- parameterType指定数据类型为java.util.List。
- foreach表示遍历,item表示集合中的元素。遍历后的结果相当于:(1,2,3,)。
- 取值使用#{item},此时的item与foreach标签的item属性值保持一致。
2,接收List<Student>参数示例如下:
<select id="getObjectByIds" parameterType="java.util.List" resultType="studentModel">
select name,age
from student
where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.id}
</foreach>
</select>
说明:
- 此时parameterType仍然是java.util.List。
- 取值使用#{item.id},此时的item与foreach标签的item属性值保持一致,表示集合中的元素,即student对象,id表示student的id字段。
五,Map参数
Map<String,Object>参数示例如下:
<select id="queryList" parameterType="map" resultType="studentModel">
select name,age
from student WHERE name=#{name} AND age=#{age}
</select>
说明:
- 此时parameterType是map。
- 在sql中使用#{name}和#{age}接收参数,此时name和age必须与map的键对应,不能自定义。
当Map的value是Student时示例如下:
<select id="queryList" parameterType="map" resultType="studentModel">
select name,age
from student WHERE name=#{student.name} AND age=#{student.age}
</select>
说明:
- 此时parameterType是map。
- 在sql中使用#{student.name}和#{student.age}接收参数,此时student必须与map的键对应,name和age是Student的字段名。
##返回值
一,返回基本数据类型
查询数据条数的sql返回值都是int,示例如下:
<select id="queryCount" parameterType="studentModel" resultType="int">
SELECT COUNT(*) FROM student
WHERE name=#{student.name} AND age=#{student.age}
</select>
说明:
- 使用resultType定义返回值类型,此时使用int。
- 查询到的数量只有一个值,会自动返回。
返回string类型的数据。示例如下:
<select id="queryOne" parameterType="int" resultType="string">
select name
from student WHERE id=#{id}
</select>
二,返回对象
返回对象的标准写法如下:
<select id="queryOne" parameterType="int" resultType="studentModel">
select name as name,age as age
from student WHERE id=#{id}
</select>
说明:
- 使用resultType定义返回值类型,此时是studentModel类。
- sql语句中as前的name是数据库的字段,as后的name是StudentModel类的字段。
如果数据库表字段名和类的字段名相同,则可以简写:
<select id="queryOne" parameterType="int" resultType="studentModel">
select name ,age
from student WHERE id=#{id}
</select>
三,返回List集合
返回List结合和返回单个对象在Mapper文件中的写法完全一样,返回值仍然写List中元素的类型,sql完全不变,只是sqlsession对象调用的方法不同。sqlsession的调用如下:
List<StudentModel> studentModelList = sqlSession.selectList("student.queryList", student);
四,返回Map对象
返回map对象示例如下:
<select id="queryOne" parameterType="int" resultType="map">
select name ,age
from student WHERE id=#{id}
</select>
注:此时返回的map对象的键分别是name和age,即与表字段名保持一直。
自定义map的key的写法如下:
<select id="queryOne" parameterType="int" resultType="map">
select name as name1 ,age as age1
from student WHERE id=#{id}
</select>
##insert时返回主键
在开发中很多情况下需要插入数据时返回主键,MyBatis中提供了该方法。但MySql和oracle数据库返回主键的方法不同。
一,MySql数据库insert时返回主键
具体如下:
<insert id="insert" parameterType="studentModel" useGeneratedKeys="true" keyProperty="id">
insert into student (name,age)
values(#{name},#{age})
</insert>
说明:
- useGeneratedKeys表示自动生成主键,keyProperty表示主键的字段。
- 返回的主键并不是在方法返回值中,而是在参数studentModel中。
sqlsession的代码如下:
//row为影响的条数
int row = sqlSession.insert("student.insert", student);
//id为返回的主键id
int id = student.getId();
二,Oracle数据库insert时返回主键
具体如下:
<insert id="insertUser" parameterType="studentModel">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
Select 序列名.nextval from dual
</selectKey>
insert into user(id,student,age)
values(#{id},#{student},#{age})
</insert>
注:因为roacle的主键id不是自增长的,所以一个表要关联一个序列号,获取下一个序列号的值当作表的主键。
##jdbcType属性的使用
一,jdbcType的使用
在上面的示例中sql语句都不是严格的写法,严格应该如下:
<insert id="insert" parameterType="studentModel" useGeneratedKeys="true" keyProperty="id">
insert into student (name,age)
values(#{name,jdbcType=VARCHAR},#{age,jdbcType=INTEGER})
</insert>
严格的写法要在获取数据时指定数据类型,jdbcType即是指定数据类型。
二,为什么要使用jdbcType
相信很多人在使用Mybatis时遇到过下面问题:
org.springframework.jdbc.UncategorizedSQLException: Error setting null parameter.
Most JDBC drivers require that the JdbcType must be specified for all nullable parameters.
Caused by: java.sql.SQLException: 无效的列类型: 1111
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
......
产生这个异常的原因是:当某个参数为null时,系统不知道该参数是什么数据类型,此时就会报错。
但是,我有一个大大的❓,为什么大部分时候都不报错,只有个别情况下报错。希望看到此处的大神给予留言帮助,感激不尽!
解决上面问题的方式就是使用jdbcType指定数据类型。
三,常用的jdbcType与java数据类型的对应关系
常用的对应关系如下:
VARCHAR String
NUMERIC java.math.BigDecimal
INTEGER int
BIGINT long
DOUBLE double
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
##resultMap的使用
一,定义resultMap
在mapper.xml文件中定义resultMap的方式如下:
<resultMap id="BaseResultMap" type="studentModel">
<result column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="age" jdbcType="VARCHAR" property="age"/>
<result column="created_time" jdbcType="TIMESTAMP" property="createdTime"/>
</resultMap>
说明:
- resultMap标签有两个属性,id是该resultMap的标识,type指定数据类型。
- 一个result标签对应数据库表中的字段,且对应Model类中的字段。column为数据库表中的字段,property为model类的字段。jdbcType为数据类型。
注:此时jdbyType的数据类型与上面讲的jdbcType的类型一致,但此时使用双引号,上面不需要双引号。
二,resultMap的使用
使用示例如下:
<select id="queryOne" parameterType="int" resultMap="BaseResultMap">
select name ,age
from student WHERE id=#{id}
</select>
说明:
- 这是一个查询语句,此时查询的结果封装到resultMap中,此时resultMap属性的值即为定义resultMap时的id。
- 此时select name时不需要写as name,会根据resultMap中定义的对应关系对应Model类中的字段。
- 在java代码中直接使用resultMap中定义的Model类数据接收即可。
三,resultMap的作用
resultMap有两大作用:
- 指定数据库表中的字段与Model类中的字段的对应关系。
- 可以复用。
##sql片段的使用
在mapper.xml文件中可以定义sql片段,然后被其他地方使用。具体如下:
一,sql片段的定义
<sql id="Base_Column_List">
id, name, age
</sql>
说明:
- 定义sql片段使用sql标签,id属性为该sql片段的标识。
- 在sql片段中可以是任意sql中的一段。
二,sql片段的使用
<select id="queryOne" parameterType="int" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from student WHERE id=#{id}
</select>
说明:
- 使用include引用sql片段,refid对应sql片段的ID。
- 引用sql片段等效于把该段sql写到引用处。
三,sql片段的作用
sql片段的最大作用就是复用,类似于java代码中的字符串常量,也便于修改维护。
##mapper.xml文件中特殊字符的处理
mapper.xml文件是一个xml文件,一些字符被作为xml的定义符号,当sql语句中使用这些特殊符号时需要做特殊处理。处理方式有两种,一种是使用转译字符,另外一种使用<![CDATA[ ]]>。
一,使用转译字符
常见的需要转译的字符如下:
原符号 < <= > >= & ' "
替换符号 < <= > >= & ' "
例如:sql如下:
create_date_time >= #{startTime} and create_date_time <= #{endTime}
二,使用<![CDATA[ ]]>
写在“<![CDATA[ ]]>”里面的字符不会被mybatis解析,直接拼接到sql语句中。如下:
大于等于
<![CDATA[ >= ]]>
小于等于
<![CDATA[ <= ]]>
例如:sql如下:
create_date_time <![CDATA[ >= ]]> #{startTime} and create_date_time <![CDATA[ <= ]]> #{endTime}
##总结
MyBatis是一个非常优秀的框架,不仅将sql与代码分离,而且提供了很好的数据交互方式。