Java之MyBatis【IDEA版】(一篇文章精通系列)增删改查【XML开发】 - 所有知识点(大全)

x33g5p2x  于2021-09-19 转载在 Java  
字(35.6k)|赞(0)|评价(0)|浏览(575)

下一篇文章地址:Java之MyBatis【IDEA版】(一篇文章精通系列)增删改查【注解开发】 - 所有知识点(大全)

一、Mybatis简介

mybatis 是一个优秀的基于java的持久层框架,
它内部封装了jdbc,使开发者只需要关注sql语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
*
mybatis通过xml或注解的方式将要执行的各种 statement配置起来,
并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
*
最后mybatis框架执行sql并将结果映射为java对象并返回。
采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,
屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,
就可以完成对数据库的持久化操作。

二、Mybatis的快速入门

MyBatis官网地址:http://www.mybatis.org/mybatis-3/

MyBatis开发步骤:

  • 添加MyBatis的坐标
  • 创建user数据表
  • 编写User实体类
  • 编写映射文件UserMapper.xml
  • 编写核心文件SqlMapConfig.xml
  • 编写测试类

1、项目搭建

2、环境搭建

(1)导入MyBatis的坐标和其他相关坐标

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.itbluebox</groupId>
    <artifactId>spring-mybatis</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
        <!--mybatis坐标-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--mysql驱动坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>

        <!--单元测试坐标-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--日志坐标-->
        <dependency>
        <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

    </dependencies>

</project>
(2) 创建user数据表

(3) 编写User实体

package cn.itbluebox.domain;

public class User {

    private int id;
    private String username;
    private String password;

    public User() {
    }

    public User(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
(4)创建数据库相关配置文件
  • 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">
<mapper namespace="userMapper">

    <!--根据id进行查询-->
    <select id="findById" resultType="user" parameterType="int">
        select * from user where id=#{id}
    </select>

</mapper>
  • jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
  • sqlMapConfig.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">
<configuration>

    <!--通过properties标签加载外部properties文件-->
    <properties resource="jdbc.properties"></properties>

    <!--自定义别名-->
    <typeAliases>
        <typeAlias type="cn.itbluebox.domain.User" alias="user"></typeAlias>
    </typeAliases>

    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="cn/itbluebox/mapper/UserMapper.xml"></mapper>
    </mappers>

</configuration>

3、编写测试代码

//加载核心配置文件
InputStream resourceAsStream = 
Resources.getResourceAsStream("SqlMapConfig.xml");
//获得sqlSession工厂对象
SqlSessionFactory sqlSessionFactory = 
new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
List<User> userList = sqlSession.selectList("userMapper.findAll");
//打印结果
System.out.println(userList);
//释放资源
sqlSession.close();

4、MyBatis开发步骤:

添加MyBatis的坐标
创建user数据表
编写User实体类
编写映射文件UserMapper.xml
编写核心文件SqlMapConfig.xml
编写测试类
先在数据库当中插入一些数据

三、MyBatis的映射文件概述

四、MyBatis的增删改查

1、MyBatis的插入数据操作

(1)编写UserMapper映射文件

<?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="userMapper">

    <!--根据id进行查询-->
    <insert id="add" parameterType="cn.itbluebox.domain.User">
        insert into user values (#{id},#{username},#{password})
    </insert>

</mapper>
(2)编写插入实体User的代码

package cn.itbluebox.test;

import cn.itbluebox.domain.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.Test;
import java.io.IOException;
import java.io.InputStream;

public class MyBatisTest {

    @Test
    //插入一个对象
    public void test1()throws IOException {
        //获得核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获得session回话对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行操作,参数:namespace+id
        int insert  = sqlSession.insert("userMapper.add", new User(1, "zhangsan", "2121212"));
        //打印数据
        System.out.println(insert);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }
}

(3)插入操作注意问题
  • 插入语句使用insert标签
  • 在映射文件当中使用parmeterType属性指定要插入的数据类型
  • Sql语句中使用/#{实体属性名}方式引用实体的属性值
  • 插入操作使用的是API是sqlSession.insert("命名空间.id",实体对象);
  • 插入操作涉及数据库变化,所以要使用sqlSession对象显示的提交事务
    sqlSession.commit()

2、MyBatis的修改数据操作

(1)编写UserMapper映射文件

<update id="update" parameterType="cn.itbluebox.domain.User">

        update user set username = #{username},password = #{password} where id = #{id}

    </update>
(2)编写修改实体User的代码

@Test
    //修改实体User的代码
    public void testUpdateUser()throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = new User();
        user.setId(1);
        user.setUsername("张三丰");
        user.setPassword("12121212121212");

        int update = sqlSession.update("userMapper.update", user);
        System.out.println(update);
        sqlSession.commit();
        sqlSession.close();

    }
(3)运行测试

(4)修改操作注意问题

修改语句使用update标签
修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);

3、MyBatis的删除数据操作

(1)编写UserMapper映射文件

MyBatis的parameterType传入参数类型

<delete id="delete" parameterType="java.lang.Integer">
        delete from user where id = #{id}
    </delete>
(2)编写删除数据的代码

@Test
    //删除User
    public void testDeleteUser() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory  = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        int delete = sqlSession.delete("userMapper.delete",1);
        System.out.println(delete);
        sqlSession.commit();
        sqlSession.close();
    }

