MyBatis快速入门

在这里插入图片描述

孤独的人有自己的泥沼。

1、MyBatis简述


  • MyBatis 是一款优秀的持久层框架,用于简化JDBC开发。(半自动化的ORM框架)
  • 它支持自定义SQL、存储过程以及高级映射。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和Java的POJO(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录。
  • MyBatis 是 Apache的一个开源项目iBatis,在2010年6月 Apache 将项目交与Google进行管理,更名MyBatis。于2013年11月迁移到GitHub上。
  • Mybatis官网:https://mybatis.org/mybatis-3/zh/index.html
  • 项目地址:https://github.com/mybatis/mybatis-3/releases
  • 目前最新版本是:3.5.11,其发布时间是2022年9月18日。

MyBatis的缺点:

  • 编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
  • SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
  • 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
  • 二级缓存机制不佳。

什么是框架?

  • 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。
  • 在架构的基础之上构建软件编写更加高效、规范、通用、可扩展。

软件设计:(open-close开闭原则)尽量不修改源代码,对程序进行扩展。

  • 对扩展是开放的。
  • 对修改源码是关闭的。

MyBatis的安装:

1、使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。

2、如果使用 Maven 来构建项目,则需将下面的依赖引入 pom.xml 文件中:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

2、快速入门


1、创建一个普通的Maven项目

2、引入依赖坐标

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>
<!-- mysql 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
</dependency>
<!-- junit 单元测试 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<!-- slf4j日志api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.20</version>
</dependency>
<!-- logback-classic -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<!-- logback-core -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>

3、导入SQL脚本

-- 创建数据库
drop database if exists `mybatis`;
create database `mybatis` character set = utf8;

use mybatis;

-- 创建数据表
create table `user`(
	`id` int auto_increment primary key comment '编号',
	`name` varchar(20) unique comment '姓名', -- 唯一约束
	`pwd` varchar(20) comment '密码',
	`gender` char(1) comment '性别',
	`addr` varchar(30) comment '家庭住址'
)engine=innodb default charset=utf8;

-- 插入数据
insert into user(name,pwd,gender,addr) values
("张三","123456",'男',"北京"),
("李四","123456",'女',"南京"),
("王五","777777",'男',"杭州"),
("赵六","123456",'女',"温州"),
("陈七","666666",'男',"黑河");

4、编写实体类

public class User {
    private Integer id;
    private String name;
    private String pwd;
    private char gender;
    private String addr;

    public User() {
    }

    public User(Integer id, String name, String pwd, char gender, String addr) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
        this.gender = gender;
        this.addr = addr;
    }

    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 getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public char getGender() {
        return gender;
    }

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

    public String getAddr() {
        return addr;
    }

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

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

5、编写mapper接口

public interface UserMapper {
    // 查询所有用户
    List<User> findAll();
}

6、编写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">

<!--namespace:命名空间,用来绑定对应的mapper-->
<mapper namespace="com.baidou.mapper.UserMapper">
    <!--select语句 , id:是这里的唯一标识用来绑定接口中对应的方法 ,resultType:返回值类型-->
    <select id="findAll" resultType="com.baidou.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

7、编写mybatis核心配置文件

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <!--可以多环境切换-->
    <environments default="development">
        <environment id="development">
            <!--事务管理-->
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射器-->
    <mappers>
      <!--之后mapper的配置文件需要在这里注册-->
      <mapper resource="com/baidou/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

8、编写日志配置文件
logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">

    <!--控制台输出-->  
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">                
        <encoder> 
            <!-- 输出的日志格式 -->
            <pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg%n</pattern>   
        </encoder>    
    </appender>

    <!--level:用来设置日志输出级别,有OFF FATAL ERROR WARN INFO DEBUG TRACE ALL,默认DEBUG-->
    <logger name="com.baidou" level="DEBUG" additivity="false">
        <appender-ref ref="Console"/>
    </logger>
    <root level="DEBUG">
        <appender-ref ref="Console"/>
    </root>
</configuration>

9、测试

public class ApplicationTest {
    public static void main(String[] args) throws IOException {
        // 1、加载Mybatis核心配置文件,获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2、获取对应的SqlSession对象,用来执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3、获取mapper,来调用mapper中的方法
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.findAll();
        for (User user:users){
            System.out.println(user);
        }
        //4、关闭SqlSession
        sqlSession.close();

    }
}

控制台输出结果如下:
在这里插入图片描述

10、优化(编写MyBatis工具类)

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            // 获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过SqlSessionFactory来获取SqlSession对象
     * SqlSession:提供了在数据库执行SQL命令所需的所有方法。
     *
     * @return SqlSession
     */
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(); //connection
    }
}

