直接在外层嵌套 这个标签,例如
= ]]>
标签说明:
CDATA
(Character Data)标签,它在 XML 和 HTML 中用于定义一段文本数据,该数据不应被解析器解析为标记。CDATA 部分中的内容将原样输出,即其中的所有字符都将被视为普通文本,即使它们可能包含特殊字符或标记。
sql 举例如下:
select
*
from
user
where
age = ]]> 18
符号替换,如下面表格所示
原符号 | 替换符号 |
---|---|
< | < |
<= | <= |
> | > |
>= | >= |
& | & |
’ | &apos |
" | " |
符号区分:
<
– 其中 l 代表 less,t 代表 than,合起来是 less than
>
– 其中 g 代表 greater,t 代表 than,合起来是 greater than
sql 举例如下:
select
*
from
user
where
age >= 18
SQL 映射文件有以下几个顶级元素(按照它们应该被定义的顺序):
cache
– 给定命名空间的缓存配置cache-ref
– 其他命名空间缓存配置的引用resultMap
– 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象sql
– 可被其他语句引用的可重用语句块insert
– 映射插入语句update
– 映射更新语句delete
– 映射删除语句select
– 映射查询语句有两种形式:
${}
– 字符串替换#{}
– 预编译处理区别:
#{}
是预编译处理,像传进来的数据会加个 ''
(#
将传入的数据都当成一个字符串,会对自动传入的数据加一个单引号)
?
)位置上,而不是直接将参数值拼接到SQL语句中${}
就是字符串替换。直接替换掉占位符。$
方式一般用于传入数据库对象,例如传入表名。使用 ${}
的话会导致 sq| 注入什么是 SQL 注入呢?
比如:
select * from user where id = ${value}
value 应该是一个数值吧。然后如果对方传过来的是 001 and name= tom
。这样不就相当于多加了一个条件嘛?
把 SQL 语句直接写进来了。如果是攻击性的语句呢?001;drop table user
,直接把表给删了。
建议
所以为了防止 SQL 注入,能用 #{}
的不要去用 ${}
如果非要用 ${}
的话,那要注意防止 SQL 注入问题,可以手动判定传入的变量,进行过滤,一般 SQL 注入会输入很长的一条 SQL 语句。
只能使用 ${}
,因为表名不能加单引号
例如:
<select id="getUserByTable" resultType="User">
select * from t_info_${tableName}
select>
在 MyBatis 中,当你插入一条新记录并希望获取这条新记录的主键 ID 时,你可以使用数据库提供的自动生成主键的机制(例如自增字段),也可以通过 MyBatis 提供的一些特性来获取主键值。
以下是一些常见的方法来获取新增记录的主键 ID:
这是最常见的方法。许多数据库系统(如 MySQL、PostgreSQL、SQL Server 等)都支持自动生成主键。在你的数据库表中,你可以设置一个字段为自增(例如,在 MySQL 中使用 AUTO_INCREMENT
属性),这样每次插入新记录时,数据库会自动为这个字段生成一个新的值。
你的表结构可能如下所示:
CREATE TABLE your_table (
id INT NOT NULL AUTO_INCREMENT,
other_column VARCHAR(255),
PRIMARY KEY (id)
);
在你的 MyBatis 映射文件中,你可以这样写:
<insert id="insertUser" parameterType="User">
INSERT INTO your_table (other_column) VALUES (#{otherColumn})
insert>
然后,在你的 Java 代码中,你可以在插入记录后从数据库获取主键 ID:
在调用插入方法时,会自动将生成的主键 ID 设置到实体对象中,因此可以直接通过实体对象获取主键 ID。
User user = new User();
user.setOtherColumn("some value");
// sqlSession.insert("insertUser", user);
// sqlSession.insert("com.xxx.project.mapper.XxxMapper.insertUser", user);
userMapper.insertUser(user);
// 获取数据库自动生成的主键 ID
Long id = user.getId();
useGeneratedKeys
属性如果你的数据库支持返回生成的主键,你可以在 MyBatis 映射文件中设置 useGeneratedKeys="true"
,这样 MyBatis 会在执行插入操作后返回生成的主键。
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO your_table (other_column) VALUES (#{otherColumn})
insert>
# <insert id="insertEntity" parameterType="YourEntityClass" useGeneratedKeys="true" keyProperty="id">
# INSERT INTO your_table (column1, column2, ...)
# VALUES (#{property1}, #{property2}, ...)
# insert>
在这个例子中,keyProperty
属性指定了要将生成的主键值设置到哪个属性上。
useGeneratedKeys="true"
:表示使用数据库自动生成的主键。keyProperty="id"
:表示将自动生成的主键值设置到实体类的指定属性中。在你的 Java 代码中,你可以直接获取这个属性的值:
User user = new User();
user.setOtherColumn("some value");
// sqlSession.insert("insertUser", user);
// sqlSession.insert("com.xxx.project.mapper.XxxMapper.insertUser", user);
userMapper.insertUser(user);
// 现在 user 对象的 id 属性已经被设置为新生成的主键值
Long id = user.getId();
@SelectKey
注解如果你使用的是 MyBatis 注解而不是映射文件,你可以使用 @SelectKey
注解来获取生成的主键。
public interface UserMapper {
@Insert("INSERT INTO your_table (other_column) VALUES (#{otherColumn})")
@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", before = false)
int insertUser(User user);
}
在这个例子中,
@SelectKey
注解指定了一个 SQL 语句 SELECT LAST_INSERT_ID()
来获取最后插入记录的 ID。keyProperty
属性指定了要将这个值设置到哪个属性上。before
属性指定了生成的主键是在执行插入操作之前还是之后被选择的。User user = new User();
user.setOtherColumn("some value");
// sqlSession.insert("insertUser", user);
// sqlSession.insert("com.xxx.project.mapper.XxxMapper.insertUser", user);
userMapper.insertUser(user);
// 现在 user 对象的 id 属性已经被设置为新生成的主键值
Long id = user.getId();
1、Mapper 接口
/**
* 根据用户id查询用户信息为map集合
* @param id
* @return
*/
Map<String, Object> getUserToMap(@Param("id") int id);
2、对应的映射文件
<select id="getUserToMap" resultType="map">
select * from t_user where id = #{id}
select>
1、Mapper 接口
/**
* 查询所有用户信息为map集合
*
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,
* 此时可以将这些map放在一个list集合中获取
*
* @return
*/
List<Map<String, Object>> getAllUserToMap();
2、对应的映射文件
<select id="getAllUserToMap" resultType="map">
select * from t_user
select>
1、Mapper 接口(用 @MapKey
注解)
/**
* 查询所有用户信息为map集合
*
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并且最终要以一个map的方式返回数据,
* 此时需要通过 @MapKey 注解设置 map 集合的键,值是每条数据所对应的 map 集合
*
* @return
*/
@MapKey("id")
Map<String, Object> getAllUserToMap();
2、对应的映射文件
<select id="getAllUserToMap" resultType="map">
select * from t_user
select>
MyBatis 动态 SQL 提供了多种标签,用于在运行时动态构建 SQL 语句,极大地提高了 SQL 语句的灵活性和可重用性。
以下是几个关键动态 SQL 标签及其用法的总结:
含义
用于根据表达式的值来决定是否包含某段 SQL 语句。
用法
<if test="condition">
SQL 片段
if>
解释
if
标签可通过 test
属性(即传递过来的数据)的表达式进行判断
含义
类似于 Java 中的 switch-case
结构,根据多个条件分支执行不同 SQL 片段。
用法
<choose>
<when test="condition1">SQL片段1when>
<when test="condition2">SQL片段2when>
<otherwise>默认SQL片段(当所有when都不满足时执行)otherwise>
choose>
含义
用于动态地添加 WHERE 子句,避免不必要的 AND
或 OR
关键词出现在 SQL 语句中。
用法
包裹多条可能的条件语句,MyBatis 会智能地忽略那些条件未满足(表达式结果为假)时产生的 AND
或 OR
关键词。
where 和 if 一般结合使用
若 where 标签中的 if 条件都不满足,则 where 标签没有任何功能,即不会添加 where 关键字
若 where 标签中的 if 条件满足,则 where 标签会自动添加 where 关键字,并将条件【最前方】多余的 and/or 去掉
注意:where 标签不能去掉【条件后】多余的
and/or
示例
<select id="getEmpByCondition" resultType="Emp">
select * from t_emp
<where>
<if test="empName != null and empName !=''">
emp_name = #{empName}
if>
<if test="age != null and age !=''">
and age = #{age}
if>
<if test="sex != null and sex !=''">
and sex = #{sex}
if>
<if test="email != null and email !=''">
and email = #{email}
if>
where>
select>
含义
动态地添加 UPDATE 语句的 SET 部分,同样可以避免不必要的逗号问题。
用法
在 UPDATE 语句中,根据条件决定哪些列需要更新。(搭配 trim
标签使用。)
示例
<update id="updateUserInfo">
UPDATE
t_user
<set>
<if test="dto.gender != null">
gender = #{dto.gender},
if>
<if test="dto.birthday != null">
birthday = #{dto.birthday},
if>
set>
WHERE
user_id = #{userId}
update>
解释
在更新数据的时候,使用
标签,使用了 set 标签会自动帮你删除尾部的逗号。
含义
用来【删除】SQL 片段首尾的特定字符或关键字,也可以在首尾【添加】字符或关键字。
常用属性
prefix
:在 trim 标签中的内容的前面【添加】某些内容suffix
:在 trim 标签中的内容的后面【添加】某些内容prefixOverrides
:在 trim 标签中的内容的前面【去掉】某些内容suffixOverrides
:在 trim 标签中的内容的后面【去掉】某些内容(suffixOverrides="and|or"
)用法
<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
column1,
column2
trim>
<update id="updateUserInfo">
UPDATE
t_user
<set>
<if test="dto.gender != null">
gender = #{dto.gender},
if>
<if test="dto.birthday != null">
birthday = #{dto.birthday}
if>
<trim suffixOverrides=","/>
set>
WHERE
user_id = #{userId}
update>
<trim prefix="SET" suffixOverrides=",">
...
trim>
含义
遍历集合,适用于 in 语句或者批量插入等场景。
用法
<insert id="batchInsert">
INSERT INTO tbl_user (id,name,age,sex,is_delete)
VALUES
<foreach collection="userList" item="item" index="index" open="(" separator="),(" close=")">
#{item.id},#{item.name},#{item.age},#{item.sex},#{item.isDelete}
foreach>
insert>
上述示例为批量插入语句,会遍历名为 userList
的集合,依次将每个元素 item 插入 SQL 语句中,每一条数据用 "),("
分隔。
include 标签
进行引入
标签<sql id="empColumns">eid,emp_name,age,sex,emailsql>
标签
<select id="getEmpByCondition" resultType="Emp">
select <include refid="empColumns">include> from t_emp
select>
&{}
这种方式,简单,但是无法防止 SQL 注入,所以不推荐使用
<if test="dto.name != null">
AND name LIKE '%${dto.name}%'
if>
在 #{}
左右两边写上字符串 "%"
<if test="dto.name != null">
AND name LIKE "%" #{dto.name} "%"
if>
用 concat()
函数
<if test="dto.name != null">
AND name LIKE concat('%', #{dto.name}, '%')
if>
<select id="searchstudents" resultType="com.example.entity.studentEntity"
parameterType="com.example.entity.studentEntity">
<bind name="pattern1" value="'%' + parameter.name + '%'" />
<bind name="pattern2" value="'%' + parameter.address + '%'" />
SELECT * FROM test student
<where>
<if test="name != null and name != ''">
name LIKE #{pattern1}
if>
<if test="address != null and address != ''">
AND address LIKE #{pattern2}
if>
where>
ORDER BY id
select>
1、直接在 java 代码里写,在值的两边加上 %
dto.setName("%张三%");
2、然后,在映射文件中直接传参就行
<if test="dto.name != null">
AND name LIKE #{dto.name}
if>
标签property
: 指定父对象中的属性名,该属性应该是一个集合类型,如 List 或 Set。ofType
: 指定集合中元素的类型。select
: 指定一个 MyBatis 查询,该查询返回集合中的元素。column
: 用于传递参数给
查询的参数名称。(例如:column="objId=id"
,id
是父对象的元素,objId
是查询参数 #{objId}
)
- 延迟加载:
标签通常用于延迟加载关联集合。
- 关联查询: 通过
标签,MyBatis 可以处理关联查询,将多个表的结果集映射到一个对象的属性中。
- 参数传递:
column
属性用于将查询参数传递给关联查询。
<resultMap id="dVO" type="com.chenmeng.project.vo.MaintainerVO">
<collection property="documentInfoVoS"
ofType="com.chenmeng.project.vo.DocumentInfoVO" select="getDocumentInfo"
column="objId=id">
collection>
resultMap>
<select id="getDocumentInfo" resultType="com.chenmeng.project.vo.DocumentInfoVO">
select info.certificate_name name,
expire_date expire,
file.file_path image
from t_test_document_info info
left join t_test_file file on file.obj_id = info.id
and file.is_deleted = 0
where info.obj_id = #{objId}
and info.is_deleted = 0
select>
<select id="queryByCreateUser" resultMap="dVO">
SELECT mn.id, mn.name
en.enterprise_name,
en.field_type
FROM t_test_enterprise en,
t_test_maintainer mn
WHERE mn.is_deleted = 0
and en.id = mn.enterprise_id
and en.is_deleted = 0
and mn.create_user = #{userId}
select>
/**
* 人员信息视图
*/
@Data
public class MaintainerVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "维保人id")
private Long id;
@ApiModelProperty(value = "维保人姓名")
private String name;
@ApiModelProperty(value = "证件信息")
private List<DocumentInfoVO> documentInfoVoS;
}
/**
* 证件信息视图
*/
@Data
public class DocumentInfoVO implements Serializable {
private Long id;
private String name;
private String expire;
private String image;
}
queryByCreateUser
对应的 mapper 接口,最终返回 MaintainerVO
对象类型
标签会延迟加载关联集合,自动查询 documentInfoVoS
属性的元素并加载。
标签判断条件等于字符串的值写法示例
# ...
<if test="req.yearCheckCount != null and req.yearCheckCount != ''">
<choose>
<when test="req.yearCheckCount == '0'.toString()">
and t2.year_check_count is null
when>
<when test="req.yearCheckCount == '1'.toString() or req.yearCheckCount == '2'.toString()">
and t2.year_check_count = #{req.yearCheckCount}
when>
<otherwise>
and t2.year_check_count >= 3
otherwise>
choose>
if>
# ...
mybatis中大于等于小于等于的写法_mybatis大于小于-CSDN博客
归档 - MyBatis 教程 (javaboy.org)
MyBatis 中#{}和${}区别_w3cschool
Mybatis最全笔记知识点 - 知乎 (zhihu.com)
MyBatis 判断条件为不等于的问题(<if test=“变量!= ‘1‘.toString()“> xxx </if>_在mybatis中test不等于某个值-CSDN博客