删除成功

(3)删除操作注意问题

删除语句使用delete标签

Sql语句中使用/#{任意字符串}方式引用传递的单个参数

删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

4、MyBatis的查询数据查询所有

数据库当中插入一些数据

(1)编写UserMapper映射文件

<!--查询操作-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
(2)编写查询所有数据的代码

@Test
    //查询所有shuju
    public void testFindAllUser() throws  IOException{
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //创建作用域工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取会话对象
        SqlSession sqlSession = sessionFactory.openSession();
        List<User> users = sqlSession.selectList("userMapper.findAll");
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.commit();
        sqlSession.close();
    }

运行结果

(3)添加条件

<!--查询操作-->
    <select id="findAllByname" resultType="user" parameterType="cn.itbluebox.domain.User">

        select * from user where username like "%" #{username}  "%"
    </select>

@Test
    //查询所有shuju
    public void testFindAllUserByName() throws  IOException{
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //创建作用域工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取会话对象
        SqlSession sqlSession = sessionFactory.openSession();

        User user = new User();
        user.setUsername("张");
        List<User> users = sqlSession.selectList("userMapper.findAllByname",user);
        for (User us : users) {
            System.out.println(us);
        }
        sqlSession.commit();
        sqlSession.close();
    }

运行测试

5、MyBatis的查询数据查询一个

(1)编写UserMapper映射文件

<!--查询操作-->
    <select id="findById" resultType="user" parameterType="java.lang.Integer">

        select * from user where id = #{id} 
    </select>
(2)编写查询一个数据的代码

@Test
    //查询一个对象
    public void testFindUserOne() throws IOException {

        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //创建作用域工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取会话对象
        SqlSession sqlSession = sessionFactory.openSession();

        User user = sqlSession.selectOne("userMapper.findById", 1);

        System.out.println(user);

        sqlSession.commit();
        sqlSession.close();
    }

运行测试

6、知识小结

五、MyBatis核心配置文件概述

1、MyBatis核心配置文件层级关系

2、MyBatis常用配置解析

(1)environments标签

数据库环境的配置,支持多环境配置

其中,事务管理器(transactionManager)类型有两种:

JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,
它依赖于从数据源得到的连接来管理事务作用域。
*
MANAGED:这个配置几乎没做什么。

它从来不提交或回滚一个连接,
而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。

默认情况下它会关闭连接,然而一些容器并不希望这样,
因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。

其中,数据源(dataSource)类型有三种:

UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
*
POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
*
JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,
容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

(2)mapper标签
该标签的作用是加载映射的,加载方式有如下几种:
使用相对于类路径的资源引用,例如:
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
使用完全限定资源定位符(URL),例如:
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
使用映射器接口实现类的完全限定类名,例如:
<mapper class="org.mybatis.builder.AuthorMapper"/>
将包内的映射器接口实现全部注册为映射器,例如:
<package name="org.mybatis.builder"/>
(3)Properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

(4)typeAliases标签

类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下

配置typeAliases,为com.itbluebox.domain.User定义别名为user

上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名

3、知识小结

核心配置文件常用配置:
1、properties标签:该标签可以加载外部的properties文件

<properties resource="jdbc.properties"></properties>

2、typeAliases标签:设置类型别名

<!--自定义别名-->
    <typeAliases>
        <typeAlias type="cn.itbluebox.domain.User" alias="user"></typeAlias>
    </typeAliases>

3、mappers标签:加载映射配置

<!--加载映射文件-->
    <mappers>
        <mapper resource="cn/itbluebox/mapper/UserMapper.xml"></mapper>
    </mappers>

