SSM -- Mybatis

Mybatis

1. 概述

  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

2. 添加依赖(pom.xml)

	<!-- 添加jdbc的jar包依赖 -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.23</version>
       </dependency>
	<!-- 添加mybatis的依赖包 -->
       <dependency>
           <groupId>org.mybatis.spring.boot</groupId>
           <artifactId>mybatis-spring-boot-starter</artifactId>
           <version>2.1.4</version>
       </dependency>

3. Mybatis配置文件(mybatis-config.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">

<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!-- environments可以配置多个数据库的连接信息,default指定默认的环境 -->
    <environments default="test">
        <environment id="test">
            <!-- transactionManager:使用的事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- dataSource:配置了数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    
 <!-- 引入一个映射文件 -->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"></mapper>
    </mappers>

</configuration>

4. User类

package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @Author Sky-haohao
 * @Date 2021/8/16 17:39
 * @Version 1.0
 */
//注意: 属性名 和 表里的字段名 必须一致,否则无法ORM(对象关系映射)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class User {
    private Integer id;
    private String name;
    private String addr;
    private Integer age;
}

5. UserMapper.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">
<!-- 这个文件是映射文件,写SQL的
    namespace:用来作为mapper.xml的唯一标识
    resultType:类的全路径,用来封装查到的结果-->
<mapper namespace="userMapper">
    <!-- 查id=1的用户信息 -->
    <select id="getById" resultType="cn.tedu.pojo.User">
        select * from user where id = 1
    </select>
    <!-- 查询所有用户的信息 -->
    <select id="selectAll" resultType="cn.tedu.pojo.User">
        select * from user
    </select>
    <!--
        SQL动态获取参数时,使用$和#的区别
        $是底层使用了低级传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
        #底层使用了高级传输器,安全,高效,会自动拼接字符串
    -->
    <!-- 根据用户名查询 -->
    <select id="getByName" resultType="cn.tedu.pojo.User">
        select * from user where name = #{name}
    </select>
</mapper>

6. 测试(TestMybatis.java)

package cn.tedu.test;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Author Sky-haohao
 * @Date 2021/8/17 9:50
 * @Version 1.0
 */
