[!quote] ORM 框架 ORM 是对象关系映射,通过抽象数据库表为对象模型,使得开发者可以不必编写复杂的 SQL 语句,而是通过操作这些对象来间接地与数据库进行交互
[!hint] 技术选型
- 【MyBatis】 非完整的 ORM
- 优点
- 可以更细致化地定制化 SQL
- 插入,单表查询时,性能更高【
因为 MyBatis 直接操作数据库】- 更容易对 SQL 进行性能优化
- 缺点
- 需要手动编写大量 SQL
- 数据库表结构变化时,需要手动更改 SQL
- 【Hibernate】 完整的 ORM
- 优点
- 拥有全面的 ORM 功能【
你只需要创建和修改好对象,Hibernate 会自动帮你更新数据库中的数据】- 跨数据库兼容性好【
因为完整的 ORM 提供了更加高层的抽象】- 懒加载:在真正需要数据时才从数据库加载数据
- 一级,二级,查询缓存:缓存查询结果,便于后续查询可以直接获取数据
- 缺点
- 由于不可定制化,所以难以优化性能
概述
[!quote] MyBatis MyBatis 是一个 Java 持久层框架,封装了 JDBC 程序,简化了数据库的访问代码的编写,提供了灵活性和高度可定制的 SQL 映射,以及良好的性能
[!quote] JDBC JDBC 是 SUN 公司提供的一套操作关系型数据库的 API
mermaid
graph TB
a[Java程序]-->b[JDBC]
b--控制-->c[MySql实现]
b--控制-->d[Oracle实现]
b--控制-->e[SqlServer实现]
c--控制-->f[Mysql]
d--控制-->g[Oracle]
e--控制-->h[SqlServer]
subgraph 驱动
c
d
e
end数据库连接池技术
- 在没有数据库连接池技术时,Java 程序要执行一条 SQL 语句,就要创建一个数据库连接对象,在使用完成之后,再释放这个连接对象
- 而使用了数据库连接池技术后,客户端需要执行 SQL 语句时,可以去数据库连接池中拿连接对象,用完之后再还回去
mermaid
graph LR
a[客户端A]--拿Connection对象-->b[数据库连接池]
b--还回去-->a
c[客户端B]-->b
d[客户端C]-->b
b--访问-->e[数据库]
[!hint] 数据库连接池的优点
- 资源的重用【用完的 Connection 对象无需销毁,还回去即可】
- 提升系统的响应速度【无需创建 Connection 对象,去拿即可】
准备工作
- 引入 MyBatis,mysql 依赖
xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>- 在配置文件中配置 MySQL
yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接到localhost:3306服务的,security数据库
url: jdbc:mysql://localhost:3306/security?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
username: root
password: 134- 配置 SQL 提示

- 在 idea 的数据库配置中添加数据库

