【大家好,我是爱干饭的猿,本文重点介绍ORM 框架和Mybatis的关系、通过注解 或者 通过XML配置文件的使用Mybatis,以及参数占位符 #{} 和 ${} 的区别, 什么是sql 注入。
后续会继续分享其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】
上一篇文章:《【SSM】Spring AOP 统一问题处理(重点:Spring AOP 实现原理)》
🎁1.MyBatis 是什么?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获 取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库工具。
🎁2. 什么是ORM框架?
ORM 把数据库映射为对象:
-
数据库表(table)–> 类(class) -
记录(record,行数据)–> 对象(object) -
字段(field) –> 对象的属性(attribute)
一般的 ORM 框架,会将数据库模型的每张表都映射为一个 Java 类。 也就是说使用 MyBatis 可以像操作对象一样来操作数据库中的表,可以实现对象和数据库表之间的转换。
MyBatis 也是一个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语言中,将关系型数据库中的数据 与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
-
将输入数据(即传入对象)+SQL 映射成原生 SQL
-
将结果集映射为返回对象,即输出对象
一些其他框架:
-
Hibernate框架:偏向简化SQL的模式 -
MyBatis框架:偏向ORM的模式 -
Spring 内部提供的JdbcTemplate:偏向简化SQL的模式 -
JPA :完全倒向了ORM的形式,建表的过程都被抽象,我们看到的只有类(我写了类,框架根据类建表)
🎁3. MyBatis 的使用
3.1 添加MyBatis框架支持
1. 新项目添加MyBatis框架
2. 旧项目添加MyBatis框架
a. 使用 EditStarters插件
b. 手动添加
<!-- 把 DataSource对象注册到Spring 中-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<!-- 添加 mybatis 框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- 添加 MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
3.2 配置连接字符串和MyBatis
此步骤需要进行两项设置,数据库连接字符串设置和 MyBatis 的 XML 文件配置。
1. 配置连接字符串
如果是 application.yml 添加如下内容:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/...?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
2. 配置 MyBatis 中的 XML 路径
通过XML配置文件的形式使用Mybatis 时需要配置,通过注解使用Mybatis时,不需要配置
mybatis:
mapper-locations: classpath:mapper/**.xml
3.3 通过注解使用Mybatis
定义Mapper 接口
@Repository // 消除报错
@Mapper // Mapper 注解
public interface UserMapper {
}
1. 查询
// 1. 查询
// 1.1 通过uid 查询得到Map对象
@Select("select uid, username, password from users where uid = #{uid}")
Map<String, Object> select1(@Param("uid") int uid);
// 1.2 通过uid 查询得到User类对象
@Select("select uid, username, password from users where uid = #{uid}")
UserDO select2(@Param("uid") int uid);
### 2. 插入
// 2. 插入
// 2.1 插入,返回插入成功的条数
@Insert("insert into users (username, password) values (#{username}, #{password})")
int insert1(UserDO userDO);
// 2.2 由于用不到这个返回值,所以写成 void 更常见
@Insert("insert into users (username, password) values (#{username}, #{password})")
void insert2(UserDO userDO);
// 2.3 插入后拿到自增id
// 通过 @Options 注解,添加一些配置,得到自增主键,设置成 uid
// keyProperty : 对象的属性名是 uid
// keyColumn : 表的字段名的 uid
@Insert("insert into users (username, password) values (#{username}, #{password})")
@Options(useGeneratedKeys = true, keyProperty = "uid", keyColumn = "uid")
void insert3(UserDO userDO);
3. 修改
// 3. 修改
@Update("update users set username = #{username}, password = #{password} where uid = #{uid}")
int update(UserDO userDO);
4. 删除
// 4. 删除
@Delete("delete from users where uid = #{uid}")
int delete(@Param("uid") int uid);
5. 总览(增删查改)
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.Map;
@Repository // 消除报错
@Mapper // Mapper 注解
public interface UserMapper {
// 1. 查询
// 1.1 通过uid 查询得到Map对象
@Select("select uid, username, password from users where uid = #{uid}")
Map<String, Object> select1(@Param("uid") int uid);
// 1.2 通过uid 查询得到User类对象
@Select("select uid, username, password from users where uid = #{uid}")
UserDO select2(@Param("uid") int uid);
// 2. 插入
// 2.1 插入,返回插入成功的条数
@Insert("insert into users (username, password) values (#{username}, #{password})")
int insert1(UserDO userDO);
// 2.2 由于用不到这个返回值,所以写成 void 更常见
@Insert("insert into users (username, password) values (#{username}, #{password})")
void insert2(UserDO userDO);
// 2.3 插入后拿到自增id
// 通过 @Options 注解,添加一些配置,得到自增主键,设置成 uid
// keyProperty : 对象的属性名是 uid
// keyColumn : 表的字段名的 uid
@Insert("insert into users (username, password) values (#{username}, #{password})")
@Options(useGeneratedKeys = true, keyProperty = "uid", keyColumn = "uid")
void insert3(UserDO userDO);
// 3. 修改
@Update("update users set username = #{username}, password = #{password} where uid = #{uid}")
int update(UserDO userDO);
// 4. 删除
@Delete("delete from users where uid = #{uid}")
int delete(@Param("uid") int uid);
}
3.4 通过XML配置文件的形式使用Mybatis
先配置 MyBatis 中的 XML 路径,然后在mapper下 .xml 文件中写
定义Mapper 接口:
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface UserMapper {
// 1. 查询
// 1.1 单个查询
User selectOneByUid(@Param("uid") int uid);
// 1.2 多个查询
List<User> selectListByUidList(@Param("uidList") List<Integer> uidList);
// 1.3 动态查询
User selectByUser(@Param("user") User user);
// 2. 插入
// 2.1 单个插入
int insertOneUser(@Param("user") User user);
// 2.1 批量插入
int insertBatch(@Param("userList") List<User> userList);
// 3. 修改
void update(int uid , String username);
// 4. 删除
void delete(int uid);
}
0. 关于resultMap
使用场景:
-
字段名称和程序中的属性名不同的情况,可使用 resultMap 配置映射; -
一对一和一对多关系可以使用 resultMap 映射并查询数据。
<!-- 返回字典映射-->
<resultMap id="xxx" type="com.haomin.mybatis_xml.User">
<id property="uid" javaType="Integer" column="uid" jdbcType="INTEGER" />
<result property="username" javaType="String" column="username" jdbcType="VARCHAR" />
<result property="password" column="password" />
</resultMap>
编辑
1. 查询
<!-- 1.1 单个查询 -->
<select id="selectOneByUid" resultType="com.haomin.mybatis_xml.User" parameterType="int">
select uid, username, password from users where uid = #{uid}
</select>
<!-- 1.2 多个查询 -->
<select id="selectListByUidList" resultMap="xxx" parameterType="List">
select uid, username, password from users where uid in (
<foreach collection="uidList" item="id" separator=", ">
#{id}
</foreach>
) order by uid
</select>
<!-- 1.3 动态查询-->
<select id="selectByUser" resultMap="xxx" parameterType="com.haomin.mybatis_xml.User">
select uid, username, password from users where
<if test="user.uid != null">
uid = #{user.uid}
</if>
<if test="user.username != null">
and username = #{user.username}
</if>
<if test="user.password != null">
and password = #{user.password}
</if>
</select>
2. 插入
<!-- 2.1 单个插入-->
<insert id="insertOneUser" useGeneratedKeys="true" keyProperty="uid" keyColumn="uid">
insert into users (username, password) values
(#{user.username}, #{user.password})
</insert>
<!-- 2.2 批量插入-->
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="uid" keyColumn="uid">
insert into users (username, password) values
<foreach collection="userList" item="user" separator=", ">
(#{user.username}, #{user.password})
</foreach>
</insert>
3. 修改
<!-- 3. 修改-->
<update id="update">
update users set username = #{username} where uid = #{uid}
</update>
4. 删除
<!-- 4. 删除-->
<delete id="delete">
delete from users where uid = #{uid}
</delete>
5. 总览(增删查改)
<?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.haomin.mybatis_xml.UserMapper">
<!-- 返回字典映射-->
<resultMap id="xxx" type="com.haomin.mybatis_xml.User">
<id property="uid" javaType="Integer" column="uid" jdbcType="INTEGER" />
<result property="username" javaType="String" column="username" jdbcType="VARCHAR" />
<result property="password" column="password" />
</resultMap>
<!-- 1.1 单个查询 -->
<select id="selectOneByUid" resultType="com.haomin.mybatis_xml.User" parameterType="int">
select uid, username, password from users where uid = #{uid}
</select>
<!-- 1.2 多个查询 -->
<select id="selectListByUidList" resultMap="xxx" parameterType="List">
select uid, username, password from users where uid in (
<foreach collection="uidList" item="id" separator=", ">
#{id}
</foreach>
) order by uid
</select>
<!-- 1.3 动态查询-->
<select id="selectByUser" resultMap="xxx" parameterType="com.haomin.mybatis_xml.User">
select uid, username, password from users where
<if test="user.uid != null">
uid = #{user.uid}
</if>
<if test="user.username != null">
and username = #{user.username}
</if>
<if test="user.password != null">
and password = #{user.password}
</if>
</select>
<!-- 2.1 单个插入-->
<insert id="insertOneUser" useGeneratedKeys="true" keyProperty="uid" keyColumn="uid">
insert into users (username, password) values
(#{user.username}, #{user.password})
</insert>
<!-- 2.2 批量插入-->
<insert id="insertBatch" useGeneratedKeys="true" keyProperty="uid" keyColumn="uid">
insert into users (username, password) values
<foreach collection="userList" item="user" separator=", ">
(#{user.username}, #{user.password})
</foreach>
</insert>
<!-- 3. 修改-->
<update id="update">
update users set username = #{username} where uid = #{uid}
</update>
<!-- 4. 删除-->
<delete id="delete">
delete from users where uid = #{uid}
</delete>
</mapper>
当然还有更多用法:可以参考 Mybatis 官方文档
3.5 参数占位符 #{} 和 ${} 和 sql 注入
-
#{}:预编译处理。
-
${}:字符直接替换。
预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的 set 方法来赋值,编译后会带上 ‘ ’。
直接替换:是 MyBatis 在处理 {} 替换成变量的值。
结论:
-
用于查询的字段,尽量使用 #{} 预查询的方式,如果用${} 可能会出现sql注入问题。 -
使用 ${sort} 可以实现排序查询或者分页,而使用 #{sort} 就不能实现排序查询了,因为当使用 #{sort} 查询时,如果传递的值为 String 则会加单引号,就会导致 sql 错误。 sql 注入代码例子:
执行:
select * from userinfo where username = '${name}' and password = '${pwd}'
当sql 为 : ‘ or 1=1 时
执行语句:
select * from users where username = ' or 1=1 and password = ' or 1=1;
当然,Mybatis 还有更多用法:可以参考
分享到此,感谢大家观看!!!
如果你喜欢这篇文章,请点赞加关注吧,或者如果你对文章有什么困惑,可以私信我。
🏓🏓🏓
原文始发于微信公众号(爱干饭的猿):【SSM】MyBatis 操作数据库(重点:Mybatis两种使用方式)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/45797.html