【注意事项】
1、接口的方法名和参数类型要与Mapper文件中的id和parameterType必须保持一致。
2、再用Session进行数据操作时,最后一定要session.commit();,否则没有提交。
3、Mybatis中like的写法 like concat('%',#{param},'%') 或者 like '%${param}%' ,推荐使用前者,可以避免sql注入。
1、查询数据。
当返回的数据是单条记录,可以采用在MyBatis中设置实体类别名的方式,也就是
<select id="selectUsers" parameterType="string" resultMap="User">
如上
但是如果返回的是多条记录,则需要在Mapper文件中配置相应的返回类型resultMap。如下:
<!-- 为了返回list 类型而定义的returnMap -->
<resultMap type="User" id="resultListUser">
<id column="id" property="id" />
<result column="userName" property="userName" />
<result column="userAge" property="userAge" />
<result column="userAddress" property="userAddress" />
</resultMap>
其中,主键采用字段名配置,其他字段采用result方式。column代表SQL语句中的字段名,property代表实体类中的属性名。
【查询语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名(在Mybatis中配置文件中为实体类配置的别名)
resultType:语句返回值类型的整类名或别名。注意,如果是集合,那么这里填写的是集合的项的整类名或别名,而不是集合本身的类名。(resultType 与resultMap 不能并用)
resultMap:引用的外部resultMap 名。结果集映射是MyBatis 中最强大的特性。许多复杂的映射都可以轻松解决。(resultType 与resultMap 不能并用)
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement,preparedstatement,callablestatement。预准备语句、可调用语句
resultSetType:forward_only,scroll_sensitive,scroll_insensitive。只转发,滚动敏感,不区分大小写的滚动
2、增加数据
Mapper中增加语句的写法有两个重要属性,分别是useGeneratedKeys和keyProperty。
useGeneratedKeys是否启用数据库生成的主键。
keyProperty生成的主键赋值的字段是哪个。如下:
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})
</insert>
另外还有一种方式,如下:
<insert id="insertStudentAutoKey" parameterType="StudentEntity">
<selectKey keyProperty="studentID" resultType="String" order="BEFORE">
select nextval('student')
</selectKey>
INSERT INTO STUDENT_TBL (STUDENT_ID,
STUDENT_NAME,
STUDENT_SEX,
STUDENT_BIRTHDAY,
CLASS_ID)
VALUES (#{studentID},
#{studentName},
#{studentSex},
#{studentBirthday},
#{classEntity.classID})
</insert>
其中 #{userName}代表实体类中的属性名。
【增加语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句
useGeneratedKeys:告诉MyBatis 使用JDBC 的getGeneratedKeys 方法来获取数据库自己生成的主键(MySQL、SQLSERVER 等关系型数据库会有自动生成的字段)。默认:false
keyProperty:标识一个将要被MyBatis设置进getGeneratedKeys的key 所返回的值,或者为insert 语句使用一个selectKey子元素。
【批量插入】
方法一:
<insert id="add" parameterType="EStudent">
<foreach collection="list" item="item" index="index" separator=";">
INSERT INTO TStudent(name,age) VALUES(#{item.name}, #{item.age})
</foreach>
</insert>
上述方式相当语句逐条INSERT语句执行,将出现如下问题:
1. mapper接口的add方法返回值将是最后一条INSERT语句的操作成功的记录数目(就是0或1),而不是所有INSERT语句的操作成功的总记录数目
2. 当其中一条不成功时,不会进行整体回滚。
方法二:
<insert id="insertStudentAutoKey" parameterType="java.util.List">
INSERT INTO STUDENT_TBL (STUDENT_NAME,
STUDENT_SEX,
STUDENT_BIRTHDAY,
CLASS_ID)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
( #{item.studentName},#{item.studentSex},#{item.studentBirthday},#{item.classEntity.classID})
</foreach>
</insert>
3、更新数据,示例如下:
<update id="updateStudent" parameterType="StudentEntity">
UPDATE STUDENT_TBL
SET STUDENT_TBL.STUDENT_NAME = #{studentName},
STUDENT_TBL.STUDENT_SEX = #{studentSex},
STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},
STUDENT_TBL.CLASS_ID = #{classEntity.classID}
WHERE STUDENT_TBL.STUDENT_ID = #{studentID};
</update>
【更新语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句
【批量更新】
方法一:(适用于将不同的记录更新不同的值)
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update course
<set>
name=${item.name}
</set>
where id = ${item.id}
</foreach>
</update>
方法二:(适用于将不同记录的更新同样的值)
<update id="updateOrders" parameterType="java.util.List">
update orders set state = '0' where no in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
4、删除数据 示例如下:
<delete id="deleteStudent" parameterType="StudentEntity">
DELETE FROM STUDENT_TBL WHERE STUDENT_ID = #{studentID}
</delete>
【批量删除】
<delete id="batchRemoveUserByPks" parameterType="java.util.List">
DELETE FROM LD_USER WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
5、Sql元素
Sql元素用来定义一个可以复用的SQL 语句段,供其它语句调用。比如:
<!-- 复用sql语句 查询student表所有字段 -->
<sql id="selectStudentAll">
SELECT ST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.CLASS_ID
FROM STUDENT_TBL ST
</sql>
<!-- 查询学生,根据id -->
<select id="getStudent" parameterType="String" resultMap="studentResultMap">
<include refid="selectStudentAll"/>
WHERE ST.STUDENT_ID = #{studentID}
</select>
6、parameters使用
MyBatis可以使用Java的基本数据类型和Java的复杂数据类型。如:基本数据类型,String,int,date等。
但是使用基本数据类型,只能提供一个参数,所以需要使用Java实体类,或Map类型做参数类型。通过#{}可以直接得到其属性。
【基本类型参数】示例如下:
<select id="getStudentListByDate" parameterType="Date" resultMap="studentResultMap">
SELECT *
FROM STUDENT_TBL ST LEFT JOIN CLASS_TBL CT ON ST.CLASS_ID = CT.CLASS_ID
WHERE CT.CLASS_YEAR = #{classYear};
</select>
【Java实体类型参数】 示例如下:
<select id="getStudentListWhereEntity" parameterType="StudentEntity" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
WHERE ST.STUDENT_NAME LIKE CONCAT('%', #{studentName},'%')
AND ST.STUDENT_SEX = #{studentSex}
</select>
【Map参数】
<select id="getStudentListWhereMap" parameterType="Map" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
WHERE ST.STUDENT_SEX = #{sex}
AND ST.STUDENT_name = #{name}
</select>
【多参数实现】
如果想传入多个参数,则需要在接口的参数上添加@Param注解。给出一个实例:
public List<StudentEntity> getStudentListWhereParam(@Param(value = "name") String name, @Param(value = "sex") String sex, @Param(value = "birthday") Date birthdar, @Param(value = "classEntity") ClassEntity classEntity);
应用如下:
<select id="getStudentListWhereParam" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
<where>
<if test="name!=null and name!='' ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="sex!= null and sex!= '' ">
AND ST.STUDENT_SEX = #{sex}
</if>
<if test="birthday!=null">
AND ST.STUDENT_BIRTHDAY = #{birthday}
</if>
<if test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' ">
AND ST.CLASS_ID = #{classEntity.classID}
</if>
</where>
</select>
7、#{}与${}的区别
默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义。
示例1:
执行SQL:Select * from emp where name = #{employeeName}
参数:employeeName=>Smith
解析后执行的SQL:Select * from emp where name = ?
执行SQL:Select * from emp where name = ${employeeName}
参数:employeeName传入值为:Smith
解析后执行的SQL:Select * from emp where name =Smith
说明:
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #{user_id},如果传入的值是111,那么解析成sql时的值为order by “111”,
如果传入的值是id,则解析成的sql为order by “id”.
2. $将传入的数据直接显示生成在sql中。如:order by ${user_id},如果传入的值是111,那么解析成sql时的值为order by 111, 如果传入的值是id,则解析成的sql为order by id.
综上所述,${}方式会引发SQL注入的问题、同时也会影响SQL语句的预编译,所以从安全性和性能的角度出发,能使用#{}的情况下就不要使用${}。
${}在什么情况下使用呢?
有时候可能需要直接插入一个不做任何修改的字符串到SQL语句中。这时候应该使用${}语法。
比如,动态SQL中的字段名,如:ORDER BY ${columnName}
<select id="queryMetaList" resultType="Map" statementType="STATEMENT">
Select * from emp where name = ${employeeName} ORDER BY ${columnName}
</select>
由于${}仅仅是简单的取值,所以以前sql注入的方法适用此处,如果我们order by语句后用了${},那么不做任何处理的时候是存在sql注入危险的。
8、Mybatis调用存储过程 xml示例代码如下:
--------------------------------------------存储过程基本调用-------------------------------------------------------------
create procedure sptest.adder(in addend1 integer, in addend2 integer, out theSum integer)
begin atomic
set theSum = addend1 + addend2;
end
go
<parameterMap type="map" id="testParameterMap">
<parameter property="addend1" jdbcType="INTEGER" mode="IN"/>
<parameter property="addend2" jdbcType="INTEGER" mode="IN"/>
<parameter property="sum" jdbcType="INTEGER" mode="OUT"/>
</parameterMap>
<update id="adderWithParameterMap" parameterMap="testParameterMap" statementType="CALLABLE">
{call sptest.adder(?, ?, ?)}
</update>
JAVA调用
public void testAdderAsUpdateWithParameterMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("addend1", 3);
parms.put("addend2", 4);
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
spMapper.adderWithParameterMap(parms);
assertEquals(7, parms.get("sum"));
} finally {
sqlSession.close();
}
}
----------------------------------------带输入输出参数的存储过程------------------------------------------------------------------------------
create procedure sptest.getnames(in lowestId int, out totalrows integer)
BEGIN ATOMIC
declare cur cursor for select * from sptest.names where id >= lowestId;
select count(*) into totalrows from sptest.names where id >= lowestId;
open cur;
END
go
<select id="getNames" parameterType="java.util.Map" statementType="CALLABLE" resultMap="nameResult">
{call sptest.getnames(
#{lowestId,jdbcType=INTEGER,mode=IN},
#{totalRows,jdbcType=INTEGER,mode=OUT})}
</select>
JAVA调用
public void testCallWithResultSet2_a1() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("lowestId", 1);
List<Name> names = spMapper.getNamesAnnotated(parms);
assertEquals(3, names.size());
assertEquals(3, parms.get("totalRows"));
} finally {
sqlSession.close();
}
}
---------------------------------------返回多个结果集------------------------------------------------------
create procedure sptest.getnamesanditems()
reads sql data
dynamic result sets 2
BEGIN ATOMIC
declare cur1 cursor for select * from sptest.names;
declare cur2 cursor for select * from sptest.items;
open cur1;
open cur2;
END
go
<resultMap type="org.apache.ibatis.submitted.sptests.Name" id="nameResult">
<result column="ID" property="id"/>
<result column="FIRST_NAME" property="firstName"/>
<result column="LAST_NAME" property="lastName"/>
</resultMap>
<resultMap type="org.apache.ibatis.submitted.sptests.Item" id="itemResult">
<result column="ID" property="id"/>
<result column="ITEM" property="item"/>
</resultMap>
<select id="getNamesAndItems" statementType="CALLABLE"
resultMap="nameResult,itemResult">
{call sptest.getnamesanditems()}
</select>
JAVA调用
public void testGetNamesAndItems() throws SQLException {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
List<List<?>> results = spMapper.getNamesAndItems();
assertEquals(2, results.size());
assertEquals(4, results.get(0).size());
assertEquals(3, results.get(1).size());
} finally {
sqlSession.close();
}
}
1、接口的方法名和参数类型要与Mapper文件中的id和parameterType必须保持一致。
2、再用Session进行数据操作时,最后一定要session.commit();,否则没有提交。
3、Mybatis中like的写法 like concat('%',#{param},'%') 或者 like '%${param}%' ,推荐使用前者,可以避免sql注入。
1、查询数据。
当返回的数据是单条记录,可以采用在MyBatis中设置实体类别名的方式,也就是
<select id="selectUsers" parameterType="string" resultMap="User">
如上
但是如果返回的是多条记录,则需要在Mapper文件中配置相应的返回类型resultMap。如下:
<!-- 为了返回list 类型而定义的returnMap -->
<resultMap type="User" id="resultListUser">
<id column="id" property="id" />
<result column="userName" property="userName" />
<result column="userAge" property="userAge" />
<result column="userAddress" property="userAddress" />
</resultMap>
其中,主键采用字段名配置,其他字段采用result方式。column代表SQL语句中的字段名,property代表实体类中的属性名。
【查询语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名(在Mybatis中配置文件中为实体类配置的别名)
resultType:语句返回值类型的整类名或别名。注意,如果是集合,那么这里填写的是集合的项的整类名或别名,而不是集合本身的类名。(resultType 与resultMap 不能并用)
resultMap:引用的外部resultMap 名。结果集映射是MyBatis 中最强大的特性。许多复杂的映射都可以轻松解决。(resultType 与resultMap 不能并用)
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement,preparedstatement,callablestatement。预准备语句、可调用语句
resultSetType:forward_only,scroll_sensitive,scroll_insensitive。只转发,滚动敏感,不区分大小写的滚动
2、增加数据
Mapper中增加语句的写法有两个重要属性,分别是useGeneratedKeys和keyProperty。
useGeneratedKeys是否启用数据库生成的主键。
keyProperty生成的主键赋值的字段是哪个。如下:
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})
</insert>
另外还有一种方式,如下:
<insert id="insertStudentAutoKey" parameterType="StudentEntity">
<selectKey keyProperty="studentID" resultType="String" order="BEFORE">
select nextval('student')
</selectKey>
INSERT INTO STUDENT_TBL (STUDENT_ID,
STUDENT_NAME,
STUDENT_SEX,
STUDENT_BIRTHDAY,
CLASS_ID)
VALUES (#{studentID},
#{studentName},
#{studentSex},
#{studentBirthday},
#{classEntity.classID})
</insert>
其中 #{userName}代表实体类中的属性名。
【增加语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句
useGeneratedKeys:告诉MyBatis 使用JDBC 的getGeneratedKeys 方法来获取数据库自己生成的主键(MySQL、SQLSERVER 等关系型数据库会有自动生成的字段)。默认:false
keyProperty:标识一个将要被MyBatis设置进getGeneratedKeys的key 所返回的值,或者为insert 语句使用一个selectKey子元素。
【批量插入】
方法一:
<insert id="add" parameterType="EStudent">
<foreach collection="list" item="item" index="index" separator=";">
INSERT INTO TStudent(name,age) VALUES(#{item.name}, #{item.age})
</foreach>
</insert>
上述方式相当语句逐条INSERT语句执行,将出现如下问题:
1. mapper接口的add方法返回值将是最后一条INSERT语句的操作成功的记录数目(就是0或1),而不是所有INSERT语句的操作成功的总记录数目
2. 当其中一条不成功时,不会进行整体回滚。
方法二:
<insert id="insertStudentAutoKey" parameterType="java.util.List">
INSERT INTO STUDENT_TBL (STUDENT_NAME,
STUDENT_SEX,
STUDENT_BIRTHDAY,
CLASS_ID)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
( #{item.studentName},#{item.studentSex},#{item.studentBirthday},#{item.classEntity.classID})
</foreach>
</insert>
3、更新数据,示例如下:
<update id="updateStudent" parameterType="StudentEntity">
UPDATE STUDENT_TBL
SET STUDENT_TBL.STUDENT_NAME = #{studentName},
STUDENT_TBL.STUDENT_SEX = #{studentSex},
STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},
STUDENT_TBL.CLASS_ID = #{classEntity.classID}
WHERE STUDENT_TBL.STUDENT_ID = #{studentID};
</update>
【更新语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句
【批量更新】
方法一:(适用于将不同的记录更新不同的值)
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update course
<set>
name=${item.name}
</set>
where id = ${item.id}
</foreach>
</update>
方法二:(适用于将不同记录的更新同样的值)
<update id="updateOrders" parameterType="java.util.List">
update orders set state = '0' where no in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
4、删除数据 示例如下:
<delete id="deleteStudent" parameterType="StudentEntity">
DELETE FROM STUDENT_TBL WHERE STUDENT_ID = #{studentID}
</delete>
【批量删除】
<delete id="batchRemoveUserByPks" parameterType="java.util.List">
DELETE FROM LD_USER WHERE ID in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
5、Sql元素
Sql元素用来定义一个可以复用的SQL 语句段,供其它语句调用。比如:
<!-- 复用sql语句 查询student表所有字段 -->
<sql id="selectStudentAll">
SELECT ST.STUDENT_ID,
ST.STUDENT_NAME,
ST.STUDENT_SEX,
ST.STUDENT_BIRTHDAY,
ST.CLASS_ID
FROM STUDENT_TBL ST
</sql>
<!-- 查询学生,根据id -->
<select id="getStudent" parameterType="String" resultMap="studentResultMap">
<include refid="selectStudentAll"/>
WHERE ST.STUDENT_ID = #{studentID}
</select>
6、parameters使用
MyBatis可以使用Java的基本数据类型和Java的复杂数据类型。如:基本数据类型,String,int,date等。
但是使用基本数据类型,只能提供一个参数,所以需要使用Java实体类,或Map类型做参数类型。通过#{}可以直接得到其属性。
【基本类型参数】示例如下:
<select id="getStudentListByDate" parameterType="Date" resultMap="studentResultMap">
SELECT *
FROM STUDENT_TBL ST LEFT JOIN CLASS_TBL CT ON ST.CLASS_ID = CT.CLASS_ID
WHERE CT.CLASS_YEAR = #{classYear};
</select>
【Java实体类型参数】 示例如下:
<select id="getStudentListWhereEntity" parameterType="StudentEntity" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
WHERE ST.STUDENT_NAME LIKE CONCAT('%', #{studentName},'%')
AND ST.STUDENT_SEX = #{studentSex}
</select>
【Map参数】
<select id="getStudentListWhereMap" parameterType="Map" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
WHERE ST.STUDENT_SEX = #{sex}
AND ST.STUDENT_name = #{name}
</select>
【多参数实现】
如果想传入多个参数,则需要在接口的参数上添加@Param注解。给出一个实例:
public List<StudentEntity> getStudentListWhereParam(@Param(value = "name") String name, @Param(value = "sex") String sex, @Param(value = "birthday") Date birthdar, @Param(value = "classEntity") ClassEntity classEntity);
应用如下:
<select id="getStudentListWhereParam" resultMap="studentResultMap">
SELECT * from STUDENT_TBL ST
<where>
<if test="name!=null and name!='' ">
ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="sex!= null and sex!= '' ">
AND ST.STUDENT_SEX = #{sex}
</if>
<if test="birthday!=null">
AND ST.STUDENT_BIRTHDAY = #{birthday}
</if>
<if test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' ">
AND ST.CLASS_ID = #{classEntity.classID}
</if>
</where>
</select>
7、#{}与${}的区别
默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义。
示例1:
执行SQL:Select * from emp where name = #{employeeName}
参数:employeeName=>Smith
解析后执行的SQL:Select * from emp where name = ?
执行SQL:Select * from emp where name = ${employeeName}
参数:employeeName传入值为:Smith
解析后执行的SQL:Select * from emp where name =Smith
说明:
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #{user_id},如果传入的值是111,那么解析成sql时的值为order by “111”,
如果传入的值是id,则解析成的sql为order by “id”.
2. $将传入的数据直接显示生成在sql中。如:order by ${user_id},如果传入的值是111,那么解析成sql时的值为order by 111, 如果传入的值是id,则解析成的sql为order by id.
综上所述,${}方式会引发SQL注入的问题、同时也会影响SQL语句的预编译,所以从安全性和性能的角度出发,能使用#{}的情况下就不要使用${}。
${}在什么情况下使用呢?
有时候可能需要直接插入一个不做任何修改的字符串到SQL语句中。这时候应该使用${}语法。
比如,动态SQL中的字段名,如:ORDER BY ${columnName}
<select id="queryMetaList" resultType="Map" statementType="STATEMENT">
Select * from emp where name = ${employeeName} ORDER BY ${columnName}
</select>
由于${}仅仅是简单的取值,所以以前sql注入的方法适用此处,如果我们order by语句后用了${},那么不做任何处理的时候是存在sql注入危险的。
8、Mybatis调用存储过程 xml示例代码如下:
--------------------------------------------存储过程基本调用-------------------------------------------------------------
create procedure sptest.adder(in addend1 integer, in addend2 integer, out theSum integer)
begin atomic
set theSum = addend1 + addend2;
end
go
<parameterMap type="map" id="testParameterMap">
<parameter property="addend1" jdbcType="INTEGER" mode="IN"/>
<parameter property="addend2" jdbcType="INTEGER" mode="IN"/>
<parameter property="sum" jdbcType="INTEGER" mode="OUT"/>
</parameterMap>
<update id="adderWithParameterMap" parameterMap="testParameterMap" statementType="CALLABLE">
{call sptest.adder(?, ?, ?)}
</update>
JAVA调用
public void testAdderAsUpdateWithParameterMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("addend1", 3);
parms.put("addend2", 4);
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
spMapper.adderWithParameterMap(parms);
assertEquals(7, parms.get("sum"));
} finally {
sqlSession.close();
}
}
----------------------------------------带输入输出参数的存储过程------------------------------------------------------------------------------
create procedure sptest.getnames(in lowestId int, out totalrows integer)
BEGIN ATOMIC
declare cur cursor for select * from sptest.names where id >= lowestId;
select count(*) into totalrows from sptest.names where id >= lowestId;
open cur;
END
go
<select id="getNames" parameterType="java.util.Map" statementType="CALLABLE" resultMap="nameResult">
{call sptest.getnames(
#{lowestId,jdbcType=INTEGER,mode=IN},
#{totalRows,jdbcType=INTEGER,mode=OUT})}
</select>
JAVA调用
public void testCallWithResultSet2_a1() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("lowestId", 1);
List<Name> names = spMapper.getNamesAnnotated(parms);
assertEquals(3, names.size());
assertEquals(3, parms.get("totalRows"));
} finally {
sqlSession.close();
}
}
---------------------------------------返回多个结果集------------------------------------------------------
create procedure sptest.getnamesanditems()
reads sql data
dynamic result sets 2
BEGIN ATOMIC
declare cur1 cursor for select * from sptest.names;
declare cur2 cursor for select * from sptest.items;
open cur1;
open cur2;
END
go
<resultMap type="org.apache.ibatis.submitted.sptests.Name" id="nameResult">
<result column="ID" property="id"/>
<result column="FIRST_NAME" property="firstName"/>
<result column="LAST_NAME" property="lastName"/>
</resultMap>
<resultMap type="org.apache.ibatis.submitted.sptests.Item" id="itemResult">
<result column="ID" property="id"/>
<result column="ITEM" property="item"/>
</resultMap>
<select id="getNamesAndItems" statementType="CALLABLE"
resultMap="nameResult,itemResult">
{call sptest.getnamesanditems()}
</select>
JAVA调用
public void testGetNamesAndItems() throws SQLException {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
List<List<?>> results = spMapper.getNamesAndItems();
assertEquals(2, results.size());
assertEquals(4, results.get(0).size());
assertEquals(3, results.get(1).size());
} finally {
sqlSession.close();
}
}