Mybatis——(2)

2.2 Mybatis 工具类(了解)

为了简化MyBatis的开发,可将MyBatis进一步封装。

java 复制代码
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 java.io.IOException;
import java.io.InputStream;
/**
 * Mybatis工具类
 */
public class MybatisUtil {
    /**
     * 不让用户在外界创建工具类对象
     */
    private MybatisUtil() {
    }
    /**
    * 初始化SqlSessionFactory对象
    */
    private static SqlSessionFactory factory;
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取SqlSession对象的方法
     */
    public static SqlSession getSession() {
        return factory.openSession();
    }
}

测试:

java 复制代码
public class MybatisUtilTest {
    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtil.getSession();
        System.out.println(sqlSession);
        sqlSession.close();
    }
}

2.4 Mapper代理方式(强制)

Mapper代理开发方式只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

程序员编写Mapper接口需要遵循一些开发规范,MyBatis可以自动生成Mapper接口实现类代理对象

2.4.1 开发规范

1、Mapper.xml文件中的namespace与mapper接口的类路径相同。

2、Mapper.xml中定义的每个标签的id与Mapper接口方法名相同。

3、Mapper.xml中定义的每个sql的parameterType的类型与Mapper接口方法的参数类型相同。

4、Mapper.xml中定义的每个sql的resultType的类型与Mapper接口方法返回值类型相同。

注:Mapper.xml映射文件最好和Mapper接口名称一致。

2.4.2 实体类

java 复制代码
package org.example.mybatis.entity;
​
import java.util.Date;
​
/**
 * Emp实体类
 */
public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
​
    public Integer getEmpno() {
        return empno;
    }
​
    public void setEmpno(Integer empno) {
        this.empno = empno;
    }
​
    public String getEname() {
        return ename;
    }
​
    public void setEname(String ename) {
        this.ename = ename;
    }
​
    public String getJob() {
        return job;
    }
​
    public void setJob(String job) {
        this.job = job;
    }
​
    public Integer getMgr() {
        return mgr;
    }
​
    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }
​
    public Date getHiredate() {
        return hiredate;
    }
​
    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }
​
    public Double getSal() {
        return sal;
    }
​
    public void setSal(Double sal) {
        this.sal = sal;
    }
​
    public Double getComm() {
        return comm;
    }
​
    public void setComm(Double comm) {
        this.comm = comm;
    }
​
    public Integer getDeptno() {
        return deptno;
    }
​
    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }
​
    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", comm=" + comm +
                ", deptno=" + deptno +
                '}';
    }
}

2.4.3 Mapper接口

java 复制代码
package org.example.mybatis.mapper;
​
import org.example.mybatis.entity.Emp;
​
import java.util.List;
​
/*
 * Mapper接口相当于我们之前写的Dao接口,只是在Mybatis里面我们习惯这么写而已。
 */
public interface Mapper {
    List<Emp> select();
​
    Emp selectById(Integer empno);
​
    void insert(Emp emp);
​
    int update(Emp emp);
​
    boolean delete(Integer empno);
}

批量查询:方法返回值为List类型,表示SqlSession对象将调用selectList()方法。

单条查询:方法返回值为单个实体对象,表示SqlSession对象将调用selectOne()方法。

增删改:

方法返回值为void,表示SqlSession对象中insert,update,delete方法的返回值不做任何处理。

方法返回值为int类型,表示SqlSession对象中insert,update,delete方法的返回值直接返回。

方法返回值为boolean类型,表示根据SqlSession对象中的insert,update,delete方法返回值(影响数据库的条数)判断操作是否成功,如果影响数据库的条数大于0条,表示成功,否则表示失败。

2.4.4 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">
<!--namespace:与Mapper接口的全限定名保持一致-->
<mapper namespace="org.example.mybatis.mapper.Mapper">
    <!--
    statementId与Mapper接口的方法名称保持一致;
    parameterType的类型必须与方法的参数类型保持一致;
    resultType的类型必须与方法的返回值类型保持一致;
    -->
    <select id="select" resultType="org.example.mybatis.entity.Emp">
        select empno,
               ename,
               job,
               mgr,
               hiredate,
               sal,
               comm,
               deptno
        from emp
    </select>
    <select id="selectById" parameterType="java.lang.Integer"
            resultType="org.example.mybatis.entity.Emp">
        select empno,
               ename,
               job,
               hiredate,
               mgr,
               sal,
               comm,
               deptno
        from emp
        where empno = #{empno}
    </select>
