Mybtais 中文网站
Maven 仓库
考点: SQL 注入
#{}最终生成预编译sql,预编译Sql语句中?替换#{}内容
一个#{} 替换一个?
在模糊查询时要使用 , ′ {},'% ,′{}%’ ,因为?不能出现在‘’中,而${}不会生成预编译sql,会直接将传过来的字符串进行拼接。
但这种方式性能低、不安全、存在SQL注入问题
因此可换成:concat(‘%’,‘张’,‘%’)
插件
在idea中下载 MybatisX插件,更好地使用mybtiais
依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-mybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- 最新Mysql驱动包 -->
<!--
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.32</version>
<scope>runtime</scope>
</dependency>
-->
<!-- 旧版本 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--spring boot单元测试需要的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
数据库连接
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
#开启驼峰
mybatis.configuration.map-underscore-to-camel-case=true
#配置日志:Sql如何执行的
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
xml映射
@Mapper和@Repository的区别
@Mapper和@Repository都是作用在dao层接口,但是:
- @Repository需要在Spring中配置扫描地址,然后生成Dao层的Bean才能被注入到Service层中:如下,在启动类中配置扫描地址:
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(basePackages = "com.example.dao.**")
public class DemoMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(DemoMybatisApplication.class, args);
}
}
2.@Mapper不需要配置扫描地址,通过xml里面的namespace里面的接口地址,生成了Bean后注入到Service层中
下面提供两种方式:
但不建议使用@Select、@Update等注解直接定义SQL
package com.example.dao;
import com.example.pojo.Emp;
import com.example.pojo.User;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
//根据id 动态删除数据。返回值:此次操作影响多少条记录
@Delete("delete from emp where id = #{id}")
int deleteById(Integer id);
@Delete("delete from emp where id = #{id}")
void delete(String id);
//主键返回:useGeneratedKeys = true:需要拿到生成的主键。keyProperty = "id":所获取的主键最终会封装到emp中的id中
@Options(keyProperty = "id",useGeneratedKeys = true)
//多个参数 传入,动态接收---将多个参数封装到对象中.values中的值对应Emp实体类中的属性值,inser to所对应数据库字段名
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
"values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
void insert(Emp emp);
/*@Update("update emp set username=#{username},update_time=#{updateTime} where id=#{id}")
void update(Emp emp);*/
void update(Emp emp);
// id -> 1
@Select("select * from emp where id=#{id}")
Emp selectById(Integer id);
//条件查询:可能是多条数据
/*@Select("select * from emp where name like concat('%',#{name},'%') and job=#{job} and entrydate between #{start} and #{end}")
List<Emp> list(String name,Short job, LocalDate start,LocalDate end);*/
//alt+回车。自动生成xml sql。要有select关键字,mybatis 知道生成什么类型标签
List<Emp> list(String name,Short job, LocalDate start,LocalDate end);
//批量删除 @Param:指定参数名,多个参数/List/Map/实体类对象
void deleteByIds(@Param("idList") List<Integer> idList);
void deleteByObject(Emp emp);
}
动态SQL
if>
where>
注意:
第一个参数null----》where and错误的sql
解决方案:
替代where 作用:
动态生成sql,如果没有一个条件成立,sql就没有where
以及自动去除条件子句前面的and/or
set>
如果执行update set字段
但没有给字段负赋值,这时会自动设置为null
SQL 标签
问题:如果数据库字段发生改变,那么xml对应的也要修改
代码复用性差
解决方案:将sql代码片段抽离出去—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.dao.EmpMapper">
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
<!--动态更新sql-->
<update id="update">
update emp
<set>
<if test="username!=null">username=#{username},</if>
<if test="name!=null">name=#{name},</if>
<if test="gender!=null">gender=#{gender},</if>
<if test="image!=null">image=#{image},</if>
<if test="job!=null">job=#{job},</if>
<if test="entrydate!=null">entrydate=#{entrydate},</if>
<if test="deptId!=null">dept_id=#{deptId},</if>
<if test="updateTime!=null">update_time=#{updateTime}</if>
</set>
where id = #{id}
</update>
<!-- resultType:返回值,单条记录所封装的类型 。List<Emp> ,类型时Emp-->
<!-- 动态SQL:if 条件判断,test:条件,如果true则执行-->
<!-- 不建议使用select* -->
<select id="list" resultType="com.example.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name!=null">
name like concat('%', #{name}, '%')
</if>
<if test="job!=null">
and job = #{job}
</if>
<if test="start!=null and end!=null">
and entrydate between #{start} and #{end}
</if>
</where>
</select>
<!-- 批量删除:遍历id集合中的值,之后将()拼接到sql中where in (id1,id2,id3...)-->
<delete id="deleteByIds">
delete FROM emp where id in
<foreach collection="idList" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<delete id="deleteByObject">
delete from emp where id = #{id}
</delete>
</mapper>
测试
package com.example;
import com.example.dao.EmpMapper;
import com.example.dao.UserMapper;
import com.example.pojo.Emp;
import com.example.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//spring boot整合单元测试的注解
@SpringBootTest
class DemoMybatisApplicationTests {
@Autowired
private UserMapper userMapper;
@Autowired
private EmpMapper empMapper;
@Test
public void listUser(){
List<User> list = userMapper.list();
list.stream().forEach(user -> System.out.println(user));
}
@Test
public void deleteById(){
// where id = '1 OR id='2''
empMapper.delete("1 OR id='3'");
}
@Test
public void insert(){
Emp emp = new Emp();
emp.setUsername("yuanbao");
emp.setName("元宝");
emp.setGender((short) 1);
emp.setImage("2.page");
emp.setJob((short)2);
emp.setEntrydate(LocalDate.of(2012,10,11));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
System.out.println(emp.getId());
}
@Test
public void update(){
Emp emp = new Emp();
emp.setUsername("可爱");
emp.setUpdateTime(LocalDateTime.now());
emp.setId(3);
empMapper.update(emp);
}
@Test
public void selectById(){
Emp emp = empMapper.selectById(15);
System.out.println(emp);
}
@Test
public void list(){
List<Emp> empList = empMapper.list(null, (short) 1,null,null);
System.out.println(empList);
}
@Test
public void deleteByIds(){
List<Integer> ids = Arrays.asList(3, 4, 5);
Emp emp = new Emp();
emp.setId(3);
empMapper.deleteByObject(emp);
}
}