概述
mybatis是什么?
它是一款半自动的ORM持久层框架,用于简化JDBC的开发
具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低
什么是ORM?
Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应。Student类就对应student表,一个Student对象就对应student表中的一行数据
为什么mybatis是半自动的ORM框架?
用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多
什么是JDBC?
JDBC(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API
什么是数据库连接池?
- 数据库连接池是个容器,负责分配、管理数据库连接
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 释放空闲时间超过预设的最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
优势
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
常见连接池
- C3P0
- DBCP
- Druid(德鲁伊,alibaba开源)
- HiKari(springboot默认)
切换Druid连接池
只需引入依赖即可
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
快速入门
1、创建springboot工程
- 创建springboot工程
- 导入mybatis的起步依赖、mysql的驱动包
- 项目创建完成后,会自动在pom.xml文件中,导入 Mybatis依赖和 MySQL驱动依赖
2、连接数据库
3、新建架构
(如果已经有架构,此步可忽略)
4、新建数据库表
5、修改配置文件
将application.properties改为application.yml
server:
port: 8080 #默认端口8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo_2024 #jdbc:mysql://localhost:3306/+自己的数据库架构名称
username: root #统一
password: **** #自己数据库密码
6、创建实体类
package com.example.springbootlogindemo.entity;
public class User {
private Integer id;
private String username;
private String password;
private String age;
//以下这些get,set方法以后可以引入lombok后使用@Data代替
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
7、创建mapper接口
package com.example.springbootlogindemo.mapper;
import com.example.springbootlogindemo.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper//在运行时,会自动生成该接口的实现类对象(代理对象),并将该对象交给IOC容器管理
public interface UserMapper {
//增
@Insert("insert into `user` (username,password,age)values (#{username},#{password},#{age})")
void insert(User user);
}
8、编写测试类进行测试
package com.example.springbootlogindemo;
import com.example.springbootlogindemo.entity.User;
import com.example.springbootlogindemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootLoginDemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void insert() {
User user = new User();
user.setUsername("admin");
user.setPassword("123456");
user.setAge("18");
userMapper.insert(user);
}
}
9、查看user表确认数据是否插入进去
success!
拓展CRUD
以上是新增操作
要求完善基础的删、改、查的功能
package com.example.springbootlogindemo.mapper;
import com.example.springbootlogindemo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserMapper {
//增
@Insert("insert into `user` (username,password,age)values (#{username},#{password},#{age})")
void insert(User user);
//删(根据id)
@Delete("delete from `user`where id=#{id}")
void deleteUser(Integer id);
//改
@Update("update `user` set username=#{username},password=#{password},age=#{age} where id=#{id}")
void updateUser(User user);
//查(根据id)
@Select("select * from `user`where id=#{id} order by id desc ")
User selectById(Integer id);
//查(所有)
@Select("select * from `user`order by id desc ")
List<User> selectAll();
//查(多条件)
@Select("select * from `user` where age=#{age} and username=#{username} order by id desc") //注意是用and连接
List<User> selectMore(@Param("age") String age, @Param("username") String username);
}
package com.example.springbootlogindemo;
import com.example.springbootlogindemo.entity.User;
import com.example.springbootlogindemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootLoginDemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test//增
void insert() {
User user = new User();
user.setUsername("admin4");
user.setPassword("123456");
user.setAge("18");
userMapper.insert(user);
}
@Test//删(根据id)
void delete() {
userMapper.deleteUser(1);
}
@Test//改
void updateUser() {
User user = new User();
user.setId(1);
user.setUsername("admin2");
user.setPassword("654321");
user.setAge("20");
userMapper.updateUser(user);
}
@Test//查(根据id)
void selectById() {
User user = userMapper.selectById(1);
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getAge());
}
@Test//查(所有)
void selectAll() {
for (User user : userMapper.selectAll()) {
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getAge());
}
}
@Test//查(多条件)
void selectMore() {
for (User user : userMapper.selectMore("18", "admin3")) {
System.out.println(user.getUsername());
System.out.println(user.getPassword());
System.out.println(user.getAge());
}
}
}
其他
如何配置SQL提示
选中任意sql代码->右键->显示上下文操作->语言注入设置->选择MySQL->确认
开启Mybatis日志
只需在application.yml加入以下代码
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
SQL注入
通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法
例:select conut(*) from emp where username='dfgauygfagfsuyd' and password='';
SQL注入后:
select conut(*) from emp where username='dfgauygfagfsuyd' and password='' or '1'='1';
预编译SQL
优势:
- 性能更高
- 更安全(防止SQL注入)
参数占位符
#{}
执行SQL时,将#{……}替换为? 生成预编译SQL,会自动设置参数值
适用于:参数传递
${}
执行SQL时,直接将参数拼接在SQL语句中,存在SQL注入问题
适用于:对表名,列表进行动态设置时使用
主键返回
在数据添加成功后,需要获取插入数据库数据的主键
实现:在SQL语句所对应的注解上方添加@Options(keyProperty="id", useGeneratedKeys=true)
数据库字段与实体类不一致
如:user_name != userName
为了能查询到数据,解决方案:
方案一:起别名,在SQL语句中,对不一样的列名起别名,和实体类属性名一样
方案二:使用@Results和@Restult进行手动结果映射
@Select(select * from emp where id = #{id})
@Results({
@Result(column="create_time",property="createTime"),
@Result(column="update_time",property="updateTime")
})
方案三:(推荐)开启驼峰命名,在配置文件中添加
mybatis:
configuration:
map-underscore-to-camel-case: true
总结
模糊查询
XML映射文件
XML映射文件名称与Mapper接口名称一致,并且XML映射文件名称与Mapper接口放在同一个包下(同包同名)
XML映射文件的namespace属性与Mapper接口名称一致
XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致
<?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.example.sp.mapper.ShopMapper">
<select id="list" resultType="com.example.sp.pojo.Shop">
所要查询的sql语句
</select>
</mapper>
动态SQL
注意:如果是String类型时,除了判断不能为null,还要判断不能为''(空字符串)
用于判断条件是否成立,使用test属性进行条件判断,若条件为true,则拼接SQL
只会在子元素有内容的情况下才插入where语句,自动去除子语句开头的and或or
<?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.example.sp.mapper.ShopMapper">
<select id="list" resultType="com.example.sp.pojo.Shop">
select * from shop
<where>
<if test="categoryId!=null">
category_id=#{categoryId}
</if>
<if test="state!=null">
and state=#{state}
</if>
and create_user=#{userId}
</where>
</select>
</mapper>
动态插入set关键字,并会删去额外的逗号(用在update语句中)
<?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.example.sp.mapper.ShopMapper">
<update id="updata">
<set>
<if test="categoryId!=null">
category_id=#{categoryId},
</if>
<if test="state!=null">
and state=#{state}
</if>
</set>
where id=#{id}
</update>
</mapper>
循环遍历
collection 遍历的集合
item 遍历出来的元素
separator 分隔符
open 遍历开始前拼接的SQL片段
close 遍历结束后拼接的SQL片段
<?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.example.sp.mapper.ShopMapper">
<delete id="deleteByIds">
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
</mapper>
抽取SQL片段
引入SQL片段