​
    <insert id="insert" parameterType="org.example.mybatis.entity.Emp">
        insert into emp(ename, job, mgr, hiredate, sal, comm, deptno)
        values (#{ename}, #{job}, #{mgr}, #{hiredate}, #{sal}, #{comm}, #{deptno})
    </insert>
    <update id="update" parameterType="org.example.mybatis.entity.Emp">
        update emp
        set ename=#{ename}
          , job=#{job}
          , mgr=#{mgr}
          , hiredate=#{hiredate}
          , sal=# {sal},comm=#{comm}
          , deptno=#{deptno}
        where empno=#{empno}
    </update>
    <delete id="delete" parameterType="java.lang.Integer">
        delete
        from emp
        where empno = #{empno}
    </delete>
</mapper>

加载mapper文件:

复制代码
<?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">
<!-- configuration 文件的根节点 -->
<configuration>
    <!--
    properties 用于引入外部的properties配置文件
    resource:引入类路径下的文件
    url:引入磁盘或网路
    -->
    <properties/>
    <!--
    environments:多个配置环境;通过default属性可以对多个环境快速切换。
    environments default属性的值必须和某个environment的id值一致。
    -->
    <!-- 和spring整合后 environments配置将废除,了解即可 -->
    <environments default="mysql">
        <environment id="oracle">
            <!-- 配置事务:使用jdbc的事务管理 -->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源:连接数据库的信息
            type: 表示连接是否使用连接池,POOLED表示mybatis中自带的连接池;JNDI、
            POOLED、UNPOOLED
            -->
            <dataSource type="POOLED">
                <property name="driver"
                          value="oracle.jdbc.driver.OracleDriver"/>
                <property name="url"
                          value="jdbc:oracle:thin:@localhost:1521:orcl"/>
                <property name="username" value="scott"/>
                <property name="password" value="tiger"/>
            </dataSource>
        </environment>
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?
characterEncoding=utf8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
​
    <!-- 加载映射文件的位置 -->
    <mappers>
        <mapper resource="mapper/Mapper.xml"/>
    </mappers>
</configuration>

2.4.5 测试

java 复制代码
package org.example.mybatis.test;
​
import org.apache.ibatis.session.SqlSession;
import org.example.mybatis.entity.Emp;
import org.example.mybatis.mapper.Mapper;
import org.example.mybatis.utils.MybatisUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
import java.util.Date;
import java.util.List;
​
public class MapperTest {
    private SqlSession sqlSession;
    private Mapper mapper;
​
    @Before
    public void before() {
        sqlSession = MybatisUtil.getSession();
        //获取Mapper接口的代理对象
        mapper = sqlSession.getMapper(Mapper.class);
    }
​
    @After
    public void after() {
        sqlSession.commit();
        sqlSession.close();
    }
​
    @Test
    public void test() {
        System.out.println(sqlSession);
        System.out.println(mapper);
    }
​
    @Test
    public void testSelect() {
        List<Emp> list = mapper.select();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }
​
    @Test
    public void testSelectById() {
        Emp emp = mapper.selectById(7938);
        System.out.println(emp);
    }
​
    @Test
    public void testInsert() {
        Emp emp = new Emp();
        emp.setEname("小明");
        emp.setJob("职员");
        emp.setSal(4500.0);
        emp.setComm(1000.0);
        emp.setMgr(1);
        emp.setHiredate(new Date());
        mapper.insert(emp);
    }
​
    @Test
    public void testUpdate() {
        Emp emp = new Emp();
        emp.setEmpno(7940);
        emp.setEname("小李");
        emp.setJob("秘书");
        emp.setSal(5300.0);
        emp.setComm(1300.0);
        emp.setMgr(1);
        emp.setHiredate(new Date());
        int result = mapper.update(emp);
        System.out.println("方法的返回值:" + result);
    }
​
    @Test
    public void testDelete() {
        boolean result = mapper.delete(7940);
        System.out.println("方法的返回值:" + result);
    }
}

三、Mybatis 核心配置文件(了解)

MyBatis的全局配置文件mybatis-config.xml,配置内容如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

四、Mybatis Mapper配置文件

mapper.xml映射文件中定义了操作数据库的Sql,每个Sql是一个statement,映射文件是MyBatis的核心。

4.1 parameterType输入映射(强制)

parameterType配置输入参数的类型。

4.1.1 表结构

复制代码
CREATE TABLE `users` (
`id` int(11) PRIMARY KEY AUTO_INCREMENT,
`username` varchar(20),
`password` varchar(50),
`realname` varchar(20)
);
INSERT INTO `users` VALUES (1, 'admin', '123456', '管理员');
INSERT INTO `users` VALUES (2, 'tom', '123', '汤姆');
INSERT INTO `users` VALUES (3, 'jerry', '456', '杰瑞');
INSERT INTO `users` VALUES (4, 'zhangsan', '111', '张三');
INSERT INTO `users` VALUES (5, 'lisi', '222', '李四');

4.1.2 实体类

java 复制代码
package org.example.mybatis.entity;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String realname;

    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 getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }

    @Override
    public String toString() {
        return "Users{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", realname='" + realname + '\'' +
                '}';
    }
}