测试:

public class MyBatisTest {
    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.findAll();
        userList.forEach(System.out::println);
    }
}

测试结果如下:
在这里插入图片描述

项目的目录结构:
在这里插入图片描述
MyBatis执行流程:
在这里插入图片描述

总结:

  • 导入MyBatis依赖
  • 编写核心配置文件,mybatis-config.xml
  • 编写实体、接口
  • 编写mapper.xml(mapper 对应mapper.xml)
  • 在核心配置文件中注册这个mapper.xml
  • 编写工具类(用来获取SqlSession实例)
  • 通过工具类得到SqlSession,然后通过SqlSession来获取我们的mapper,之后通过这个mapper来调用它的方法
  • 关闭SqlSession

3、Mapper代理开发


1、定义与SQL映射文件同名的Mapper接口,并将Mapper接口和SQL映射文件放置在同一目录下;
在这里插入图片描述


2、设置SQL映射文件的namespace属性为Mapper接口全限定名(包名.接口名);
在这里插入图片描述


3、在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致;
在这里插入图片描述


4、编码操作

  • 通过SqlSession的getMaper()方法获取Mapper接口的代理对象;
  • 调用对应方法完成sql的执行;

【扩展】如果Mapper接口和SQL映射文件名称相同,并且在同包下,可以使用包扫描的方式简化SQL映射文件的加载:

<!-- 加载sql的映射文件 -->
<mappers>
    <!--<mapper resource="com/baidou/mapper/UserMapper.xml"/>-->
    <package name="com.baidou.mapper"/>
</mappers>

【示例】测试CRUD操作

1、编写接口

public interface UserMapper {

    /**
     * 获取全部的用户
     */
    List<User> getUserList();

    /**
     * 通过ID获取用户
     * @param id
     * @return
     */
    List<User> getUserById(int id);

    /**
     * 添加用户
     * @param user
     * @return
     */
    int addUser(User user);

    /**
     * 修改用户信息
     * @param user
     * @return
     */
    int updateUser(User user);

    /**
     * 删除用户
     * @param id
     * @return
     */
    int deleteUser(int id);

}

2、编写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:绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.baidou.mapper.UserMapper">
    <!-- select查询语句,id:绑定对应方法名,resultType:返回值类型 -->
    <select id="getUserList" resultType="com.baidou.pojo.User">
        select  * from mybatis.user ;
    </select>

    <select id="getUserById" resultType="com.baidou.pojo.User" parameterType="int">
        select * from mybatis.user where id = #{id} ;
    </select>

    <insert id="addUser" parameterType="com.baidou.pojo.User">
        insert into mybatis.user (name, pwd) values(#{name},#{pwd}) ;
    </insert>

    <update id="updateUser" parameterType="com.baidou.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id} ;
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id =#{id} ;
    </delete>
</mapper>

3、测试

public class UserMapperTest {

    // 查询所有用户
    @Test
    public void test() {
        // 获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        // 方式一:getmapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();


        // 方式二:
        // List<User> userList = sqlSession.selectList("com.baidou.dao.UserDao.getUserList");

        //for (User user : userList) {
        //    System.out.println(user);
        //}
        userList.forEach(System.out::println);

        //关闭SqlSession
        sqlSession.close();
    }

    // 查询指定id的用户
    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUserById(1);
        System.out.println(user);
        // 关闭SqlSession
        sqlSession.close();
    }

    // 添加用户
    @Test
    public void addUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(mapper.addUser(new User("风清扬", "fenqingyang",'男',"金庸")) > 0 ? "添加成功" : "添加失败");
        // 增删改需要提交事务
        sqlSession.commit();
        // 关闭SqlSession
        sqlSession.close();
    }

    // 修改用户
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(mapper.updateUser(new User(3, "王富贵", "wangfugui",'女',"土耳其")) > 0 ? "修改成功" : "修改失败");
        // 提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    // 删除用户
    @Test
    public void deleteUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println(mapper.deleteUser(3) > 0 ? "删除成功" : "删除失败");
        // 提交事务
        sqlSession.commit();
        // 关闭SqlSession
        sqlSession.close();
    }
}

