MyBatis

MyBatis 是什么?

MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。

JDBC 的操作流程:

  1. 创建数据库连接池 DataSource
  2. 通过 DataSource 获取数据库连接 Connection
  3. 编写要执⾏带 ? 占位符的 SQL 语句
  4. 通过 Connection 及 SQL 创建操作命令对象 Statement
  5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
  6. 使⽤ Statement 执⾏ SQL 语句
  7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
  8. 处理结果集
  9. 释放资源

MyBatis学习

框架交互流程图:
MyBatis_第1张图片
MyBatis 也是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象的互相转换:

  1. 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL
  2. 将结果集映射为返回对象,即输出对象
    ORM 把数据库映射为对象:

数据库表(table)–> 类(class)
记录(record,⾏数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)

准备工作:

数据库中建立一张登录表:
MyBatis_第2张图片

添加MyBatis框架⽀持

⽼项⽬添加MyBatis

<dependency>
  <groupId>org.mybatis.spring.bootgroupId>
  <artifactId>mybatis-spring-boot-starterartifactId>
  <version>2.1.4version>
dependency>

<dependency>
  <groupId>mysqlgroupId>
  <artifactId>mysql-connector-javaartifactId>
  <version>5.1.38version>
  <scope>runtimescope>
dependency>
新项⽬添加MyBatis

如果是新项⽬创建 Spring Boot 项⽬的时候添加引⽤就可以了,如下图所示:
MyBatis_第3张图片

配置连接字符串和MyBatis

此步骤需要进⾏两项设置,数据库连接字符串设置和 MyBatis 的 XML ⽂件配置。

配置连接字符串

如果是 application.yml 添加如下内容:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/myjava?characterEncoding=utf-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#  MyBatis 的 XML 中保存是查询数据库的具体操作 SQL,配置如下:
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
  configuration: # 配置打印 MyBatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

注意事项:
如果使⽤ mysql-connector-java 是 5.x 之前的使⽤的是“ com.mysql.jdbc.Driver ” ,如果是⼤于 5.x 使⽤的是“ com.mysql.cj.jdbc.Driver ” 。

添加业务代码

下⾯按照后端开发的⼯程思路,也就是下⾯的流程来实现 MyBatis 查询所有⽤户的功能:
MyBatis_第4张图片
目录解构:
MyBatis_第5张图片

添加实体类
import lombok.Data;
@Data
    public class Login {
        private int uid;
        private String username;

        private String password;
        private String power;//职位

        public Login(){}
        public Login(String username, String password, String power) {
            this.username = username;
            this.password = password;
            this.power = power;
        }
    }
添加 mapper 接⼝
import com.model.Login;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface LoginMapper {
    List<Login> selectAll();
}
添加 LoginMapper.xml
<?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.mapper.LoginMapper">
    
</mapper>

LoginMapper.xml 查询所有⽤户的具体实现 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.mapper.LoginMapper">
    <select id="selectAll" resultType="com.model.Login">
        select * from userregister
    </select>
</mapper>

对以上标签的说明:

  • 标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接⼝的全限定名,包括全包名.类名。
  • 查询标签:是⽤来执⾏数据库的查询操作的:
  • id:是和 Interface(接⼝)中定义的⽅法名称⼀样的,表示对接⼝的具体实现⽅法。
  • resultType:是返回的数据类型,也就是开头我们定义的实体类

其他:

  • useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段),默认值:false。
  • keyColumn:设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。
  • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性名称。
添加 Service
import com.mapper.LoginMapper;
import com.model.Login;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class LoginService {
    @Autowired
    private LoginMapper loginMapper;
    public List<Login> selectAll(){
        return loginMapper.selectAll();
    }
}
添加 Controller
import com.model.Login;
import com.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/login")
public class LoginController {
    @Autowired
    private LoginService loginService;
    @RequestMapping("/selectAll")
    public List<Login> selectAllLogin(){
        return loginService.selectAll();
    }
}

以上代码写完,整个 MyBatis 的查询功能就实现完了,接下来使⽤ postman 来测试⼀下。

使⽤ postman 测试

MyBatis_第6张图片

增、删、改操作

对应使⽤ MyBatis 的标签如下:

  • 标签:插⼊语句
  • 标签:修改语句
  • 标签:删除语句