public class TestMybatis {
    @Test
    public void get(){
        try {
        	//读取配置文件
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //创建会话工厂
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
            //开启会话,准备执行SQL
            SqlSession session = factory.openSession();
            // 定位sql(namespace的值.id的值),并执行
            // 根据id 查询,selectOne返回一个结果
            Object o = session.selectOne("userMapper.getById");
            System.out.println(o);
            // 查询所有用户的信息,selectList 返回一个或多个结果
            List<Object> list = session.selectList("userMapper.selectAll");
            for (Object u : list){
                System.out.println(u);
            }
            // 根据name查询
            Object o2 = session.selectOne("userMapper.getByName","hanmeimei");
            System.out.println(o2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7. $和#的区别

  • 推荐使用##在底层使用的是高级传输器,安全高效,且避免了sql注入攻击,并且会自动拼接字符串
    • 例如,传入参数jackselect * from user where name = #{name}; 会自动加上'',转换后变成select * from user where name = 'jack';
  • $使用的是低级的传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
    • 上述sql中,如果使用select * from user where name = ${name};则不会拼接字符串,直接变成select * from user where name = jack;,此时执行出错。

8. 使用alisa别名 进行优化

  • mybatis-config.xml文件中<configuration>标签下配置别名
    <!-- 配置别名 -->
        <typeAliases>
            <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
        </typeAliases>
    
  • 此时,userMapper.xml中的resultType都可以改成User
    <select id="getById" resultType="User">
    

接口开发

9. 概述

  • 为了优化定位sql的字符串拼接过程,namespace的值.id的值
  • 修改后,namespace的值是接口的全路径,id的值是接口里的方法名

10. Dept类 ---- 完成ORM

package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * @Author Sky-haohao
 * @Date 2021/8/17 14:37
 * @Version 1.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
//完成ORM,属性名 必须和 字段名 一致
public class Dept {
    private Integer id;
    private String dname;
    private String loc;
}

11. 修改核心配置文件,配置别名,并引入Mapper

  • mybatis-config.xml
    <typeAliases>
    	<typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>
    
    <!-- 引入一个映射文件 -->
    <mappers>
        <mapper resource="mappers/DeptMapper.xml"></mapper>
    </mappers>
    

12. 创建接口

package cn.tedu.dao;

import cn.tedu.pojo.Dept;

/**
 * @Author Sky-haohao
 * @Date 2021/8/17 15:12
 * @Version 1.0
 */
public interface DeptMapper {
    /**
     * 通过id查询对应的部门信息
     * @return Dept对象
     */
    Dept getById();

    /**
     * 根据部门名称查询对应的部门名称
     * @param dname 部门名称
     * @return Dept对象,可能存在多个,返回值为List
     */
    List<Dept> getByName(@Param("dname") String dname);

	/**
     * 新增部门记录
     * @param dept 部门信息对象
     * @return 返回影响行数
     */
    Integer save(Dept dept);

	/**
     * 根据id删除 -- 方式一
     * @param a 数组a,存放多个值
     * @return 返回影响的行数
     */
    Integer delete(int[] a);

    /**
     * 根据id删除记录 -- 方式二
     * @param id id值
     * @return 返回影响的行数
     */
    Integer deleteByIds(Integer... id);
}

13. DeptMapper.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="cn.tedu.dao.DeptMapper">
    <!-- 提取SQL片段,提高SQL片段的复用性 -->
    <sql id="cols">
        id, dname, loc
    </sql>
    <!-- 根据id查询 -->
    <select id="getById" resultType="Dept">
        select * from dept where id = 1
    </select>
    <!-- 根据name查询 -->
    <select id="getByName" resultType="Dept">
        select
            <include refid="cols"></include> 
        from dept where dname = #{dname}
    </select>
    <!-- 新增部门记录 -->
    <insert id="save">
        insert into dept values (#{id},#{dname},#{loc})
    </insert>
    <!-- 根据id删除 - 方式一 -->
    <delete id="delete">
        delete from dept where id in
        <foreach collection="array" item="ids" open="(" close=")" separator=",">
            #{ids}
        </foreach>
    </delete>
    <!-- 根据id删除 - 方式二 -->
    <delete id="deleteByIds">
        delete from dept where id in
        <foreach collection="array" item="id" open="(" close=")" separator="," >
            #{id}
        </foreach>
    </delete>
</mapper>

14. 测试

package cn.tedu.test;

import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @Author Sky-haohao
 * @Date 2021/8/17 9:50
 * @Version 1.0
 */
public class TestMybatis {
    @Test
    public void get(){
        try {
            //读取配置文件
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //创建会话工厂
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
            //开启会话,准备执行SQL
            SqlSession session = factory.openSession();
            
            //开始测试Dept表
            /*Object o3 = session.selectOne("deptMapper.getById");
            System.out.println(o3);*/
            
            //调用接口里的方法
            DeptMapper mapper = session.getMapper(DeptMapper.class);
            Dept d = mapper.getById();
            System.out.println(d);
            List<Dept> name = mapper.getByName("java教研部");
            //List<Dept> dname = mapper.getByName(null);
            for (Dept dname : name){
                System.out.println(dname);
            }
            //测试新增部门记录
            Dept dept = new Dept();
            dept.setId(null).setDname("java开发部").setLoc("上海");
            
            Integer row = mapper.save(dept);
            // mybatis不会自动提交事务,增删改要自己提交
            session.commit();
            System.out.println("受影响的行数:"+row);
            
            //测试删除部门记录
            //方式一
            Integer num = mapper.delete(new int[]{12,100});
            session.commit();
            System.out.println("受影响的行数:"+num);
            //方式二
            Integer num2 = mapper.deleteByIds(12,100);
            session.commit();
            System.out.println("受影响的行数:"+num2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Mybatis动态SQL

15. sql和include

  • sql标签用来提取SQL片段,提高复用性
  • include标签用来指引使用位置
    	<!-- 提取SQL片段,提高SQL片段的复用性 -->
        <sql id="cols">
            id, dname, loc
        </sql>
        <!-- 根据name查询 -->
        <select id="getByName" resultType="Dept">
            select
                <include refid="cols"></include>
            from dept where dname = #{dname}
        </select>
    

16. if

  • 在执行sql时,增加一些判断条件
  • 如:判断字段名是否为null,不为null再执行
    	<select id="getByName" resultType="Dept">
            select
                <include refid="cols"></include>
            from dept 
                <if test="dname != null">
                    where dname = #{dname}
                </if> 
        </select>
    

17. where

  • 用于去掉条件中可能多余的and或者or
<select id="getAll" resultType="Dept">
        select
            <include refid="cols"></include>
        from dept
            <where>
                <if test="name != null"> name like #{name}</if>
	            <if test="loc != null">and loc like #{loc}</if>
            </where>
    </select>

18. foreach

  • 用于in子查询中的多个值的遍历
  • 测试方法见上文
	<!-- 根据id删除 - 方式一 -->
    <delete id="delete">
        delete from dept where id in
        <foreach collection="array" item="ids" open="(" close=")" separator=",">
            #{ids}
        </foreach>
    </delete>
    <!-- 根据id删除 - 方式二 -->
    <delete id="deleteByIds">
        delete from dept where id in
        <foreach collection="array" item="id" open="(" close=")" separator="," >
            #{id}
        </foreach>
    </delete>
  • 参数解析:
    • item是迭代时的别名,要与下方#{}中的值对应
    • open是以什么开始,此处一般为open="("
    • close是以什么结束,此处一般为close=")"
    • separator是每次迭代用什么符合作为分割符,此处一般为separator=","
    • collection属性必须指定,有3个值:
      • list:
        • collection="list"
        • 参数写法:List<Integer> ids
        • 测试代码:
          List<Integer> ids = new ArrayList<Integer>();
          ids.add(1);
          ids.add(3);
          mapper.delete(ids);
          
      • array:
        • collection="array"
        • 参数写法:int[] ids
        • 测试代码:mapper.delete(new int[]{12,103});
      • Map.key:
        • collection="ids",ids是map集合遍历中的key值
        • 参数写法:Map<String, Object> map
        • 测试代码:
          Map<String,Object> map = new HashMap<String,Object>();
          String[] ps = {"1","22"};
          map.put("ids", ps );
          mapper.delete(map);
          

19. SQL中的特殊字符

  • 当SQL中有特殊字符时,mybatis不能正常解析,如< >等符号,此时有两种解决方案
  • 一是使用<![CDATA[ ]]>括起来,比如<![CDATA[ and age<=#{age} ]]>
  • 二是使用转义字符
    • 小于号:< &lt;
    • 大于号:> &gt;
    • 与:& &amp;
    • 单引号:' &apos;
    • 双引号: " &quot;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值