4.1.3 简单类型

Java基本数据类型以及包装类,String字符串类型。

mapper接口:

java 复制代码
package org.example.mybatis.mapper;

import org.example.mybatis.entity.Users;

import java.util.List;

public interface UsersMapper {
    List<Users> selectByRealname(String realname);
}

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="org.example.mybatis.mapper.UsersMapper">
    <select id="selectByRealname" parameterType="java.lang.String"
            resultType="org.example.mybatis.entity.Users">
        select id, username, password, realname
        from users
        where realname like
              concat('%', #{realname}, '%')
    </select>
</mapper>

测试:

java 复制代码
package org.example.mybatis.test;

import org.apache.ibatis.session.SqlSession;
import org.example.mybatis.entity.Users;
import org.example.mybatis.mapper.UsersMapper;
import org.example.mybatis.utils.MybatisUtil;
import org.junit.Test;

import java.util.List;

public class ParameterTypeTest {
    @Test
    public void testSimpleParam() {
        SqlSession sqlSession = MybatisUtil.getSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        List<Users> list = usersMapper.selectByRealname("张");
        for (Users users : list) {
            System.out.println(users);
        }
        sqlSession.close();
    }
}

4.1.4 实体类或自定义类型

开发中通过实体类或pojo类型传递查询条件,查询条件是综合的查询条件,不仅包括实体类中查询条件

还包括其它的查询条件,这时可以使用包装对象传递输入参数。

4.1.4.1 自定义类型

分页类:

java 复制代码
package org.example.mybatis.entity;

public class Page {
    //当前页码
    private Integer pageNum = 1;
    //每页条数
    private Integer pageSize = 3;
    //总页数: 总记录数/每页条数,除不尽+1
    private Integer pages;
    //总记录数
    private Integer total;
    /**
     * mysql
     * 起始偏移量:(当前页码-1)*每页条数
     */
    private Integer offset;

    /**
     * oracle
     * 起始条数:(当前页码-1)*每页条数+1
     * 结束条数: 当前页码*每页条数
     */
    private Integer start;
    private Integer end;

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getPages() {
        return getTotal() % getPageSize() == 0 ? getTotal() / getPageSize() :
                getTotal() / getPageSize() + 1;
    }

    public void setPages(Integer pages) {
        this.pages = pages;
    }

    public Integer getTotal() {
        return total;
    }

    public void setTotal(Integer total) {
        this.total = total;
    }

    public Integer getOffset() {
        return (getPageNum() - 1) * getPageSize();
    }

    public void setOffset(Integer offset) {
        this.offset = offset;
    }

    public Integer getStart() {
        return (getPageNum() - 1) * getPageSize() + 1;
    }

    public void setStart(Integer start) {
        this.start = start;
    }

    public Integer getEnd() {
        return getPageNum() * getPageSize();
    }

    public void setEnd(Integer end) {
        this.end = end;
    }
}

复合类:UsersQuery

java 复制代码
package org.example.mybatis.entity;

/**
 * 多条件查询复合类
 */
public class UsersQuery {
    private Users users;
    private Page page;

    public Users getUsers() {
        return users;
    }

    public void setUsers(Users users) {
        this.users = users;
    }

    public Page getPage() {
        return page;
    }

    public void setPage(Page page) {
        this.page = page;
    }
}
4.1.4.2 mapper接口
java 复制代码
// 在UsersMapper接口上增加
List<Users> selectByPage(Page page);

List<Users> selectByRealnameAndPage(UsersQuery usersQuery);
4.1.4.3 mapper文件
复制代码
<select id="selectByPage" parameterType="org.example.mybatis.entity.Page"
        resultType="org.example.mybatis.entity.Users">
    select id,username,password,realname from users order by id limit #{offset}, #{pageSize}
</select>
<select id="selectByRealnameAndPage" parameterType="org.example.mybatis.entity.UsersQuery"
        resultType="org.example.mybatis.entity.Users">
    select id,username,password,realname from users
    where realname like concat('%',#{users.realname},'%')
    order by id limit #{page.offset}, #{page.pageSize}
</select>
4.1.4.4 测试
java 复制代码
package org.example.mybatis.test;

import org.apache.ibatis.session.SqlSession;
import org.example.mybatis.entity.Page;
import org.example.mybatis.entity.Users;
import org.example.mybatis.entity.UsersQuery;
import org.example.mybatis.mapper.UsersMapper;
import org.example.mybatis.utils.MybatisUtil;
import org.junit.Test;

import java.util.List;

public class ClassParamTests {
    @Test
    public void testClassParam1() {
        SqlSession sqlSession = MybatisUtil.getSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Page page = new Page();
        page.setPageNum(1);
        System.out.println("mysql起始偏移量:" + page.getOffset());
        System.out.println("起始条数:" + page.getStart());
        System.out.println("结束条数:" + page.getEnd());
        List<Users> list = usersMapper.selectByPage(page);
        for (Users users : list) {
            System.out.println(users);
        }
        sqlSession.close();
    }
    @Test
    public void testPojoParam2() {
        SqlSession sqlSession = MybatisUtil.getSession();
        UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
        Page page = new Page();
        page.setPageNum(1);
        Users users = new Users();
        users.setRealname("张");
        UsersQuery usersQuery = new UsersQuery();
        usersQuery.setPage(page);
        usersQuery.setUsers(users);
        List<Users> list = usersMapper.selectByRealnameAndPage(usersQuery);
        for (Users u : list) {
            System.out.println(u);
        }
        sqlSession.close();
    }
}

4.1.5 Map类型

mapper接口:

java 复制代码
// 在UsersMapper接口上增加
List<Users> selectUseMap(Map<String, Object> map)

mapper文件:

复制代码
<select id="selectUseMap" parameterType="java.util.HashMap" resultType="org.example.mybatis.entity.Users">
    select id,username,password,realname from users
    where realname like concat('%',#{name},'%')
    order by id limit #{begin}, #{size}
</select>

测试:

java 复制代码
@Test
public void testMapParam() {
    SqlSession sqlSession = MybatisUtil.getSession();
    UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("name", "李");
    map.put("size", 5);
    map.put("begin", 0);
    List<Users> list = usersMapper.selectUseMap(map);
    for (Users u : list) {
        System.out.println(u);
    }
    sqlSession.close();
}

4.1.6 多输入参数

MyBatis中允许有多个输入参数,可使用@Param注解。

这种做法类似与Map类型的输入参数,其中@Param注解的value属性值为Map的key,在映射文件中通

过ognl可获取对应的value,并且parameterType可以不指定类型。

mapper接口:

复制代码
Users login(@Param("uname") String username, @Param("pwd") String password);

mapper文件:

复制代码
<select id="login" parameterType="java.util.HashMap" resultType="org.example.mybatis.entity.Users">
    select id,username,password,realname from users
    where username=#{uname} and password=#{pwd}
</select>

测试:

java 复制代码
@Test
public void testMultiParam() {
	SqlSession sqlSession = MybatisUtil.getSession();
	UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);

	Users users = usersMapper.login("jerry", "456");
	System.out.println(users);
	sqlSession.close();
}

4.2 resultType输出映射(强制)

4.2.1 表结构

复制代码
CREATE TABLE `person` (
`id` int(11) PRIMARY KEY AUTO_INCREMENT,
`person_name` varchar(20),
`person_age` int(4),
`person_address` varchar(50)
);
INSERT INTO `person` VALUES (1, '曹操', 40, '洛阳');
INSERT INTO `person` VALUES (2, '刘备', 38, '成都');
INSERT INTO `person` VALUES (3, '孙权', 29, '杭州');
INSERT INTO `person` VALUES (4, '关羽', 35, '荆州');
INSERT INTO `person` VALUES (5, '张飞', 32, '成都');
INSERT INTO `person` VALUES (6, '曹仁', 28, '许都');

4.2.2 实体类

java 复制代码
package org.example.mybatis.entity;

public class Person {
    private Integer id;
    private String personName;
    private Integer personAge;
    private String personAddress;

    public Integer getId() {
        return id;
    }

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

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    public Integer getPersonAge() {
        return personAge;
    }

    public void setPersonAge(Integer personAge) {
        this.personAge = personAge;
    }

    public String getPersonAddress() {
        return personAddress;
    }

    public void setPersonAddress(String personAddress) {
        this.personAddress = personAddress;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", personName='" + personName + '\'' +
                ", personAge=" + personAge +
                ", personAddress='" + personAddress + '\'' +
                '}';
    }
}

4.2.3 简单类型

查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。

mapper接口:

java 复制代码
package org.example.mybatis.mapper;

public interface PersonMapper {
    // 查询Person的总数量
    Integer selectCount();
}

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="org.example.mybatis.mapper.PersonMapper">
    <select id="selectCount" resultType="java.lang.Integer">
        select count(1) from person
    </select>
</mapper>

测试:

java 复制代码
package org.example.mybatis.test;

import org.apache.ibatis.session.SqlSession;
import org.example.mybatis.mapper.PersonMapper;
import org.example.mybatis.utils.MybatisUtil;
import org.junit.Test;

public class ResultTypeTest {

    @Test
    public void testSimpleResult() {
        SqlSession sqlSession = MybatisUtil.getSession();
        PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
        int total = personMapper.selectCount();
        System.out.println("总记录数:" + total);
        sqlSession.close();
    }
}

4.2.4 实体类对象和列表

不管是输出的实体类是单个对象还是一个列表(list中包括实体类对象),在mapper.xml中resultType指定的类型是一样的。

在原始Dao的方式中,通过selectOne和selectList方法来区分返回值为单个对象或集合列表,而在mapper代理中,则通过接口中定义的方法返回值来区分。

mapper接口:

java 复制代码
    Person selectById(Integer id);
    List<Person> selectAll();

mapper文件:

复制代码
<select id="selectById" parameterType="java.lang.Integer" resultType="org.example.mybatis.entity.Person">
    select id,person_name personName,person_age personAge,person_address
                          personAddress from person where id=#{id}
</select>

<select id="selectAll" resultType="org.example.mybatis.entity.Person">
    select id,person_name personName,person_age personAge,person_address
                          personAddress from person
</select>

测试:

java 复制代码
@Test
public void testResultType1() {
    SqlSession sqlSession = MybatisUtil.getSession();
    PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
    Person person = personMapper.selectById(1);
    System.out.println(person);
    sqlSession.close();
}

@Test
public void testResultType2() {
    SqlSession sqlSession = MybatisUtil.getSession();
    PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
    List<Person> list = personMapper.selectAll();
    for (Person person : list) {
        System.out.println(person);
    }
    sqlSession.close();
}

4.2.5 resultMap

resultType可以指定将查询结果映射为实体类,但需要实体类的属性名和SQL查询的列名一致方可映射成功,当然如果开启下划线转驼峰 或 Sql设置列别名,也可以自动映射。

如果SQL查询字段名和实体类的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还会将查询结果映射到实体类对象中。

resultMap可以实现将查询结果映射为复合型的实体类,比如在查询结果映射对象中包括实体类和list实现一对一查询和一对多查询。

mapper接口:

java 复制代码
List<Person> selectAll();

**mapper文件:**使用resultMap作为statement的输出映射类型。

复制代码
<resultMap id="selectResultMap" type="org.example.mybatis.entity.Person">
    <id property="id" column="id"/>
    <result property="personName" column="person_name"/>
    <result property="personAge" column="person_age"/>
    <result property="personAddress" column="person_address"/>
</resultMap>
<select id="select" resultMap="selectResultMap">
    select id,person_name,person_age,person_address from person
</select>

resultType: 自动映射。

resultMap: 手动映射。

id: 唯一标识,名称;

type: 手动映射的java类型;

子标签 <id/> 配置数据库表中的主键和实体类中属性的对应关系;

子标签 <result/> 配置数据库表中的普通字段和实体类中属性的对应关系;

property:实体类中的成员变量名;

column:结果集中的字段名称;

javaType:实体类成员变量的类型,由mybaits自动识别,可不配置;

jdbcType:表字段的类型,由mybaits自动识别,可不配置;

typeHandler:自定义类型处理器,用的相对比较少;

测试:

java 复制代码
@Test
public void testResultMap() {
	SqlSession sqlSession = MybatisUtil.getSession();
	PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
	List<Person> list = personMapper.select();
	for (Person person : list) {
		System.out.println(person);
	}
	sqlSession.close();
}

4.3 动态SQL(强制)

4.3.1 什么是动态SQL

动态Sql是指MyBatis对Sql语句进行灵活操作,通过表达式进行判断,对Sql进行灵活拼接、组装。

比如:

我们要查询姓名中带 M 和 高于 1000的员工信息;

可能有时候我们需要不带条件查询;

可能有时候我们需要模糊查询;

可能有时候需要根据多条件查询;

动态SQL可以帮助我们解决这些问题。

通过Mybatis提供的各种标签方法实现动态拼接sql。

4.3.2 if标签

判断标签,当参数符合判断条件拼接SQL语句。

实体类:

java 复制代码
package org.example.mybatis.entity;

import java.util.Date;

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
    private String gender;

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Integer getMgr() {
        return mgr;
    }

    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Double getComm() {
        return comm;
    }

    public void setComm(Double comm) {
        this.comm = comm;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", comm=" + comm +
                ", deptno=" + deptno +
                ", gender='" + gender + '\'' +
                '}';
    }
}

mapper接口:

java 复制代码
package org.example.mybatis.mapper;

import org.example.mybatis.entity.Emp;

import java.util.List;

public interface EmpMapper {

    List<Emp> selectUseIf(Emp emp);
}

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="org.example.mybatis.mapper.EmpMapper">
    <select id="selectUseIf" parameterType="org.example.mybatis.entity.Emp"
            resultType="org.example.mybatis.entity.Emp">
        select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
        where
        <!--
        注意:判断条件中使用的变量为实体类或输入参数的属性
        空字符串的判断仅能使用在字符串类型的属性中
        -->
        <if test="ename != null and ename != ''">
            ename like concat('%',#{ename},'%')
        </if>
        <if test="sal != null">
            and sal=#{sal}
        </if>
        <if test="deptno != null">
            and deptno=#{deptno}
        </if>
    </select>
</mapper>

测试:

java 复制代码
package org.example.mybatis.test;

import org.apache.ibatis.session.SqlSession;
import org.example.mybatis.entity.Emp;
import org.example.mybatis.mapper.EmpMapper;
import org.example.mybatis.utils.MybatisUtil;
import org.junit.Test;

import java.util.List;

/*
 * 动态sql测试
 */
public class DynamicSqlTest {

    @Test
    public void testIf() {
        SqlSession sqlSession = MybatisUtil.getSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = new Emp();
        emp.setEname("S");
        emp.setSal(1300.0);
        emp.setDeptno(20);
        List<Emp> list = empMapper.selectUseIf(emp);
        for (Emp e : list) {
            System.out.println(e);
        }
        sqlSession.close();
    }
}

4.3.3 where标签

where标签,替代where关键字。

  1. 当where标签内所有的条件都不成立,不会拼接where关键字,只要有一个条件成立就会在SQL语句中拼接where关键字。

  2. where标签会自动剔除条件头部的and或者or关键字。

mapper接口:

java 复制代码
List<Emp> selectUseWhere(Emp emp);

mapper文件:

复制代码
<select id="selectUseWhere" parameterType="org.example.mybatis.entity.Emp"
        resultType="org.example.mybatis.entity.Emp">
    select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
    <where>
        <if test="ename != null and ename != ''">
            ename like concat('%',#{ename},'%')
        </if>
        <if test="sal != null">
            and sal=#{sal}
        </if>
        <if test="deptno != null">
            and deptno=#{deptno}
        </if>
    </where>
</select>

测试:

java 复制代码
@Test
public void testWhere() {
    SqlSession sqlSession = MybatisUtil.getSession();
    EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = new Emp();
    emp.setEname("S");
    emp.setSal(1300.0);
    emp.setDeptno(20);
    List<Emp> list = empMapper.selectUseWhere(emp);
    for (Emp e : list) {
        System.out.println(e);
    }
    sqlSession.close();
}

4.3.4 set标签

set标签,替代set关键字。

  1. 当set标签内所有的条件都不成立,不会拼接set关键字,只要有一个条件成立就会在SQL语句中拼接set关键字。

注意:如果set包含的内容为空SQL语句会出错。

  1. set标签会自动剔除条件末尾的任何不相关的逗号。

mapper接口:

java 复制代码
void updateUseSet(Emp emp);

mapper文件:

复制代码
<update id="updateUseSet" parameterType="org.example.mybatis.entity.Emp">
    update emp
    <set>
        <if test="ename != null">
            ename=#{ename},
        </if>
        <if test="job != null">
            job=#{job},
        </if>
        <if test="mgr != null">
            mgr=#{mgr},
        </if>
        <if test="hiredate != null">
            hiredate=#{hiredate},
        </if>
        <if test="sal != null">
            sal=#{sal},
        </if>
        <if test="comm != null">
            comm=#{comm},
        </if>
        <if test="deptno != null">
            deptno=#{deptno},
        </if>
    </set>
    where empno=#{empno}
</update>

测试:

java 复制代码
@Test
public void testSet() {
	SqlSession sqlSession = MybatisUtil.getSession();
	EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
    
	Emp emp = new Emp();
	emp.setEmpno(7938);
	emp.setEname("JACK");
	emp.setJob("MANAGER");
	emp.setMgr(7844);
	emp.setSal(5600.0);
	emp.setComm(1200.0);
	emp.setHiredate(new Date());
	emp.setDeptno(30);
	empMapper.updateUseSet(emp);
	sqlSession.commit();
	sqlSession.close();
}

4.3.5 trim标签

trim标签属性解析:

prefix:前缀,包含内容前加上某些字符。

suffix:后缀,包含内容后加上某些字符。

prefixOverrides:剔除包含内容前的某些字符。

suffixOverrides:剔除包含内容后的某些字符。

4.3.5.1 mapper接口
java 复制代码
void insertUseTrim(Emp emp);
4.3.5.2 mapper文件
复制代码
<!--trim标签-->
    <insert id="insertUseTrim" parameterType="org.example.mybatis.entity.Emp">
        insert into emp
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="ename != null">
                ename,
            </if>
            <if test="job != null">
                job,
            </if>
            <if test="mgr != null">
                mgr,
            </if>
            <if test="hiredate != null">
                hiredate,
            </if>
            <if test="sal != null">
                sal,
            </if>
            <if test="comm != null">
                comm,
            </if>
            <if test="deptno != null">
                deptno,
            </if>
        </trim>
        <trim prefix=" values(" suffix=")" suffixOverrides=",">
            <if test="ename != null">
                #{ename},
            </if>
            <if test="job != null">
                #{job},
            </if>
            <if test="mgr != null">
                #{mgr},
            </if>
            <if test="hiredate != null">
                #{hiredate},
            </if>
            <if test="sal != null">
                #{sal},
            </if>
            <if test="comm != null">
                #{comm},
            </if>
            <if test="deptno != null">
                #{deptno},
            </if>
        </trim>
    </insert>
4.3.5.3 测试
java 复制代码
@Test
public void testTrim() {
	SqlSession sqlSession = MybatisUtil.getSession();
	EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

	Emp emp = new Emp();
	emp.setEname("CHRIS");
	emp.setJob("CLERK");
	emp.setMgr(1);
	emp.setSal(3400.0);
	emp.setComm(800.0);
	emp.setHiredate(new Date());
	emp.setDeptno(10);
	empMapper.insertUseTrim(emp);
	sqlSession.commit();
	sqlSession.close();
}
4.3.5.4 代替where标签
复制代码
<select id="selectUseTrim" parameterType="org.example.mybatis.entity.Emp" resultType="org.example.mybatis.entity.Emp">
    select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
    <trim prefix="where" prefixOverrides="and|or">
        <if test="ename != null and ename != ''">
            ename like concat('%',#{ename},'%')
        </if>
        <if test="sal != null">
            and sal=#{sal}
        </if>
        <if test="deptno != null">
            and deptno=#{deptno}
        </if>
    </trim>
</select>
4.3.5.5 代替set标签
复制代码
    <!--代替set标签-->
    <update id="updateUseTrim" parameterType="org.example.mybatis.entity.Emp">
        update emp
        <trim prefix="set" suffixOverrides=",">
            <if test="ename != null">
                ename=#{ename},
            </if>
            <if test="job != null">
                job=#{job},
            </if>
            <if test="mgr != null">
                mgr=#{mgr},
            </if>
            <if test="hiredate != null">
                hiredate=#{hiredate},
            </if>
            <if test="sal != null">
                sal=#{sal},
            </if>
            <if test="comm != null">
                comm=#{comm},
            </if>
            <if test="deptno != null">
                deptno=#{deptno},
            </if>
        </trim>
        where empno=#{empno}
    </update>

4.3.6 foreach标签

向SQL传递数组或list,MyBatis使用foreach解析。

属性解析:

collection: 遍历的数组或集合对象名称。

SQL只接收一个数组参数,这时SQL解析参数的名称MyBatis固定为array。

SQL只接收一个List参数,这时SQL解析参数的名称MyBatis固定为list。

如果是通过一个实体类或自定义类型的属性传递到SQL的数组或List集合,则参数的名称为实体类或自定义类型中的属性名。

index: 为数组的下标。

item: 每次遍历生成的对象。

open: 开始遍历时拼接的串。

close: 结束遍历时拼接的串。

separator: 遍历的两个对象中需要拼接的串。

mapper接口:

java 复制代码
void deleteUseForeach(Integer[] ids);
void insertUseForeach(List<Emp> empList);

mapper文件:

复制代码
    <!--foreach标签-->
    <delete id="deleteUseForeach" parameterType="java.lang.Integer">
        <!--delete from emp where empno in (1,2,3,4)-->
        delete from emp where empno in
        <foreach collection="array" open="(" close=")" separator="," item="id">
            #{id}
        </foreach>
    </delete>

    <insert id="insertUseForeach" parameterType="org.example.mybatis.entity.Emp">
        insert into emp(ename,job,mgr,hiredate,sal,comm,deptno) values
        <foreach collection="list" separator="," item="emp">
            (#{emp.ename},#{emp.job},#{emp.mgr},#{emp.hiredate},#{emp.sal},#{emp.comm},#{emp.deptno})
        </foreach>
    </insert>

测试:

java 复制代码
    @Test
    public void testForeach() {
        SqlSession sqlSession = MybatisUtil.getSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        empMapper.deleteUseForeach(new Integer[]{1, 2, 3, 4});
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void testForeach2() {
        SqlSession sqlSession = MybatisUtil.getSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        List<Emp> empList = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            Emp emp = new Emp();
            emp.setEname("TOM" + i);
            emp.setJob("CLERK" + i);
            emp.setMgr(1);
            emp.setSal(4567.0);
            emp.setComm(123.0);
            emp.setHiredate(new Date());
            emp.setDeptno(10);
            empList.add(emp);
        }
        empMapper.insertUseForeach(empList);
        sqlSession.commit();
        sqlSession.close();
    }

4.3.7 choose标签

choose标签、when标签、otherwise标签的组合,类似于if-else-if判断。

复制代码
<select id="">
	select...
	<choose>
		<when test="">
		
		</when>
		<when test="">
		
		</when>
		<otherwise>
		
		</otherwise>
	</choose>
</select>

4.3.8 SQL片段

将实现的动态SQL判断代码块抽取出来,组成一个SQL片段,其它的statement中就通过 <include> 标

签就可以引用SQL片段,方便程序员进行开发。

注意:在SQL片段中不要包括where标签。

复制代码
    <sql id="feildSql">
        empno
        ,ename,job,mgr,hiredate,sal,comm,deptno
    </sql>
    <sql id="whereSql">
        <if test="ename != null and ename != ''">
            ename like concat('%',#{ename},'%')
        </if>
        <if test="sal != null">
            and sal=#{sal}
        </if>
        <if test="deptno != null">
            and deptno=#{deptno}
        </if>
    </sql>
    <select id="selectUseSql" parameterType="org.example.mybatis.entity.Emp"
            resultType="org.example.mybatis.entity.Emp">
        select
        <include refid="feildSql"></include>
        from emp
        <where>
            <include refid="whereSql"></include>
        </where>
    </select>

4.4 Map输入和输出类型(强制)

实体类:

java 复制代码
package org.example.mybatis.entity;

public class Dept {
    private Integer deptno;
    private String dname;
    private String loc;


    public Dept() {
    }

    public Dept(Integer deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }

    /**
     * 获取
     * @return deptno
     */
    public Integer getDeptno() {
        return deptno;
    }

    /**
     * 设置
     * @param deptno
     */
    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    /**
     * 获取
     * @return dname
     */
    public String getDname() {
        return dname;
    }

    /**
     * 设置
     * @param dname
     */
    public void setDname(String dname) {
        this.dname = dname;
    }

    /**
     * 获取
     * @return loc
     */
    public String getLoc() {
        return loc;
    }

    /**
     * 设置
     * @param loc
     */
    public void setLoc(String loc) {
        this.loc = loc;
    }

    public String toString() {
        return "Dept{deptno = " + deptno + ", dname = " + dname + ", loc = " + loc + "}";
    }
}

Mapper接口:

java 复制代码
package org.example.mybatis.mapper;

import java.util.List;
import java.util.Map;

public interface DeptMapper {
    //查询
    List<Map<String, Object>> queryAllDept();

    //插入
    int insertDept(Map<String, Object> map);
}

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="org.example.mybatis.mapper.DeptMapper">
    <!--
        查询,输出参数是Map
        Mybatis会把查询结果给我们封装成List<Map>
        因为一行数据就是一个Map
    -->
    <select id="queryAllDept" resultType="hashmap">
        select *
        from dept
    </select>
    <!--插入,输入参数是Map-->
    <!--输入参数是hashmap,那么#{map中的key}-->
    <insert id="insertDept" parameterType="hashmap">
        insert into dept
        values (#{id}, #{name}, #{address})
    </insert>
</mapper>

测试:

java 复制代码
    @Test
    public void testMapResultType(){
// 获取Mapper接口的代理对象 (相当于实现类对象)
        SqlSession sqlSession = MybatisUtil.getSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
//我们的输出参数是hashMap,那么mybatis会把查询结果集的列作为key,值作为value
        List<Map<String, Object>> maps = mapper.queryAllDept();
        for(Map<String, Object> map:maps){
            System.out.println(map.get("DEPTNO")+"\t"+map.get("DNAME")+"\t"+map.get("LOC"))
            ;
        }
        sqlSession.close();
    }
    @Test
    public void testMapParameter(){
// 获取Mapper接口的代理对象 (相当于实现类对象)
        SqlSession sqlSession = MybatisUtil.getSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("id",50);
        map.put("name","开发部门");
        map.put("address","北京市");
        int i = mapper.insertDept(map);
        System.out.println(i);
        sqlSession.close();
    }
相关推荐
gb42152875 分钟前
java中sha256和md5某个字符串实例代码
java·开发语言·哈希算法
三十六煩惱風6 分钟前
Java中常见的锁及其应用场景
java
Watermelon_Mr40 分钟前
Spring(二)AOP、切入点表达式、AspecJ常用通知的类型、Spring中的事务管理
java·后端·spring
出发行进1 小时前
Maven的介绍以及安装,仓库的使用和在idea使用maven
java·大数据·数据分析·maven
zhrb1 小时前
Maven简要使用说明:在IDEA中创建一个基于POI的处理Excel文件的简单Java Maven项目...
java·ide·maven·intellij-idea·excel
六千江山1 小时前
Redis bitmaps 使用
java·数据库·redis·缓存
zyxzyx6661 小时前
Redisson实现分布式锁
java·笔记·分布式·后端·spring cloud
程序员zzj1 小时前
0基础学java之Day29(单例模式、死锁)
java
cwtlw1 小时前
SpringMVC的使用
java·开发语言·笔记·学习·其他
RemainderTime1 小时前
(四)Spring Cloud Alibaba 2023.x:高效构建 Gateway 网关服务
后端·spring·spring cloud·微服务