LoginMapper接口
Integer insert(Login login);
Integer updateByCondition(@Param("uid") Integer uid,@Param("password") String password);
Integer batchDelete(Integer uid) ;
LoginMapper.xml
</insert>
        <insert id="insert" >
        insert into userregister(username,password,power)
        values(#{username},#{password},#{power})
    </insert>
<update id="updateByCondition">
        update userregister set password = #{password}
		where uid = #{uid}
    </update>
<delete id="batchDelete">
        delete from userregister where uid = #{deleteId}
    </delete>

参数占位符 #{} 和 ${}

  • #{}:预编译处理。
  • ${}:字符直接替换。

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的 set ⽅法来赋值。直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

${} 优点

使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时, 如果传递的值为 String 则会加单引号,就会导致 sql 错误。

SQL 注⼊问题

sql 注⼊代码:“’ or 1='1”

<select id="select" resultType="com.model.Login">
        select * from userregister where uid = ${uid}
    </select>

这时查询会将所有的结果查询出来,因此⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式。

like 查询(使用concat())

like 使⽤ #{} 报错

 <select id="findUserByName2" resultType="com.example.demo.model.User">
 select * from userregister where username like '%#{username}%';
 </select>

相当于: select * from userinfo where username like ‘%‘username’%’;
这个是不能直接使⽤ ${},可以考虑使⽤ mysql 的内置函数 concat() 来处理,实现代码如下:

<select id="findUserByName3" resultType="com.example.demo.model.User">
 select * from userregister where username like concat('%',#{username},'%');
</select>

多表查询

如果是增、删、改返回搜影响的⾏数,那么在 mapper.xml 中是可以不设置返回的类型的,然⽽即使是最简单查询⽤户的名称也要设置返回的类型。也就是说对于 查询标签来说⾄少需要两个属性:

  • id 属性:⽤于标识实现接⼝中的那个⽅法;
  • 结果映射属性:结果映射有两种实现标签: 和
返回类型:resultType

绝⼤数查询场景可以使⽤ resultType 进⾏返回

 <select id="selectAll" resultType="com.model.Login">
        select * from userregister
    </select>
返回字典映射:resultMap

resultMap 使⽤场景:

  • 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
  • ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据。

比如:
username改成name,password改成psw
MyBatis_第7张图片

<resultMap id="BaseMap" type="com.model.Login2">
        <id property="id" column="uid"></id>
        <result property="name" column="username"></result>
        <result property="psw" column="password"></result>
        <result property="power" column="power"></result>
    </resultMap>
<select id="getUserByName" resultMap="com.mapper.UserMapper.BaseMap">
 select * from userregister where username=#{name}
</select>
多表查询

在多表查询时,如果使⽤ resultType 标签,在⼀个类中包含了另⼀个对象是查询不出来被包含的对象的,⽐如以下实体类:

@Data
public class Company {
    private int id;
    private String company_name;
    private String region;
    private String address;
}
@Data
public class Staff {
    private int id;
    private Company company;
    private String staff_name;
    private String sex;
    private int age;
    private String phone;
    private String position;
    private Date entry_time;
}

⼀对⼀的表映射,⼀对⼀映射要使⽤ 标签

<mapper namespace="com.mapper.StaffMapper">
    <resultMap id="BaseMap" type="com.model.Staff">
        <id property="id" column="id"></id>
        <association property="company" resultMap="com.mapper.LoginMapper.BaseMap"></association>
    </resultMap>
    <select id="queryStaff" resultType="com.model.Staff">
        select * from staff left join company_information on staff.company = company_information.company_name
    </select>
</mapper>

使⽤ 标签,表示⼀对⼀的结果映射:

  • property 属性:指定 company 中对应的属性
  • resultMap 属性:指定关联的结果集映射,将基于该映射配置来组织⽤户数据。
  • association.resultMap.column是指 标签中 resultMap属性,对应的结果集映射中,column字段。

columnPrefix 属性:绑定⼀对⼀对象时,是通过 columnPrefix+association.resultMap.column 来映射结果集字段。 防止两个重名的字段。(上面没有)

<association property="company" resultMap="com.mapper.LoginMapper.BaseMap" columnPrefix=id_></association>
    </resultMap>

一对多:
⼀对多需要使⽤ 标签,⽤法和 相同,

<collection property="alist" resultMap="com.mapper.LoginMapper.BaseMap"
 columnPrefix="a_">

复杂情况:动态SQL使⽤

标签

必填字段和⾮必填字段的填入

标签

标签结合标签,对多个字段都采取动态⽣成的⽅式。
标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀
<insert id="insertByCondition">
    <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
        insert into userregister(username,password,
        <if test="power!=null">,power</if>)
        values(#{username},#{password},
        <if test="power!=null">,#{power}</if>)
    </trim>
标签

传⼊的⽤户对象,根据属性做 where 条件查询,⽤户对象中属性不为 null 的,都为查询条件

标签

根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。

 <update id="updateByCondition">
        update userregister
        <set>
            <if test="password!=null">
                password = #{password}
            </if>
        </set>
        <where>
            uid = #{uid}
        </where>
    </update>
标签

对集合进⾏遍历时可以使⽤该标签。标签有如下属性:

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串
<delete id="batchDelete">
        delete from userregister where uid in
        <foreach collection="ids" open="(" close=")" separator="," item="deleteId">
            #{deleteId}
        </foreach>
    </delete>

你可能感兴趣的:(JavaEE,mybatis,数据库,mysql)