注意:增删改需要提交事务!!!


4、MyBatis核心配置文件


核心配置文件(mybatis-config.xml)的顶层结构如下:
在这里插入图片描述
注:配置各个标签时,需要遵守前后顺序!


4.1、properties(属性)


  • properties属性可以引用外部配置文件;
  • properties属性也可以在内部增加一些属性配置;
  • 如果两个文件有共同的字段,会优先使用外部配置文件的!

1、编写db.properties配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456

2、在mybatis-config.xml中引用db.properties

<?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 resource="db.properties"/>

    <environments default="development">
        <environment id="development">
            <!--事务管理-->
            <transactionManager type="JDBC"/>
            <!--配置数据库连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射器-->
    <mappers>
        <!--<mapper resource="com/baidou/mapper/UserMapper.xml"/>-->
        <package name="com.baidou.mapper"/>
    </mappers>
</configuration>

4.2、environments(环境配置)


  • MyBatis 可以配置多种环境,但每个 SqlSessionFactory 实例只能选择一种环境;
  • 用ID这个唯一标识来切换默认使用的环境;
  • MyBatis默认的事务管理器是JDBC,连接池是POOLED;

在这里插入图片描述


4.3、typeAliases(类型别名)


类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写;

使用场景:1、给实体类起别名

<typeAliases>
    <typeAlias type="com.baidou.pojo.User" alias="user"/>
</typeAliases>

使用场景:2、扫描实体类的包,它的的默认别名为类名,首字母小写

<typeAliases>
    <package name="com.baidou.pojo"/>
</typeAliases>

在实体类比较少的时候使用第一种方式,如果实体类比较多建议使用第二种方式!

区别:第一种可以自定义别名,第二种它就不行(如果非要改 需要在实体类上增加@Alias注解)。


下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

4.4、settings(设置)


在MyBatis全局配置文件中通过<settings>标签控制MyBatis全局开关。

MyBatis的设置:https://mybatis.org/mybatis-3/zh/configuration.html#settings

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y9uydccf-1646741313536)(MyBatis笔记.assets/image-20220308085807728.png)]


示例:在mybatis-config.xml配置日志输出

 <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
 </settings>

4.5、mappers(映射器)


mappers(映射器)的作用是告诉 MyBatis 到哪里去找映射文件;


使用场景:1. 使用相对于类路径的资源引用(推荐使用)

<!-- 每一个Mapper.xml都需要在Mybatis核心配置文件中注册 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

使用场景:2. 使用映射器接口实现类绑定注册

<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

使用场景:3. 使用扫描包进行注入绑定

<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

注:接口和它的配置文件必须同名,接口和它的配置文件必须在同一个包下;


4.6、其它配置


  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • databaseIdProvider(数据库厂商标识)

5、使用Map传参以及模糊查询


5.1、使用Map传参


当我们的实体类或者数据库中的表,字段或者参数过多时,我们应当考虑使用Map!(优点:可以不用插入指定的参数,比较灵活)

mapper中添加如下方法:

//使用Map传参添加用户
int addUser2(Map<String,Object> map);
//使用Map传参修改用户信息
int updateUser2(Map<String,Object> map);

mapper映射器中:

<insert id="addUser2" parameterType="map">
    insert into mybatis.user (name, pwd) values(#{userName},#{passWorld}) ;
</insert>

<update id="updateUser2" parameterType="map">
    update mybatis.user set name=#{userName},pwd=#{password} where id=#{userId} ;
</update>

编写测试:

@Test
public void testGeneralMap(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Object> map = new HashMap<String, Object>();
    map.put("userName","钻石王老五");
    map.put("passWorld","23333");
    System.out.println(mapper.addUser2(map) > 0 ? "添加成功" : "添加失败");
    // 增删改需要提交事务
    sqlSession.commit();
    // 关闭SqlSession
    sqlSession.close();
}
@Test
public void testGeneralMap2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("userId",4);
    map.put("userName","小花");
    map.put("password","123");
    System.out.println(mapper.updateUser2(map) > 0 ? "修改成功" : "修改失败");
    // 提交事务
    sqlSession.commit();
    sqlSession.close();
}