4、environments标签:数据源环境配置标签

<!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/2>
            </dataSource>
        </environment>
    </environments>

六、MyBatis相应API

1、SqlSession工厂构建器SqlSessionFactoryBuilder

常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

String resource = "org/mybatis/builder/mybatis-config.xml"; 
InputStream inputStream = Resources.getResourceAsStream(resource); 
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); 
SqlSessionFactory factory = builder.build(inputStream);

其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。

2、SqlSession工厂对象SqlSessionFactory

SqlSessionFactory 有多个个方法创建 SqlSession 实例。常用的有如下两个:

3、SqlSession会话对象

SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有:

<T> T selectOne(String statement, Object parameter) 
<E> List<E> selectList(String statement, Object parameter) 
int insert(String statement, Object parameter) 
int update(String statement, Object parameter) 
int delete(String statement, Object parameter)

操作事务的方法主要有:

void commit()  
void rollback()

七、MyBatis的Dao层实现方式

1、传统开发方式

(1)编写UserDao接口
public interface UserDao {
	List<User> findAll() throws IOException;
}
(2)编写UserDaoImpl实现
public class UserDaoImpl implements UserDao {

	//查询所有shuju
    public List<User> findAll() throws  IOException{
        //加载配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //创建作用域工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取会话对象
        SqlSession sqlSession = sessionFactory.openSession();
        List<User> users = sqlSession.selectList("userMapper.findAll");
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.commit();
        sqlSession.close();
		return users;
    }

}
(3)测试传统方式
@Test
public void testTraditionDao() throws IOException {
    UserDao userDao = new UserDaoImpl();
    List<User> all = userDao.findAll();
    System.out.println(all);
}

2、代理开发方式

(1)代理开发方式介绍

采用 Mybatis 的代理开发方式实现 DAO 层的开发,

这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),

由Mybatis 框架根据接口定义创建接口的动态代理对象,

代理对象的方法体同上边Dao接口实现类方法。

Mapper 接口开发需要遵循以下规范:

1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

(2)编写UserMapper接口

package cn.itbluebox.mapper;

import cn.itbluebox.domain.User;

public interface UserMapper {

    User findById(Integer id);

}
(3)编辑cn.itbluebox.mapper.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">
<mapper namespace="cn.itbluebox.mapper.UserMapper">
    
    <select id="findById" parameterType="java.lang.Integer" resultType="cn.itbluebox.domain.User">

        select * from User where id = #{id}

    </select>
</mapper>
(4)测试代理方式

@Test
    public void testProxyDao() throws IOException{

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory  = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = userMapper.findById(1);

        System.out.println(user);

        sqlSession.close();
    }

3、手动对Dao进行实现:传统开发方式

代理方式对Dao进行实现:

UserMapper userMapper = 
 sqlSession.getMapper(UserMapper.class);

七、MyBatis映射文件深入

1、动态sql语句概述

Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,

有些时候业务逻辑复杂时,我们的 SQL是动态变化的,

此时在前面的学习中我们的 SQL 就不能满足要求了。
参考的官方文档,描述如下:

2、动态 SQL 之<if>

我们根据实体类的不同取值,
使用不同的 SQL语句来进行查询。
比如在 id如果不为空时可以根据id查询,

如果username 不同空时还要加入用户名作为条件。

这种情况在我们的多条件组合查询中经常会碰到。

<select id="findByCondition" parameterType="cn.itbluebox.domain.User" resultType="cn.itbluebox.domain.User">

        select * from User
        <where>
            <if test="id!=0">
                and id = #{id}
            </if>
            <if test="username != null">
                and username = #{username}
            </if>
        </where>

    </select>
(1)完善UserMapper

User findByCondition(User user);
(2)完善MyBatisTest当中创建testFindByCondition方法
1)当查询条件只有id存在时,控制台打印的sql语句如下:

@Test
    public void testFindByCondition() throws IOException{

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory  = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = new User();
        user.setId(1);
        user.setUsername("张三");

        User us = userMapper.findByCondition(user);

        System.out.println(us);

        sqlSession.close();
    }

2)当查询条件只有id存在时,控制台打印的sql语句如下:

@Test
    public void testFindByCondition() throws IOException{

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory  = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = new User();
        user.setId(1);

        User us = userMapper.findByCondition(user);

        System.out.println(us);

        sqlSession.close();
    }

5、动态 SQL 之<foreach>

(1)循环执行sql的拼接操作,例如:SELECT /* FROM USER WHERE id IN (1,2,5)

编写UserMapper.xml

<select id="findByIds" parameterType="list" resultType="cn.itbluebox.domain.User" >
        select * from User
        <where>
            <foreach collection="array" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>
(2)完善UserMapper

ArrayList<User> findByIds(int ids[]);
(3)完善MyBatisTest当中的testfindByIds方法

@Test
    public void testfindByIds() throws IOException{

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactory sqlSessionFactory  = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        int[] ids = new int[]{2,4};
        ArrayList<User> users = userMapper.findByIds(ids);
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

运行测试

(4)foreach标签的属性含义如下:

<foreach>标签用于遍历集合,它的属性:

collection:代表要遍历的集合元素,注意编写时不要写/#{}

open:代表语句的开始部分

close:代表结束部分

item:代表遍历集合的每个元素,生成的变量名(自定义任意名称)

sperator:代表分隔符

6、SQL片段抽取

Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 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="cn.itbluebox.mapper.UserMapper">
    
    <sql id="selectUser" >
        select * from User

    </sql>
    <select id="findById" parameterType="java.lang.Integer" resultType="cn.itbluebox.domain.User">
        <include refid="selectUser"></include>
         where id = #{id}

    </select>

    <select id="findByCondition" parameterType="cn.itbluebox.domain.User" resultType="cn.itbluebox.domain.User">
        <include refid="selectUser"></include>
        <where>
            <if test="id!=0">
                and id = #{id}
            </if>
            <if test="username != null">
                and username = #{username}
            </if>
        </where>

    </select>

    <select id="findByIds" parameterType="list" resultType="cn.itbluebox.domain.User" >
        <include refid="selectUser"></include>
        <where>
            <foreach collection="array" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>


</mapper>

7、知识小结

MyBatis映射文件配置:

<select>:查询
<insert>:插入
<update>:修改
<delete>:删除
<where>:where条件
<if>:if判断
<foreach>:循环
<sql>:sql片段抽取

八、MyBatis核心配置文件深入

1、typeHandlers标签(处理时间)

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时

还是从结果集中取出一个值时

都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

下表描述了一些默认的类型处理器(截取部分)。

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。

具体做法为:
实现 org.apache.ibatis.type.TypeHandler 接口,

或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
然后可以选择性地将它映射到一个JDBC类型。

例如需求:一个Java中的Date数据类型,
我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,
即java的Date与数据库的varchar毫秒值之间转换。

开发步骤:

  • 定义转换类继承类BaseTypeHandler<T>
  • 覆盖4个未实现的方法,其中setNonNullParameterjava程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 javaType类型的方法
  • 在MyBatis核心配置文件中进行注册
  • 测试转换是否正确
(1)创建MyDateTypeHandler 类

package cn.itbluebox.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

public class MyDateTypeHandler extends BaseTypeHandler<Date> {
    //将Java 类型转换为数据库需要的类型
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        long time = date.getTime();
        preparedStatement.setLong(i,time);
    }
    //将数据中的类型 转换为java类型
    //String 类型 要转换的字段名称
    //ResultSet 查询出的结果集
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        //获得结果集中需要的数据(long)转换为Date
        long aLong = resultSet.getLong(s);
        Date date = new Date(aLong);
        return date;
    }
    //将数据库当中的类型 转换为Java的类型
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        long aLong = resultSet.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
    //将数据库中的类型 转换为Java类型
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        long aLong = callableStatement.getLong(i);
        Date date = new Date(aLong);
        return date;
    }
}
(2)typeHandlers标签

<!--注册类型处理器-->
    <typeHandlers>
        <typeHandler handler="cn.itbluebox.handler.MyDateTypeHandler">
        </typeHandler>
    </typeHandlers>
(3)修改数据表和实体类User

package cn.itbluebox.domain;

import java.util.Date;

public class User {

    private int id;
    private String username;
    private String password;
    private Date birthday;

    public User() {
    }

    public User(int id, String username, String password, Date birthday) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.birthday = birthday;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
(4)完善UserMapper

void save(User user);
(5)完善UserMapper.xml

<insert id="save" parameterType="user">
        insert into User values(#{id},#{username},#{password},#{birthday})
    </insert>
(6)完善MyBatisTest测试方法

//插入数据
    @Test
    public void testSaveUser()throws IOException{
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //创建user
        User user = new User();
        user.setUsername("ceshi");
        user.setPassword("abc");
        user.setBirthday(new Date());
        //执行保存造作
        mapper.save(user);
        sqlSession.commit();
        sqlSession.close();
    }

运行测试

(7)测试查询操作

testFindByCondition刚刚写过的

2、plugins标签(处理分页)

MyBatis可以使用第三方的插件来对功能进行扩展,
分页助手PageHelper是将分页的复杂操作进行封装,
使用简单的方式即可获得分页的相关数据

开发步骤:

  • 导入通用PageHelper的坐标
  • 在mybatis核心配置文件中配置PageHelper插件
  • 测试分页数据获取
(1)导入通用PageHelper坐标

<!-- 分页助手 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>
(2)在mybatis核心配置文件中配置PageHelper插件

<!--配置分页助手插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"></property>
        </plugin>
    </plugins>
(3)UserMapper

ArrayList<User> select();
(4)UserMapper.xml

<select id="select" resultType="cn.itbluebox.domain.User">
        <include refid="selectUser"></include>
    </select>
(5)MyBatisTest

@Test
    public void testPageHelper()throws IOException{
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        PageHelper.startPage(1,3);
        ArrayList<User> select = mapper.select();
        for (User user : select) {
            System.out.println(user);
        }
        sqlSession.commit();
        sqlSession.close();
    }

(6)获得分页相关的其他参数

//其他分页的数据
        PageInfo<User> pageInfo = new PageInfo<User>(select);
        System.out.println("总条数:"+pageInfo.getTotal());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("当前页:"+pageInfo.getPageNum());
        System.out.println("每页显示长度:"+pageInfo.getPageSize());
        System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
        System.out.println("是否最后一页:"+pageInfo.isIsLastPage());

3、知识小结

MyBatis核心配置文件常用标签:
1、properties标签:该标签可以加载外部的properties文件
2、typeAliases标签:设置类型别名
3、environments标签:数据源环境配置标签
4、typeHandlers标签:配置自定义类型处理器
5、plugins标签:配置MyBatis的插件

九、MyBatis的多表操作

1、一对一查询

(1)一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

(2)一对一查询的语句

对应的sql语句:select /* from orders o,user u where o.uid=u.id;
查询的结果如下:

(3)创建Orders实体以及数据库表

在orders表当中添加一些数据

package cn.itbluebox.domain;

import java.util.Date;

public class Orders {

    private int id;
    private Date ordertime;
    private double total;

    //代表当前订单从属于哪一个客户
    private User user;

    public Orders() {
    }

    public Orders(int id, Date ordertime, double total, User user) {
        this.id = id;
        this.ordertime = ordertime;
        this.total = total;
        this.user = user;
    }

    public int getId() {
        return id;
    }

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

    public Date getOrdertime() {
        return ordertime;
    }

    public void setOrdertime(Date ordertime) {
        this.ordertime = ordertime;
    }

    public double getTotal() {
        return total;
    }

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

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", total=" + total +
                ", user=" + user +
                '}';
    }
}
(4)创建OrderMapper接口

package cn.itbluebox.mapper;

import cn.itbluebox.domain.Orders;

import java.util.List;

public interface OrderMapper {

    List<Orders> findAll();
}
(5) 配置OrderMapper.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.itbluebox.mapper.OrderMapper">

    <resultMap id="orderMap" type="cn.itbluebox.domain.Orders">

        <result property="id" column="id"></result>
        <result property="ordertime" column="ordertime"></result>
        <result property="total" column="total"></result>
        
        <association property="user" javaType="cn.itbluebox.domain.User">

            <result column="id" property="id" ></result>
            <result column="username" property="username" ></result>
            <result column="password" property="password" ></result>
            <result column="birthday" property="birthday" ></result>

        </association>

    </resultMap>
    <select id="findAll" resultMap="orderMap">
        select * from orders o,user u where o.id = u.id
   </select>

</mapper>
(6)OrderTest当中的testFindOrderAll

package cn.itbluebox.test;

import cn.itbluebox.domain.Orders;
import cn.itbluebox.mapper.OrderMapper;
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.Test;

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

public class OrderTest {

    @Test
    public void testFindOrderAll() throws IOException {

        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

        List<Orders> all = mapper.findAll();

        for (Orders order : all) {
            System.out.println(order);
        }
        sqlSession.commit();
        sqlSession.close();

    }

}

2、一对多查询

(1)一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

(2)一对多查询的语句

对应的sql语句:select /*,o.id oid from user u left join orders o on u.id=o.uid;
查询的结果如下

(3)修改User实体

package cn.itbluebox.domain;

import com.sun.org.apache.xpath.internal.operations.Or;

import java.util.Date;
import java.util.List;

public class User {

    private int id;
    private String username;
    private String password;
    private Date birthday;

    //带代表当前用户具备的哪些订单
    private List<Orders> ordersList;

    public User() {
    }

    public User(int id, String username, String password, Date birthday, List<Orders> ordersList) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.birthday = birthday;
        this.ordersList = ordersList;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                ", ordersList=" + ordersList +
                '}';
    }
}
(5)修改Orders表

(6)在创建UserMapper当中创建findUserAll()

List<User> findUserAll();
(7)在配置UserMapper.xml

<resultMap id="userMap" type="cn.itbluebox.domain.User">
        <id column="uid" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
        <!--配置集合信息 property:集合名称 ofType:当前集合中的数据类型 -->
        <collection property="ordersList" ofType="cn.itbluebox.domain.Orders">
            <!--封装order的数据-->
            <id column="oid" property="id"></id>
            <result column="ordertime" property="ordertime"></result>
            <result column="total" property="total"></result>
        </collection>
    </resultMap>

    <select id="findUserAll" resultMap="userMap">
        select *,o.id oid from user u left join orders o on u.id=o.uid;
    </select>
(8)MyBatisTest当中的testUserAll

@Test
    public void testUserAll() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> all = mapper.findUserAll();
        for (User user : all) {
            System.out.println(user.getUsername());
            List<Orders> ordersList = user.getOrdersList();
            for (Orders orders : ordersList) {
                System.out.println(orders);
            }
            System.out.println("----------------------");
        }
        sqlSession.commit();
        sqlSession.close();
    }

3、多对多查询

(1)多对多查询的模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色

(2)多对多查询的语句

对应的sql语句:

select u.*,r.*,r.id rid 
from user u left join user_role ur on u.id=ur.user_id
inner join role r on ur.role_id=r.id;

查询的结果如下:

(3)创建Role实体,创建Role表

package cn.itbluebox.domain;

public class Role {

    private int id;
    private String roleName;
    private String roleDesc;

    public int getId() {
        return id;
    }

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

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleDesc() {
        return roleDesc;
    }

    public void setRoleDesc(String roleDesc) {
        this.roleDesc = roleDesc;
    }

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", roleDesc='" + roleDesc + '\'' +
                '}';
    }
}
(4)修改User实体

package cn.itbluebox.domain;

import java.util.Date;
import java.util.List;

public class User {

    private int id;

    private String username;
    private String password;
    private Date birthday;

    //带代表当前用户具备的哪些订单
    private List<Orders> ordersList;

    private List<Role> roleList;

    public User() {
    }

    public User(int id, String username, String password, Date birthday, List<Orders> ordersList, List<Role> roleList) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.birthday = birthday;
        this.ordersList = ordersList;
        this.roleList = roleList;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    public List<Role> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<Role> roleList) {
        this.roleList = roleList;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                ", ordersList=" + ordersList +
                ", roleList=" + roleList +
                '}';
    }
}
(5)创建user_role中间表

(6)添加UserMapper接口方法

List<User> findAllUserAndRole();
(7)配置UserMapper.xml

<resultMap id="userRoleMap" type="cn.itbluebox.domain.User">
        <result column="id" property="id"></result>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
        <collection property="roleList" ofType="cn.itbluebox.domain.Role">
            <result column="rid" property="id" ></result>
            <result column="roleName" property="roleName"></result>
            <result column="roleDesc" property="roleDesc"></result>
        </collection>
    </resultMap>

    <select id="findAllUserAndRole" resultMap="userRoleMap">
        select u.*,r.*,r.id rid from user u left join user_role ur on u.id=ur.user_id
        inner join role r on ur.role_id=r.id
    </select>
(8)创建testFindAllUserAndRole方法

@Test
    public void testFindAllUserAndRole() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> allUserAndRole = mapper.findAllUserAndRole();
        for (User user : allUserAndRole) {
            System.out.println(user.getUsername());

            List<Role> roleList = user.getRoleList();
            for (Role role : roleList) {
                System.out.println(role);
            }

        }
        System.out.println("------------");
    }

运行

下一篇文章地址:Java之MyBatis【IDEA版】(一篇文章精通系列)增删改查【注解开发】 - 所有知识点(大全)

相关文章

最新文章

更多

目录