软件设计之SSM(7)
路线图推荐:
【Java学习路线-极速版】【Java架构师技术图谱】
尚硅谷新版SSM框架全套视频教程,Spring6+SpringBoot3最新SSM企业级开发
资料可以去尚硅谷官网免费领取
学习内容:
Mybatis
- Mybatis快速入门
- 动态代理如何找到对应的 SQL 语句
- SQL语句传参
- 数据输入
1、Mybatis快速入门
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 框架下,SQL语句编写位置发生改变,从原来的Java类,改成XML或者注解定义
- Mybatis 中的
Mapper 接口
相当于以前的 Dao。但是区别在于,Mapper 仅仅只是建接口即可,我们不需要提供实现类
,具体的SQL写到对应的Mapper文件
Mapper.xml讲解
namespace
填写对应XxxMapper接口- 声明标签写sql语句,比如select、delete、insert、update
- 方法名和SQL的id一致(
方法不可重载
) - 方法返回值和resultType一致(方法指的是接口中声明的抽象方法)
- 方法的参数和SQL的参数一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.atguigu.mapper.EmployeeMapper">
<!-- 查询使用 select标签
id = 方法名
resultType = 返回值类型
标签内编写SQL语句
-->
<select id="selectEmployee" resultType="com.atguigu.pojo.Employee">
<!-- #{empId}代表动态传入的参数,并且进行赋值!后面详细讲解 -->
select emp_id empId,emp_name empName, emp_salary empSalary from
t_emp where emp_id = #{empId}
</select>
</mapper>
mybatis-config.xml(MyBatis配置文件)
mybatis框架配置文件: 数据库连接信息
,性能配置
,mapper.xml配置
等
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
<environments default="development">
<!-- environment表示配置Mybatis的一个具体的环境 -->
<environment id="development">
<!-- Mybatis的内置的事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 建立数据库连接的具体信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource="mappers/EmployeeMapper.xml"/>
</mappers>
</configuration>
实现MyBatis调用数据库
- 加载 MyBatis 配置文件
- 获取 SqlSession 对象
- 获取 Mapper 接口
- 执行数据库操作
- 关闭 SqlSession
public class MyBatisTest {
@Test
public void testSelectEmployee() throws IOException {
// 1.创建SqlSessionFactory对象
// ①声明Mybatis全局配置文件的路径
String mybatisConfigFilePath = "mybatis-config.xml";
// ②以输入流的形式加载Mybatis配置文件
InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);
// ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.使用SqlSessionFactory对象开启一个会话
SqlSession session = sessionFactory.openSession();
// 3.根据EmployeeMapper接口的Class对象获取Mapper接口类型的对象(动态代理技术)
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
// 4. 调用代理类方法既可以触发对应的SQL语句
Employee employee = employeeMapper.selectEmployee(1);
System.out.println("employee = " + employee);
// 4.关闭SqlSession
session.commit(); //提交事务 [DQL不需要,其他需要]
session.close(); //关闭会话
}
}
2、 动态代理如何找到对应的 SQL 语句
在 MyBatis 中,动态代理机制是核心功能之一,它通过代理对象来将接口方法调用转化为对应的 SQL 执行
获取 Mapper 接口的代理对象
当你使用 sqlSession.getMapper
(UserMapper.class) 方法时,MyBatis 会为 UserMapper 接口创建一个动态代理对象。这个对象实现了 UserMapper 接口,负责处理对接口方法的调用。
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
拦截方法调用
当你调用代理对象的方法,比如 userMapper.selectUserById(1),代理对象会拦截这个方法调用。具体来说,代理对象会实现 InvocationHandler 接口,重写 invoke 方法。在 invoke 方法中,MyBatis 会获取到方法的签名信息
,包括:
- 方法名称:例如
selectUserById
。 - 参数类型:例如
int
类型的参数。
根据方法名称找到对应的 SQL 映射
MyBatis 使用方法名称和 Mapper 接口的全限定名去寻找对应的 SQL 语句。这一过程涉及以下几步:
-
获取接口的全限定名: 例如 com.example.UserMapper。
-
匹配 XML 文件: MyBatis 会根据接口的 namespace 属性在 Mapper.xml 文件中找到与之对应的<mapper> 标签。例如:
<mapper namespace="com.example.UserMapper">
<select id="selectUserById" parameterType="int" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
- 查找方法 ID: 接下来,MyBatis 会查找与方法名称相同的 <select>、<insert>、<update> 或 <delete> 标签的 id 属性。在这个例子中,selectUserById 就是我们需要找的 SQL 语句 ID。
获取 SQL 语句和参数
- SQL 语句获取: 找到对应的 SQL 语句后,MyBatis 会提取出 SQL 语句和任何参数类型的信息。例如,上述 SQL 语句:
SELECT * FROM users WHERE id = #{id}
- 参数绑定: MyBatis 会将接口方法的参数(在这个例子中是 1)绑定到 SQL 语句中的占位符 #{id}。这意味着在执行 SQL 时,#{id} 会被实际参数值所替代。
执行 SQL 语句
代理对象会调用 MyBatis 的 Executor 执行 SQL 语句,并传递绑定后的参数。这个过程可以用如下代码表示:
List<User> users = sqlSession.selectList("com.example.UserMapper.selectUserById", id);
结果映射
执行完 SQL 语句后,MyBatis 会将结果集映射为 Java 对象。根据 Mapper 中定义的 resultType 或 resultMap 属性,MyBatis 知道如何将结果集中的数据转换为相应的 Java 对象。
3、SQL语句传参
在 MyBatis 中,#{}
和${}
是两种不同的参数传递方式,主要用于 SQL 语句中的参数占位符。
- #{ } : 占位符 + 赋值 i = ?
->
? = 赋值,但?
只能代替值
的位置,不能替代 容器名(列名、sql关键字、标签) - ${ }: 当容器名需要为动态时,可以考虑此赋值方法
特性 | #{} | ${} |
---|---|---|
作用 | 用于参数占位符,防止 SQL 注入。 | 直接替换成参数的值。 |
传递方式 | 将参数作为 JDBC 的 PreparedStatement 处理。 | 直接拼接字符串。 |
安全性 | 安全,防止 SQL 注入攻击。 | 不安全,容易引发 SQL 注入。 |
使用场景 | 当需要传递参数并防止 SQL 注入时。 | 当需要动态生成 SQL 语句的片段时。 |
示例 | SELECT * FROM users WHERE id = #{id} | SELECT * FROM users WHERE id = ${id} |
4、数据输入
单个简单类型
单个简单类型参数,在#{}中的key
可以随意命名,但是没有必要。通常还是使用和接口方法参数同名。
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>
实体类类型
Mybatis会根据#{}
中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。 传入的key
需要是该实体类的属性名
int insertEmployee(Employee employee);
<insert id="insertEmployee">
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>
多个简单类型
- 方式1:Mapper接口中抽象方法的声明
key值
(推荐)
int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);
<update id="updateEmployee">
update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
</update>
- 方式2:mybatis默认机制
<update id="updateEmployee">
update t_emp set emp_salary=#{arg0} where emp_id=#{arg1}
</update>
<!-- 或者 -->
<update id="updateEmployee">
update t_emp set emp_salary=#{param1} where emp_id=#{param2}
</update>
Map类型
#{}
中写Map中的key
Map<K, V>
- K(Key):表示键的类型,通常是 String 类型,因为 SQL 查询结果的列名通常会被映射为字符串。
- V(Value):表示值的类型,可以是任何类型,例如 Integer、String、List、Object 等。