最终表数据如下:
在这里插入图片描述

5.2、模糊查询的使用


1、在SQL拼接中使用通配符

在这里插入图片描述

2、在Java代码执行的时候,传递通配符 % 内容 %

在这里插入图片描述


6、解决属性名与字段名不一致问题


1、数据库表中的字段:
在这里插入图片描述


2、拷贝之前的配置文件 mybatis-config.xml & db.properties

mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--引入外部配置文件-->
    <properties resource="db.properties"/>
    <!--给实体类取别名起别名-->
    <typeAliases>
        <package name="com.baidou.pojo"/>
    </typeAliases>
    <!--用于切换开发环境-->
    <environments default="development">
        <environment id="development">
            <!--采用JDBC事务管理-->
            <transactionManager type="JDBC"/>
            <!--配置数据库连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url"
                          value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射器-->
    <mappers>
        <package name="com.baidou.mapper"/>
    </mappers>
</configuration>

db.properties:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456

3、向pom.xml加入资源过滤配置,解决UserMapper.xml绑定异常

<!--解决资源过滤问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

4、编写MyBatis工具类:

public class MyBatisUtils {
    private static SqlSessionFactory sessionFactory = null;

    // 获取SqlSessionFactory实例
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取SqlSession
     * @return
     */
    public static SqlSession getSqlSession() {
        return sessionFactory.openSession();
    }
}

5、编写实体类与数据库不一致的情况

public class User {
    private Integer id;
    private String name;
    private String password; //对应数据表中的pwd字段
    private char gender;
    private String addr;

    public User(Integer id, String name, String password, char gender, String addr) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.gender = gender;
        this.addr = addr;
    }

    public User(String name, String password, char gender, String addr) {
        this.name = name;
        this.password = password;
        this.gender = gender;
        this.addr = addr;
    }

    public User() {
    }

    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 getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public char getGender() {
        return gender;
    }

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

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
        @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", gender=" + gender +
                ", addr='" + addr + '\'' +
                '}';
    }
}

6、编写UserMapper及UserMapper.xml并放到同一个包下

UserMapper接口:

public interface UserMapper {
    // 通过id获取用户信息
    User getUserById(int id);
}

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:绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.baidou.mapper.UserMapper">
    <!--
        select语句
        id:绑定对应方法
        resultType:返回值类型
        parameterType:参数类型 
    -->
    <select id="getUserById" resultType="user" parameterType="int">
        select *
        from mybatis.user
        where id = #{id};
    </select>
</mapper>

7、编写测试

public class ApplicationDemo {
    public static void main(String[] args) {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
    }
}

运行结果如下:
在这里插入图片描述

发现:这里的password的数据为null,是因为没有对应数据表中的字段pwd。

解决方案

方案1:修改sql起别名 (最暴力的解决方式)

select id,name,pwd as password,gender,addr
        from mybatis.user
        where id = #{id};

在这里插入图片描述

运行结果如下:
在这里插入图片描述

方案2:在映射文件中配置resultMap(结果集映射)

<!--
     resultMap:自定义结果集映射规则,自定义某个JavaBean的封装规则。
     id:唯一id,方便引用。
     type:自定义规则的Java类。
-->
<resultMap id="userMap" type="User">
    <!--
         column:数据库中的字段
         property:实体类中的属性
     -->
    <result  column="pwd" property="password"/>
</resultMap>
<!-- select语句 -->
<select id="getUserById" resultMap="userMap">
    select *
    from mybatis.user
    where id = #{id};
</select>

在这里插入图片描述

运行结果如下:
在这里插入图片描述

7、日志的使用


7.1、配置日志工厂


  • 排查数据库出现的异常以及打印SQL的执行流程
  • 之前我们使用控制台打印和debug的方式,而现在我们使用MyBatis的日志工厂。
设置名描述有效值默认值
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J 、LOG4J、LOG4J2、 JDK_LOGGING 、COMMONS_LOGGING 、STDOUT_LOGGING 、NO_LOGGING未设置