- 安装
MyBatisX插件:可以在 xml 文件 与 Mapper 接口 中快速跳转
通过注解来实现 MyBatis
增删改查
java
//配置实体user类
package com.example.Pojo;
@Getter //lombok中的注释
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class user {
private Integer id;
private String name;
private Integer age;
private Integer gender;
private String phone;
}java
//定义Mapper接口
package com.example.mapper;
import com.example.Pojo.user;
//表示当前类是MyBatis的Mapper接口,在运行时会自动生成该接口的实现类对象,并将该对象交给IOC容器管理
@Mapper
public interface UserMapper {
//查询
@Select("SELECT * FROM user")
public List<user> list();
//增
@Insert("INSERT INTO user VALUES(#{id},#{name},#{age},#{gender},#{phone})")
public int InsertOne(Integer id, String name, Integer age, Integer gender, String phone);
//删
@Delete("DELETE FROM user WHERE id = #{id}") //这个DELETE语句会返回删除了几条数据
public void DeleteOne(Integer id);
//改
@Update("UPDATE user SET name=#{name},age=#{age},gender=#{gender},phone=#{phone} WHERE id = #{id}")
public void UpdateOne(Integer id, String name, Integer age, Integer gender, String phone);
}java
//启动测试类
package com.example;
import com.example.Pojo.user;
import com.example.mapper.UserMapper;
@SpringBootTest
class SpringBootMyBatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void SelectUser() {
List<user> list = userMapper.list();
for (user user : list) {
System.out.println(user.toString());
}
}
@Test
public void InsertOne() {
int i = userMapper.InsertOne(6, "hoan", 30, 1, "211");
System.out.println(i); //输出影响的记录数
}
@Test
public void DeleteOne() {
userMapper.DeleteOne(6);
}
@Test
public void UpdateOne() {
userMapper.UpdateOne(1, "greenteck", 35, 1, "985985");
}
}
---
打印出所有用户数据
---
1
---
删除
---
修改[!hint]
#{}和${}
${}直接替换:将传入的参数直接嵌入到生成的 SQL 语句中,适用于动态拼接 sql 片段,而不是值
- 会被 SQL 注入
#{}预编译处理:会将传递参数替换为一个占位符,在后续执行时设置具体参数,适用于拼接参数值,而不是一大段 sql 片段
- 性能高,因为不同参数的 SQL 语句只用编译一遍【MYSQL 有缓存机制】
- 安全:防止了 SQL 注入【用户使用输入数据来篡改 SQL 语句】
#{}不能放在单引号或多引号之间使用,如果一定要在引号里进行占位符,可以使用CONCAT 函数
主键返回
在很多时候我们会在插入一条数据之后,再拿到这条数据的 id。由于不能简单的通过 getId 来获取,所以我们要添加 Options 注释
useGeneratedKeys = true表示我们要拿到生成的主键值keyProperty = "id"表示将自动生成的主键值映射到user对象的id属性
java
@Options(useGeneratedKeys = true, keyProperty = "id") //需要添加这条注释
@Insert("INSERT INTO user(name,age,gender,phone) VALUES(#{name},#{age},#{gender},#{phone})")
public void InsertOne(user user);java
package com.example;
import com.example.Pojo.user;
import com.example.mapper.UserMapper;
@SpringBootTest
class SpringBootMyBatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void InsertOne() {
user user = new user();
user.setName("chico"); //有主键自增,所以不用插入id
user.setAge(47);
user.setGender(1);
user.setPhone("9898989");
userMapper.InsertOne(user);
System.out.println(user.getId());
}
}
---
17通过 XML 来实现 MyBatis
[!hint] 三大规范
- 同包同名,一一对应:XML 文件的名称与 Mapper 接口的名称保持一致,一个 XML 文件对应一个 Mapper 接口,XML 文件在
resource 目录下与 Mapper 接口在 java 目录下的包一致- XML 文件的
namespace属性与 Mapper 接口的全类名保持一致- XML 文件中的 sql 语句的 id 与 Mapper 接口的方法名一致,且返回类型一致
java
package com.example.spring_security.infrastructure.mapper;
@Mapper
public interface UserMapper {
// 查询user中所有数据
public List<user> selectAll();
}xml
<!-- 必需添加 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapperXml">
<!--resultType表示的是单条记录所封装的类型-->
<select id="SelectAll" resultType="com.example.Pojo.user">
select * from user //书写sql语句
</select>
</mapper>动态 SQL
动态查询
<where>标签可以动态的拼接<if>标签里的条件,如果只使用 WHERE- 如果第一个条件不成立会多出一个 AND
- 如果所有条件不成立,会多出一个 WHERE
<if>标签可以根据 test 条件判断是否要拼接标签里的 sql
xml
<select id="SelectCondition" resultType="com.example.Pojo.user">
select *
from user
<where>
<if test="name != null"> <!--test条件成立,则拼接sql-->
name like concat('%',#{name},'%')
</if>
<if test="age != null">
and age = #{age}
</if>
<if test="gender != null">
and gender = #{gender}
</if>
</where>
</select>动态更新
<set>标签可以动态删除语句中的逗号
xml
<update id="UpdateUser">
UPDATE user
<set>
<if test="name != null">
name=#{name}
</if>
<if test="age != null">
,age=#{age}
</if>
<if test="gender != null">
,gender=#{gender}
</if>
<if test="phone != null">
,phone=#{phone}
</if>
<if test="otId != null">
,ot_id=#{otId}
</if>
</set>
WHERE id=#{id}
</update>动态批量删除
collection表示集合的名称item表示集合元素的名称open在遍历元素的之前加的字符separator遍历每个元素之后要加的字符close遍历完所有元素之后要加的字符
xml
<delete id="DeleteIds">
DELETE
FROM user
WHERE id in //ids集合名需要与Mapper接口传递的集合名保持一致
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
---
DELETE
FROM user
WHERE id in (A,B,C……)java
@Mapper
public interface UserMapperXml {
public List<user> SelectAll();
//根据id集合来批量删除记录
public void DeleteIds(List<Integer> ids);
}sql 片段的抽取与引用
如果像上面一样每个语句都独立写代码,那复用性会很差,如果要更改表名或者其他参数,则要一个一个语句标签更改。引入
<sql>,<include>标签可以解决这个问题
xml
<sql id="select1"> //声明sql片段,定义id属性
select id, name, age, gender, phone, ot_id
from user
</sql>
<select id="SelectCondition" resultType="com.example.Pojo.user">
<include refid="select1"></include> //引入sql片段,指定refid属性
<where>
……
</where>
</select>其他配置
数据封装
当数据库的字段名【dept_id】与实体类的属性名【deptId】不一致时,默认不会进行封装,所以我们要在配置文件中配置自动映射:
#开启MyBatis驼峰命名自动映射开关,此时a_column字段名 就会自动封装到 aColumn 或 AColumn 属性里
mybatis.configuration.map-underscore-to-camel-case=true输出 MyBatis 日志到控制台
在配置文件配置之后,会在控制台输出要执行的 sql 语句,和各种日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl