二阶段-三大框架之一MyBatis持久层

目录

一、MyBatis持久层框架

1、概念

2、内部组件结构图

二、MyBatis-XML映射方式

1、创建库user

2、项目结构

 3、修改pom文件,添加mybatis的jar包,jdbc依赖包

4、创建核心配置文件,指定连接数据库的参数

5、创建映射文件,写SQL

6、创建User类

7、回到第四步核心配置文件中引入映射文件

8、测试xml映射方式能否映射读取到数据库的字段值

9、异常报错总结

三、XML映射方式练习

四、参数解析

1、配置类的别名alias

2、 面试题:$ 和 #取值的区别?

3、映射文件SQL语句的转义符号

五、动态SQL

案例:操作dept表

1、创建Dept类,用来完成ORM

2、创建DeptMapper.xml,用来写SQL

3、修改mybatis-config.xml核心配置文件,引入dept的映射文件

4、创建测试类

5、映射文件中练习动态SQL

6、修改测试文件

7、动态SQL:

六、MyBatis-接口映射方式

1、为什么使用接口映射方式

2、操作步骤

2.1 修改映射文件,把namespace的值改成接口的全路径

2.2 创建接口文件

2.3 创建测试类

2.4 总结

七、问答题

JDBC和MyBatis的区别?

XML和接口方式的区别?

接口方式怎么找到xml执行的?


一、MyBatis持久层框架

1、概念


MyBatis的前身就是iBatis,iBatis本是apache的一个开源项目,2010年5月这个项目由apahce sofeware foundation 迁移到了google code,并且改名为MyBatis。
MyBatis 是支持普通 SQL增删改查,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。

  1. 简化JDBC操作数据库的过程 
  2. 能够更好的完成ORM框架(对象关系映射)
     

2、内部组件结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TmpD1kne-1623150729867)(RackMultipart20210608-4-12c6kke_html_28841cf87cefc5b9.png)]

1) 两个配置文件:

  1. 核心配置文件,用于配置数据库的连接参数
  2. 映射文件 – 用来写SQL语句

2)两个核心工具类:

  1. SqlSessionFactory--会话工厂,用来产生会话
  2. SqlSession--会话,用来执行SQL

3)ORM:对象关系映射,是指把表里字段的值,自动映射给 类里的属性

二、MyBatis-XML映射方式

1、创建库user

create database mybatisdb default character set utf8;
use mybatisdb;
create table user(id int primary key auto_increment,name varchar(100),addr varchar(100),age int);
Insert into user values(null,'hanmeimei','北京',28);
Insert into user values(null,'xiongda','上海',20);
Insert into user values(null,'xiaonger','上海',19);
DROP TABLE IF EXISTS dept;
CREATE TABLE dept (
  id int(11) NOT NULL AUTO_INCREMENT,
  dname varchar(14) DEFAULT NULL,
  loc varchar(13) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO dept VALUES ('1', '呵呵呵', '一区');
INSERT INTO dept VALUES ('2', '哈哈哈哈', '二区');
INSERT INTO dept VALUES ('3', 'operations', '二区');
INSERT INTO dept VALUES ('5', 'java教研部', '大钟寺');
INSERT INTO dept VALUES ('10', '开发', '西二旗');
DROP TABLE IF EXISTS emp;
CREATE TABLE emp (
  id int(11) NOT NULL AUTO_INCREMENT,
  ename varchar(10) DEFAULT NULL,
  job varchar(9) DEFAULT NULL,
  mgr decimal(4,0) DEFAULT NULL,
  hiredate date DEFAULT NULL,
  sal decimal(7,2) DEFAULT NULL,
  comm decimal(7,2) DEFAULT NULL,
  deptno int(11) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=510 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO emp VALUES ('100', 'jack', '副总', null, '2002-05-03', '90000.00', null, '1');
INSERT INTO emp VALUES ('200', 'tony', '总监', '100', '2015-02-02', '10000.00', '2000.00', '2');
INSERT INTO emp VALUES ('300', 'hana', '经理', '200', '2017-02-02', '8000.00', '1000.00', '2');
INSERT INTO emp VALUES ('400', 'leo', '员工', '300', '2019-02-22', '3000.00', '200.12', '2');
INSERT INTO emp VALUES ('500', 'liu', '员工', '300', '2019-03-19', '3500.00', '200.58', '2');
INSERT INTO emp VALUES ('502', '王一博', 'topidol.', '1000', '2021-03-31', '20000.00', '99.00', '88');
INSERT INTO emp VALUES ('504', '蔡徐坤', 'rapper', '10', '2021-03-29', '100.00', '1000.00', '100');

2、项目结构

在这里插入图片描述

 3、修改pom文件,添加mybatis的jar包,jdbc依赖包

<dependencies>
        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
    </dependencies>

4、创建核心配置文件,指定连接数据库的参数

resouces-->new -->file-->maybatis-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>

    <!--可以配置多个数据库连接的环境,使用default指定默认用哪个-->
    <environments default="test">
        <!--配置了具体连接数据库的参数-->
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源:就是制定了数据库连接时的参数-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.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="root"/>
            </dataSource>
        </environment>
    </environments>

</configuration>


5、创建映射文件,写SQL

resouces-->new -->file-->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">

<!--这是映射文件,namespace用来作为文件的唯一标识
-->
<mapper namespace="UserMapperNS">
    <!--select标签表示要发起查询的SQL,
    id是SQL语句的唯一标识,
    resultType用来完成ORM,把表里的字段值 自动映射 类里的属性值
    -->
    <select id="getAll" resultType="cn.tedu.pojo.User">
        select * from user
    </select>
</mapper>

6、创建User类

package cn.tedu.pojo;
//Mybatis自动完成ORM,把表里的字段的值 查到 封装给 类里的属性
//要求:属性名要和字段名一样
public class User {
    private Integer id;
    private String name;
    private String addr;
    private Integer age;

    //get set toString...
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", addr='" + addr + '\'' +
                ", age=" + age +
                '}';
    }
}

7、回到第四步核心配置文件中引入映射文件

在mybatis-config.xml文件中使用mapper引入UserMapper.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="test">
 		<environment id="test">
 			<transactionManager type="JDBC"></transactionManager>
 			<dataSource type="POOLED">
 				<property name="driver" value="com.mysql.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="root"/> 
 			</dataSource>
 		</environment>
 	</environments>
 
 **<mappers>
         #引入映射文件
 	<mapper resource="UserMapper.xml"/>
 </mappers>**
 
 </configuration>

8、测试xml映射方式能否映射读取到数据库的字段值

package cn.tedu.test;

import cn.tedu.pojo.User;
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 org.apache.ibatis.io.Resources;

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

public class TestMybatis {
    @Test
    public void get() throws IOException {
        //1.读取核心配置文件MyBatis-Config.xml
       InputStream in = Resources.getResourceAsStream("MyBatis-Config.xml");
       //2.创建会话工厂
       SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.创建会话
        SqlSession sqlSession = factory.openSession();
        //4.执行SQL,selectList()表示查询多个
        //sqlSession.selectList("namespace的值.id的值");//唯一的标识定位了SQL
        List<User> list= sqlSession.selectList("UserMapperNS.getAll");
        //5.处理结果,高效遍历list集合
        for (User u:list){
            System.out.println(u);
        }
    }

}

9、异常报错总结

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for UserMapperNS.getAll
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for UserMapperNS.getAll

1)问题1:核心配置文件中未引入映射文件

解决方案:在核心配置文件中使用mapper引入映射文件

2)问题2:类的属性名和数据库的字段名不一致

3)问题3:类的属性类型和数据库的字段名类型不一致

4)问题4:核心配置文件中的Driver驱动版本问题,加cj或者不加

5)问题5:映射文件中resultType来形成结果集,出错原因可能写成了resultMap

三、XML映射方式练习

注意:

1)相同的SQL语句只执行一次,后面再执行该SQL语句,只会从常量池里拿取,不会执行SQL语句了,这叫做高效缓存

2)事务的增删改都需要提交commit

//第一种提交方式:创建会话加true,增删改会自动提交事务
SqlSession sqlSession = factory.openSession(true);


//第二种提交方式:执行SQL语句后写提交代码
 int[] array={1,2,3};
        //给SQL传入多个参数
        int delete = sqlSession.delete("DeptMapperNS.delete",array);
        //mybatis不会自动提交事务,增删改必须手动提交
        sqlSession.commit();
        System.out.println("删除成功");

映射文件操作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">

<!--这是映射文件,namespace用来作为文件的唯一标识
-->
<mapper namespace="UserMapperNS">
    <!--select标签表示要发起查询的SQL,id是SQL语句的唯一标识,
    resultType用来完成ORM,把表里的字段值 自动映射 类里的属性
    -->
    <select id="getAll" resultType="cn.tedu.pojo.User">
        select * from user
    </select>
    <!--1.查询id=1的user信息
        select * from user where id=1   不要把参数1写死,太死板了
        ${???} 动态获取执行SQL时传入的参数
    -->
    <select id="getById" resultType="cn.tedu.pojo.User">
        select * from user where id=${id}
    </select>

    <!--2.查询名字是xiongda的用户信息
        select * from user where name=${name}
        面试题:$ 和 #取值的区别?
        都能获取参数的值,$只获取值本身不拼接单引号,#获取到值以后自动拼接单引号
        $底层使用Statement传输器不安全低效,#底层使用PreparedStatement高效安全SQL简单
    -->
    <select id="getByName" resultType="cn.tedu.pojo.User">
        select * from user where name=#{name}
    </select>

    <!--3.查询上海有几个员工
        resultType是指查询的结果要交给谁处理,
        结果可以是写一个类的路径,也可以写int string等
    -->
    <select id="getByAddr" resultType="int">
        select count(1) from user where addr=#{addr}
    </select>

    <!--4.动态修改id对应的name列的名称-->
    <update id="setname" parameterType="int">
        update car set name="宝马" where id=#{id}
    </update>
        <!--5.动态修改id对应的color列的信息-->
    <update id="setcolor" parameterType="int">
        update car set color="黄色" where id=#{id}
    </update>

</mapper>





测试:

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;

//测试
public class Test1 {
    @Test
    public void get() throws IOException {
        //1,读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        //2,创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3,创建会话
        SqlSession session = factory.openSession();
        //4,执行SQL
//        session.selectList("namespace的值.id的值");//唯一的定位了SQL
        List<User> list = session.selectList("UserMapperNS.getAll");//查询出多个结果
        //5,处理结果
        for(User u : list){
            System.out.println(u);
        }

        //测试 查询id=1的user信息
        User u = session.selectOne("UserMapperNS.getById",2);
        System.out.println(u);

        //测试 查询名字是xiongda的用户信息
        //selectList(1,2)--1是SQL定位的方式 2是SQL需要的参数
        List<User> list2 = session.selectList("UserMapperNS.getByName","xiongda");
        for (User uu : list2) {
            System.out.println(uu);
        }
        //测试 查询上海有几个员工
        //selectOne(1,2)--1是SQL定位的方式 2是SQL需要的参数
        int count = session.selectOne("UserMapperNS.getByAddr","上海");
        System.out.println(count);
        
        //测试 修改id=1,name列的名称,增删改都需要提交commit
        int update = sqlSession.update("CarMapperNS.setname", 1);
        System.out.println(update);
        sqlSession.commit();

        //测试 修改id=3,color列的名称,增删改都需要提交commit
        int update1 = sqlSession.update("CarMapperNS.setcolor", 3);
        System.out.println("修改成功");
        sqlSession.commit();
    }
}

四、参数解析

1、配置类的别名alias

在核心配置文件中,配置别名,映射文件中的resultType就可以写别名即可

作用:使全路径得到简写

<typeAliases>
<typeAlias type="cn.tedu.pojo.User" alias="User"/>
</typeAliases>

2、 面试题:$ 和 #取值的区别?

  1.  都能获取参数的值,$只获取值本身不拼接单引号,#获取到值以后自动拼接单引号
  2. $底层使用Statement传输器不安全低效,#底层使用PreparedStatement高效安全SQL简单

3、映射文件SQL语句的转义符号

 用<![CDATA[ ?? ]]>括起来就能解决

<![CDATA[
	and age<=#{age}
]]>

五、动态SQL

Mybatis提供使用ognl表达式动态生成sql的功能。

案例:操作dept表

1、创建Dept类,用来完成ORM

package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.stereotype.Component;
/*可以使用Lombok 简化set、get、toString()...*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Dept {
    private Integer id;
    private String dname;
    private String loc;

}

2、创建DeptMapper.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">

<!--这是映射文件,namespace用来作为文件的唯一标识-->
<mapper namespace="DeptMapperNS">
    <!--查询所有记录-->
    <select id="getAll" resultType="cn.tedu.pojo.Dept">
        select * from dept
    </select>

</mapper>





3、修改mybatis-config.xml核心配置文件,引入dept的映射文件

配置别名 type是类的路径 alias以后使用的别名

<?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>
    <!--配置别名 type是类的路径 alias以后使用的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
        <typeAlias type="cn.tedu.pojo.Dept" alias="D"></typeAlias>
    </typeAliases>
    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.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="root"/>
            </dataSource>
        </environment>
    </environments>
/*核心配置文件引入映射文件*/
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
        <mapper resource="DeptMapper.xml"></mapper>
    </mappers>
</configuration>

4、创建测试类

package cn.tedu.test;

import cn.tedu.pojo.Dept;
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;

public class Test2 {
    @Test
    public void get() throws IOException {
        //1,读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        //2,创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3,创建会话
        SqlSession session = factory.openSession();
        //4,执行SQL
        List<Dept> list = session.selectList("DeptMapperNS.getAll");
        for (Dept d : list) {
            System.out.println(d);
        }
    }
}

5、映射文件中练习动态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">

<!--这是映射文件,namespace用来作为文件的唯一标识-->
<mapper namespace="DeptMapperNS">
    /*1.提取SQL片段*/
    <sql id="names">
        id,dname,loc
    </sql>
    <!--查询所有记录-->
    <select id="getAll" resultType="D">
        select 
         /* 2.include引入SQL片段,refid指定SQL片段的id值*/
        <include refid="names"></include>
        from dept
    </select>


    <!--查询id=1记录-->
    <select id="getById" resultType="D">
        select
         /*2.include引入SQL片段,refid指定SQL片段的id值*/
        <include refid="names"></include>
        from dept
        /* 使用if标签用来做判断,条件成立才执行SQL,不成里就不执行SQL*/
        <if test="id != null">
            where  id = #{id}
        </if>
    </select>

     <!--部门表添加表记录-->
    <insert id="insert" parameterType="int">
        insert into dept values(4,"后端开发","合肥")
    </insert>

     <!--部门表删除表记录-->
    <delete id="delet" parameterType="int">
        delete from dept 
        <if test="id != null">
            where  id = #{id}
        </if>
    </delete>

 <!--查询id等于3或者1的信息-->
    <select id="getbyids" resultType="D">
        select
        <include refid="names"></include>
        from dept
        <where>/*where标签可以去除条件中多余的or 或者 and 关键字*/
            <if test="id != null">
                id=#{id}
            </if>
           or id=3
        </where>

<!--删除id是1,2,3 的部门信息-->
    <delete id="delete" parameterType="int" >
        /*delete from dept where id in(1,2,3) 参数写死了,最好是动态解析*/
        delete from dept where id in(
        /*foreach用来遍历,collection属性的值是固定值array list 或者map里的key值
          item相当于遍历得到的数据,separator是数据间的分隔符*/
        <foreach collection="array" item="i"  separator=",">
            #{i}/*获取了遍历得到的数据*/
        </foreach>
        )
    </delete>

</mapper>

6、修改测试文件

package cn.tedu.test;

import cn.tedu.pojo.Dept;
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;

public class Test2 {
    @Test
    public void get() throws IOException {
        //1,读取核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        //2,创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3,创建会话
        SqlSession session = factory.openSession();
//SqlSession sqlSession = factory.openSession(true);//创建会话加true增删改会自动提交事务

        //4,执行SQL
        List<Dept> list = session.selectList("DeptMapperNS.getAll");
        for (Dept d : list) {
            System.out.println(d);
        }

        //selectOne(1,2)---1是SQL的定位,2是SQL需要的参数
        Dept d =session.selectOne("DeptMapperNS.getById",1);
        System.out.println(d);

        //部门表添加表记录,提交后,注释掉,防止下次执行主键约束报错
       /* int insert = sqlSession.insert("DeptMapperNS.insert");
        System.out.println(insert);
        sqlSession.commit();*/
        
        //部门表删除动态指定id的表记录,增删改都需要提交
        int delete = sqlSession.delete("DeptMapperNS.delet", 4);
        System.out.println("删除成功");
        sqlSession.commit();

        /*删除多个id值,可以存到数组里,*/
        int[] array={1,2,3};
        //给SQL传入多个参数
        int delete = sqlSession.delete("DeptMapperNS.delete",array);
        //mybatis不会自动提交事务,增删改必须手动提交
        sqlSession.commit();
        System.out.println("删除成功");
    
    }
}

7、动态SQL:

1、提取sql片段

Sql标签用来提取SQL片段,来提高SQL的复用

SQL语句中通过include引用指定的SQL片段.

2、if判断

执行SQL时,可以添加一些判断条件.

3、where标签

where标签可以去除(过滤)条件中多余的or 或者 and 关键字

4、foreach遍历标签

用于in子查询中的多个值的遍历

<delete id="delete">
DELETE FROM teachers WHERE tno IN 
<!--ids是给SQL传递的参数Map里的key,item的值就像是for循环里的i变量名-->
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>	
</delete>

调用代码:

Map<String,Object> map = new HashMap<String,Object>();
String[] ps = {"1","22"};
map.put("ids", ps );
mapper.delete(map);

5、set

去掉最后可能多余的逗号

<update id="update">
UPDATE teachers 
<set>
		<if test="tname != null">tname=#{tname},</if>
		<if test="tsex != null">tsex=#{tsex},</if>
		<if test="tbirthday != null">tbirthday=#{tbirthday},</if>
		<if test="prof != null">prof=#{prof},</if>
		<if test="depart != null">depart=#{depart}</if>
</set>
WHERE tno=#{tno}	
</update>

六、MyBatis-接口映射方式

1、为什么使用接口映射方式

在上面的测试用例中,在调用session的方法的时候,都会传入要调用的SQL的namespace+id名称,这不是必须的。可以只传入id即可。但是,如果在mybatis的环境中有多个相同id的映射名称,就会报错。所以,一般情况下,调用方法最好还是使用namespace+id。但是,namespace+id的使用方式很容易报错,因为是string类型的,没有检查。所以,mybatis提供了一种非常好的设计方式来避免这种问题,即Mapper接口。

面向接口开发,松耦合。

2、操作步骤

2.1 修改映射文件,把namespace的值改成接口的全路径

<?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.DeptDao">
    <!-- 1. 提取SQL片段,提高复用性-->
    <sql id="cols">
        id,dname,loc
    </sql>
    <!--resultType使用了别名,因为在核心配置文件里配过了 -->
    <select id="getAll" resultType="Dept">
        select
            <include refid="cols"></include> /* 2.使用了指定的SQL片段*/
        from dept;
    </select>
    <!--查询name=java教研部 的部门信息-->
    <select id="getByName" resultType="Dept">
        select
            <include refid="cols"></include>
        from dept
        /* if用来判断,test写判断条件,满足条件才执行,不满足不执行*/
        <if test="dname != null">
             where dname = #{dname}
        </if>
    </select>

    <!--查询id是1或者是3的部门信息
        /* 可以去除条件中多余的or 或者 and关键字 */
    -->
    <select id="getByIds" resultType="Dept">
        select 
            <include refid="cols"></include>
        from dept
      where id in (
                <foreach collection="array" item="i"  separator=",">
                    #{i}/*获取了遍历得到的数据*/
                </foreach>
           )
//        <where>
 //               <if test="id!=null">
   //                 id=#{id}
 //               </if>
            or id=3
    //    </where>
    </select>

    <!--删除id是1 2 3 的部门信息-->
    <delete id="delByIds">
        /*delete from dept where id in(1,2,3) 参数写死了,最好动态解析*/
        delete from dept where id in(
            /*foreach用来遍历,collection属性的值是固定值array list map里的key
                item相当于遍历得到的数据 separator是数据间的分隔符
            */
            <foreach collection="array" item="i" separator="," >
                #{i} /*获取了遍历得到的数据*/
            </foreach>
        )
    </delete>
</mapper>

2.2 创建接口文件

创建mybatis接口:

接口文件的全路径 = Mapper.xml里namespace的值
接口中的方法名 = Mapper.xml里的SQL的id值
接口中的方法的返回值 = Mapper.xml里的SQL的resultType值

package cn.tedu.dao;

import cn.tedu.pojo.Dept;

import java.util.List;
//接口文件的全路径 = Mapper.xml里namespace的值
public interface DeptDao {
    /**
     * 获取所有
     * @return 所有部门信息
     */
    List<Dept> getAll();
    /**
     * 根据名称获取部门信息
     * @return 相关名字的部门信息
     */
    List<Dept> getByName(String name);
    List<Dept> getByIds(int[] id);
    void delByIds(int[] ids);
}

2.3 创建测试类

package cn.tedu.test;

import cn.tedu.dao.DeptDao;
import cn.tedu.pojo.Dept;
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;

public class Test2 {
    @Test
    public void get() throws IOException {
        //加载核心配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //创建会话
        SqlSession session = factory.openSession();
        //获取指定的接口
        DeptDao dao = session.getMapper(DeptDao.class);
        //调用接口里的方法
        List<Dept> list = dao.getAll();
        for (Dept dept : list) {
            System.out.println(dept);
        }
        //根据名称获取部门信息
        List<Dept> list2 = dao.getByName("开发");
        for (Dept dept : list2) {
            System.out.println(dept);
        }

        /*获取指定id是1和3的部门信息*/
        int[] array ={1,3};
        List<Dept> list2 = dao.getbyids(array);
        for (Dept dept : list2) {
            System.out.println(dept);
        }
    }
}

2.4 总结

在这里插入图片描述

七、问答题

JDBC和MyBatis的区别?


JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。

MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。

XML和接口方式的区别?


MyBatis提供了两种操作数据库的方式,一种是通过xml映射文件,一种是通过java的接口类。按面向对象方式更加推荐接口方式,但如果复杂的多表映射,仍然需要使用xml映射文件的ResultMap方式实现。

接口只是假象,其底层仍然是通过xml实现,好不容易实现了一套方式,怎忍丢掉呢?可以做个测试就知道它底层怎么实现的?把xml中的sql删除,它就玩不转了。

接口方式怎么找到xml执行的?


SqlSession的getMapper方法找到类,通过反射可以获取到类的全路径(包名.类名),相加后就定位到某个xml的命名空间namespace,在根据调用的方法去找到xml中某个标签的id属性。从而实现价值接口,调用接口的方法而间接找到xml中的标签,通过解析xml获取这个标签的内容,从而获取到sql语句。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值