常用的有:

  • LOG4J (它要指定一个配置文件)
  • STDOUT_LOGGING (标准日志输出)

在mybatis核心配置文件上配置日志(这里使用STDOUT_LOGGING):

  • 坐标在configuration属性的第二个位置。
    在这里插入图片描述
    在这里插入图片描述

7.2、配置LOG4J


(1) 导入log4j包

<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

(2) 创建log4j.properties文件,并编写日志配置

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/MyTest.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

(3) 在mybatis-config.xml文件中配置log4j为日志的实现

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>

(4) 测试
在这里插入图片描述

8、分页的实现


8.1、使用limit分页


使用分页的好处:方便用户检索内容,减少数据库开销;

SQL语法如下:

select * from user limit startIndex,pageSize;

# 示例:查询数据表中前两条数据
select * from user limit 0,2;  # [0,2]

(1) 编写Mapper接口中的方法,参数为map

// 分页查询用户
 List<User> selectUser(Map<String,Integer> map);

(2) 编写SQL映射文件

 <!--  分页查询  -->
    <select id="selectUser" resultType="user" parameterType="map">
        select *
        from mybatis.user
        limit #{startIndex},#{pageSize};
    </select>

(3) 在测试类中传参

分析:起始位置 = (当前页面 - 1 )* 页面大小;

@Test
public void testLimit() {
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int currentPage = 1; // 第几页
    int pageSize = 2;    // 每页显示几个
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex", (currentPage - 1) * pageSize);
    map.put("pageSize", pageSize);
    List<User> users = mapper.selectUser(map);
    users.forEach(System.out::println);
    sqlSession.close();
}

测试结果:
在这里插入图片描述

8.2、使用数组分页


分析:查询出全部数据存list,然后在list中截取需要的部分;

(1) 编写mapper接口中的方法

// 使用数组分页
List<User> selectUserByArray();

(2) 编写SQL映射文件

<select id="selectUserByArray" resultType="user">
    select *
    from mybatis.user
</select>

(3)编写测试

  SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int currentPage = 1; // 第几页
        int pageSize = 2;    // 每页显示几个
        List<User> userList = mapper.selectUserByArray();
        // (currentPage - 1) * pageSize 从第几条开始
        // currentPage * pageSize  到第几条结束
        List<User> users = userList.subList((currentPage - 1) * pageSize, currentPage * pageSize);
        users.forEach(System.out::println);
        sqlSession.close();

测试结果:
在这里插入图片描述

8.3、RowBounds分页


使用 RowBounds 进行分页,非常方便,不需要在 sql 语句中写 limit 即可完成分页功能。

(1) 编写mapper接口中的方法

// 使用RowBounds 分页
List<User> selectUserByRowBounds();

(2) 编写SQL映射文件

<select id="selectUserByRowBounds" resultType="user">
    select *
    from mybatis.user
</select>

(3) 编写测试

@Test
public void selectUserByRowBounds() {
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    int currentPage = 2; // 第几页
    int pageSize = 2;    // 每页显示几个
    RowBounds rowBounds = new RowBounds((currentPage - 1) * pageSize, pageSize);
    // 通过session.**方法进行传递rowBounds,[此方式现在已经不推荐使用了]
    List<User> users = sqlSession.selectList(
            "com.baidou.mapper.UserMapper.selectUserByRowBounds", null, rowBounds);
    users.forEach(System.out::println);
    sqlSession.close();
}

测试结果:
在这里插入图片描述

8.4、PageHelper


官方文档:https://pagehelper.github.io/

在这里插入图片描述


9、使用注解开发


MyBatis 也可以使用注解的方式开发,这样我们就可以减少编写 Mapper 映射文件;

MyBatis常用注解如下:

@Insert:实现添加
@Update:实现更新 
@Delete:实现删除 
@Select:实现查询 

@Result:实现结果集封装 
@Results:可以与@Result 一起使用,封装多个结果集 
@ResultMap:实现引用@Results 定义的封装 

@One:实现一对一结果集封装 
@Many:实现一对多结果集封装 

@SelectProvider: 实现动态 SQL 映射 
@CacheNamespace:实现注解二级缓存的使用

1、编写实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
    private char gender;
    private String addr;

    public User(String name, String pwd, char gender, String addr) {
        this.name = name;
        this.pwd = pwd;
        this.gender = gender;
        this.addr = addr;
    }
}

2、编写接口

public interface UserMapper {
    // 查询全部用户
    @Select("select * from user")
    List<User> getUserAll();

    // 通过id查询用户,用注解传参
    // 当方法中存在多个参数时,参数的前面需要加 @Param("xxx") 注解,使用这个注解可以给参数起别名
    @Select("select * from user where id=#{id}")
    User getUserById(@Param("id") int id);

    // 添加用户
    @Insert("insert into user(name,pwd,gender,addr) values(#{name},#{pwd},#{gender},#{addr})")
    int addUser(User user);

    // 修改用户
    @Update("update user set name=#{name},pwd=#{pwd},gender=#{gender},addr=#{addr} where id=#{id}")
    int updateUser(User user);

    // 删除用户
    @Delete("delete from user where id=#{uid}")
    int deleteUser(@Param("uid") int id);
}

3、编写MyBatis核心配置文件

<!--使用映射器接口实现类绑定注册-->
<?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 resource="db.properties"/>
    
    <!--配置标准日志输出-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    
    <!--给实体类起别名-->
    <typeAliases>
        <package name="com.baidou.pojo"/>
    </typeAliases>
    
    <!--开发环境,之后这些东西在Spring中配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <!--使用class绑定方式-->
    <mappers>
        <mapper class="com.baidou.mapper.UserMapper"/>
    </mappers>
</configuration>

4、编写工具类

public class MyBatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    // 1、加载MyBatis配置文件,获取sqlSessionFactory
    static {
        try {
            String resouce = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resouce);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过sqlSessionFactory构建SqlSession
     *
     * @return SqlSession
     */
    public static SqlSession getSqlSession(boolean flag) {
        return sqlSessionFactory.openSession(flag);
    }


    /**
     * 增删改需要提交事务
     * sqlSessionFactory.openSession(true);
     *
     * @return
     */
    public static SqlSession getSqlSession() {
        return getSqlSession(true); //自动提交事务
    }
}

5、编写测试

public class MyBatisTest {

    @Test
    public void testGetUserAll() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUserAll();
        users.forEach(System.out::println);
        sqlSession.close();
    }

    @Test
    public void testGetUserById() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user); //User(id=1, name=张三, pwd=123456, gender=男, addr=北京)
        sqlSession.close();
    }


    @Test
    public void testAddUser() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.addUser(new User("布鲁克", "buluke123", '男', "复仇者联盟"));
        if (i > 0) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }
        sqlSession.close();
    }

    @Test
    public void testUpdateUser() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.updateUser(new User(1,"陈平", "123213", '男', "郑州"));
        if (i > 0) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }
        sqlSession.close();
    }

    @Test
    public void testDeleteUser() {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(9);
        if (i > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
        sqlSession.close();
    }
}

@Param()注解的使用

  • 当方法中有很多基本类型或String类型的参数,参数前面需要加@Param()注解;引用类型参数不用加;
  • 如果方法中只有一个基本类型的参数,可以忽略@Param()注解,但是建议加上它;
  • 我们在SQL中引用的#{xxx},就是我们在注解@Param(“xxx”)中设置的属性名;

#{} 和 ${}区别

  • #{}是预编译处理,$ {} 是字符串替换。
  • Mybatis在处理#{}时,会将sql中的#{}替换为占位符?,调用PreparedStatement的set方法来赋值;
  • Mybatis在处理$ {}时,就是把${}替换成变量的值。
  • 使用#{}可以有效的防止SQL注入,提高系统安全性;

10、MyBatis关联查询


表与表之间的关系:

  • 一对一
  • 一对多
  • 多对多

10.1、一对一关联查询


分析:一个用户可以有多个订单,一个订单对应它所属的用户

数据库设计:

在这里插入图片描述

-- 用户表
CREATE TABLE `user`(
  `id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
	`username` VARCHAR(50) COMMENT '用户名',
	`password` VARCHAR(50) COMMENT '密码',
	`birthday` VARCHAR(50) COMMENT '生日'
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO user(username,password,birthday) VALUES('王富贵','123123','2000-1-1');
INSERT INTO user(username,password,birthday) VALUES('小芳','234123','2001-5-1');
INSERT INTO user(username,password,birthday) VALUES('王狗蛋','223333','2000-6-17');

-- 订单表
CREATE TABLE `orders`(
  `id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
	`ordertime` VARCHAR(255) COMMENT '订单时间',
	`total` DOUBLE COMMENT '合计',
	`uid` int COMMENT '外键',
	CONSTRAINT `FK_uid` FOREIGN KEY(`uid`) REFERENCES `user`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO orders(ordertime,total,uid) VALUES('2020-11-27 21:00:05',3000,1);
INSERT INTO orders(ordertime,total,uid) VALUES('2020-11-27 20:05:00',4000,1);
INSERT INTO orders(ordertime,total,uid) VALUES('2020-11-27 17:15:20',2000,2);
INSERT INTO orders(ordertime,total,uid) VALUES('2020-11-27 15:50:00',1000,3);

1、编写实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
    private int id;
    private Date ordertime;
    private double total;
    // 当前订单属于哪个用户(用java面向对象方式实现外键)
    private User user;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;
}

2、编写接口:

public interface OrderMapper {
    List<Order> findAll();
}

3、编写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="com.baidou.mapper.OrderMapper">

    <resultMap id="orderMap" type="order">
        <!--手动指定字段与实体属性的映射关系
            column:表中的字段,为了方便查阅把id取别名为oid
            property:实体类的属性
        -->
        <id column="id" property="id"></id>
        <result column="ordertime" property="ordertime"></result>
        <result column="total" property="total"></result>
        <!-- 第一种写法封装user -->
        <!--<result column="uid" property="user.id"></result>-->
        <!--<result column="username" property="user.username"></result>-->
        <!--<result column="password" property="user.password"></result>-->
        <!--<result column="birthday" property="user.birthday"></result>-->
        
        <!-- 第二种写法,嵌入结果映射  
            property:order实体中的属性名称
            javaType:order实体中的属性类型 
         -->
        <association property="user" javaType="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>
        </association>
    </resultMap>

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

4、拷贝之前的数据库配置文件、mybatis核心配置文件、mybatis工具类:
在这里插入图片描述

5、编写测试

@Test
public void test1(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
    List<Order> orderList = mapper.findAll();
    orderList.forEach(System.out::println);
    sqlSession.close();
}

测试结果:
在这里插入图片描述

10.2、一对多关联查询


查询一个用户有多少个订单

1、编写实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;
    // 描述当前用户有哪些订单
    private List<Order> orderList;
}

2、编写接口和映射文件

public interface UserMapper {
    List<User> findAllUser();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.baidou.mapper.UserMapper">

    <!--配置结果集映射-->
    <resultMap id="userMap" type="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>

        <!-- 配置将订单信息封装到集合中
             ofType:参数类型
        -->
        <collection property="orderList" ofType="order">
            <id column="oid" property="id"></id>
            <result column="ordertime" property="ordertime"></result>
            <result column="total" property="total"></result>
        </collection>
    </resultMap>

    <select id="findAllUser" resultMap="userMap">
        select *, o.id oid
        from mybatis.user u,
             mybatis.orders o
        where u.id = o.uid
    </select>
</mapper>

3、编写测试

@Test
public void test2(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.findAllUser();
    userList.forEach(System.out::println);
    sqlSession.close();
}

测试结果:
在这里插入图片描述

10.3、多对多关联查询


引入中间表


11、动态SQL


动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,我们通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。例如,拼接时要确保添加了必要的空格,还要注意去掉列表最后一个列名的逗号。而动态 SQL 恰好解决了这一问题,可以根据场景动态的构建查询。

动态 SQL 只有几个基本元素,与 JSTL 或 XML 文本处理器相似,十分简单明了,大量的判断都可以在 MyBatis 的映射 XML 文件里配置,以达到许多需要大量代码才能实现的功能(注解方式配置SQL可读性差)。

动态 SQL 减少了平时编写代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。

MyBatis 动态SQL 包括以下几种元素:

  • if
  • choose (when,otherwise)
  • trim (where,set)
  • foreach

11.1、IF 标签


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白豆五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值