你好~Mybatis

<1>为什么使用mybatis框架

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

使用mybatis框架来替代原始JDBC的开发。mybatis把连接资源放在内部,想要用直接拿,用完还回来即可,有效的解决了JDBC频繁的创建、释放连接资源。而且我们使用mybatis框架,当sql语句需要发生改变的,不需要改变JAVA代码,只需要更改一下配置文件即可。

<2>mybatis执行的流程

在这里插入图片描述

<3>mybatis入门

  • 使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
  • 编写User实例

package com.liu.domain;

public class User {
    private int id;
    private String username;
    private String email;
    private String password;
    private String phoneNum;

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

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

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

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }
}
  • 编写映射文件UserMapper.xml

mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    <select id="findAll" resultType="com.liu.domain.User">
        select *from user
    </select>
</mapper>
  • 编写核心配置文件sqlMapconfig.xml

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。后面会再探讨 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">
        <!--配置一个id为development的环境-->
        <environment id="development">
            <!--使用JDBC事务-->
            <transactionManager type="JDBC"/>
            <!--数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///stu?useSSL=false&amp;useUnicode=true&amp;characterEconding=UTF-8&amp;allowPublicKeyRetrieval=true"/>
                <property name="username" value="root"/>
                <property name="password" value="131411"/>
            </dataSource>
        </environment>
    </environments>
    <!--加载映射文件-->
    <mappers>
        <mapper resource="com.liu.mapper/UserMapper.xml"/>
    </mappers>
</configuration>

当然,还有很多可以在 XML 文件中配置的选项,上面的示例仅罗列了最关键的部分。 注意 XML 头部的声明,它用来验证 XML 文档的正确性。environment 元素体中包含了事务管理和连接池的配置。

  • 编写一个测试类

进行测试是否成功

    @Test
    public void test01() throws IOException {
        //读取mybatis的配置文件得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        //根据配置文件信息,创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //通过工厂得到SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //通过sqlSession对象执行映射文件中定义的SQL,并返回映射结果
        List<User> list = sqlSession.selectList("userMapper.findAll");
        System.out.println(list);
        //关闭sqlSession,释放资源
        sqlSession.close();
    }

运行结果展示:

在这里插入图片描述

<4>mybatis增删改查

如果通过上述代码来写的话,可以发现有很多的代码是重复的。所以我们使用JUnit的@Before来创建sqlSession对象以及通过@After来关闭sqlSession,释放资源。

import com.liu.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.After;
import org.junit.Before;
import org.junit.Test;

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

public class Test1 {
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @Before
    public void init(){
        //读取mybatis的配置文件得到配置文件流
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            //根据配置文件信息,创建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //通过工厂得到SqlSession对象
            sqlSession = sqlSessionFactory.openSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //查询用户
    @Test
    public void test01() throws IOException {
        //通过sqlSession对象执行映射文件中定义的SQL,并返回映射结果
        List<User> list = sqlSession.selectList("userMapper.findAll");
        System.out.println(list);
    }
    //添加用户
    @Test
    public void test02(){
        User user = new User();
        user.setId(10);
        user.setUsername("一球");
        user.setEmail("314131@dwq");
        user.setPassword("131411");
        user.setPhoneNum("13461460194");
        int insert = sqlSession.insert("userMapper.addUser",user);
        System.out.println(insert);
    }
	//删除用户
    @Test
    public void test03(){
        int i = sqlSession.delete("userMapper.deleteByName", 10);
        System.out.println(i);
    }
    //更改用户
    @Test
    public void test04(){
        int update = sqlSession.update("userMapper.updateById", new User(3, "嘻嘻嘻嘻嘻", "dd", "ddd", "ddd"));
        System.out.println(update);
    }
    @After
    public  void destory(){
        //提交事务
        sqlSession.commit();
        //关闭sqlSession,释放资源
        sqlSession.close();
    }
}

<5>mybatisDao层实现

通过上述mybatis快速入门你会发现,我根本就没编写Dao层呀。到时候我该如何和service层进行交互呢?但这也发现了mybatis的神奇之处:mybatis不需要Dao层就可以实现增删改查。接下来让我们看一看如何使用mybatis来实现Dao层。

第一种:传统方式实现

即首先创建一个UserDao接口,在接口中编写业务方法。通过UserDaoImpl这个类来实现UserDao的方法,从而把数据返回给Service层的UserServiceImpl。

UserDao接口:

public interface UserDao {
    List<User> findAll() throws IOException;
}

UserDaoImpl接口实现:

public class UserDaoImpl implements UserDao {
    public List<User> findAll() throws IOException {
        InputStream resourceAsStream =Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        sqlSession.close();
        return userList;
    }
}

第二种:代理开发模式

采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper 接口开发需要遵循以下规范:

1、 Mapper.xml文件中的namespacemapper接口的全限定名相同

2、 Mapper接口方法名和Mapper.xml中定义的每个statementid相同

3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sqlparameterType的类型相同

4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sqlresultType的类型相同

例如:

UserDao接口:

public interface UserDao {
    List<User> findAll();
}

mapper.xml映射文件:

<mapper namespace="com.liu.dao.UserDao">
    <!--查询所有-->
    <select id="findAll" resultType="com.liu.POJO.User">
        select *from user
    </select>

UserServiceImpl测试:

public class UserServiceImpl {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userList = mapper.findAll();
        System.out.println(userList);
    }

结果:

在这里插入图片描述

<6>mybatis的核心配置文件

点击可直接进入官网详细查看:

configuration(配置)

  • properties(属性)

    properties:用于读取properties配置文件

    <!--加载属性文件-->
    <properties resource="jdbc.properties"/>
    
    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql:///stu?useSSL=false&useUnicode=true&characterEconding=UTF-8&allowPublicKeyRetrieval=true
    jdbc.user=root
    jdbc.password=131411
    
  • settings(设置)

    settings:一般我们用来配置日志文件

    配置使用log4j日志文件

    #���ȼ�ΪDEBUG����־��Ϣ�����console��file������Ŀ�ĵأ�console��file�Ķ���������Ĵ���
    log4j.rootLogger=DEBUG,console
    
    #����̨������������
    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.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
    
  • typeAliases(类型别名)

    一般用于给类起别名

    <!--给包中的类注册别名-->
        <typeAliases>
            <typeAlias type="com.liu.pojo.User" alias="User"/>
            <typeAlias type="com.liu.pojo.Orders" alias="Orders"/>
        </typeAliases>
    
  • typeHandlers(类型处理器)

    一般使用自带的类型处理器,但是当想对数据进行更改操作时可以更改重写类型处理器

    eg:数据库中的DateTime类型想输出时为Date

  • objectFactory(对象工厂)

  • plugins(插件)

    插件有很多,可以配置一个很常用的分页查询插件

    mybatis-config.xml配置如下:

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

    但是这个插件需要引入坐标

    	<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>
    

    使用的时候只需要写一行代码

     //设置分页相关参数 当前页+每页要显示的个数
       PageHelper.startPage(1,3);
    
  • environments(环境配置)

    • environment(环境变量)

      • transactionManager(事务管理器)

        一般我们配置的都是JDBC事务管理器

      • dataSource(数据源)

        dataSource配置获取

    <!--数据源环境-->
    <environments default="development">
        <!--配置一个id为development的环境-->
        <environment id="development">
            <!--使用JDBC事务-->
            <transactionManager type="JDBC"/>
            <!--数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    
  • databaseIdProvider(数据库厂商标识)

    这个几乎没用过

  • mappers(映射器)

    超级重要!!!用来加载Mapper.xml文件的!!!

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

<7>mybatismapper文件的配置

最重要的就是下面这几块了!!!

  • 首先定义mapper的命名空间
<mapper namespace="com.liu.dao.UserDao">
  • sql – 可被其它语句引用的可重用语句块。

这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。

<!--Sql片段的抽取-->
<sql id="sqlSelect">select *from user</sql>
  • select – 映射查询语句。

    这里我只列出了我认为十分重要的属性,以及他们的描述:

属性描述
id命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType**描述将会传入这条语句的参数的类全限定名或别名。**这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap**对外部 resultMap 的命名引用。**结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。

eg:在mapper.xml配置文件中写入

<!--查询所有-->
<select id="findAll" resultType="com.liu.dao.User">
    select *from user
</select>
  • insert – 映射插入语句。
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
<!--插入新User-->
<insert id="addUser" parameterType="com.liu.dao.User">
    insert into user values (#{id},#{username},#{email},#{password},#{phoneNum})
</insert>
  • update – 映射更新语句。
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
<!--更改用户信息-->
<update id="updateById" parameterType="com.liu.dao.User">
    update user set username=#{username} where id=#{id}
</update>
  • delete – 映射删除语句。
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
<!--删除用户-->
<delete id="deleteByName" parameterType="java.lang.Integer">
    delete from user where id=#{id}
</delete>
  • #{}

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。

<8>mybatis的动态SQL

动态SQL:根据不同条件拼接 SQL 语句

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。

  • if

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。

 <!--动态SQL-->
<select id="findBySome" resultType="com.liu.pojo.User" parameterType="com.liu.pojo.User">
    select *from user
    <where>
        <if test="id!=null">
            id=#{id}
        </if>
        <if test="username!=null">
            and username=#{username}
        </if>
        <if test="password!=null">
            and password=#{password}
        </if>
    </where>
</select>

测试:

public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User user = new User();
        user.setId(1);
        user.setUsername("GG");
        User user1 = new User();
        user1.setId(2);
        List<User> userList = mapper.findBySome(user);
        System.out.println(userList);
        List<User> bySome = mapper.findBySome(user1);
        System.out.println(bySome);
    	sqlSession.close();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nOPOdgdj-1603351515606)(https://shop.io.mi-img.com/app/shop/img?id=shop_177e47475fd61ba1217cc93fcaeb2891.png)]

  • foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。

<!--通过多个id查询用户数据-->
    <select id="findByIds" parameterType="list" resultType="com.liu.pojo.User">
        select *from user
        <where>
            <foreach collection="list" open="id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

测试:

 public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
      List<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(10);
        arrayList.add(1);
        List<Integer> arrayList1 = new ArrayList<Integer>();
        arrayList1.add(2);
        arrayList1.add(4);
        List<User> mapperByIds = mapper.findByIds(arrayList);
        for (User mapperById : mapperByIds) {
            System.out.println(mapperById);
        }
        List<User> userList = mapper.findByIds(arrayList1);
        for (User user : userList) {
            System.out.println(user);
        }
     	sqlSession.close();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjWTBTBT-1603351515608)(https://shop.io.mi-img.com/app/shop/img?id=shop_65178e8af9b99cffec88dcc3150d1888.png)]

<9>mybatis的多表查询

接下来的就是重点啦~

学会使用了简单的Crud,现在有一个问题出现在我们面前。上述说的crud都是单表的操作,那么双表的操作该如何用mybatis实现呢?

多表操作无非就是三种:一对一,一对多,多对多

  • 一对一

一对一我们应该要如何实现呢?

这里是关于用户和订单的业务,我们要查询每个订单的用户都是谁。我们该如何去做呢?

1.这时我们需要把要查询的用户封装订单的一个属性并生成get/set方法

public class Orders {
    private int id;
    private Date orderTime;
    private int total;
    //注意看这:*****把用户封装成订单的一个属性
    private User user;
	//重写toString方法
    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", orderTime=" + orderTime +
                ", total=" + total +
                ", 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 int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }
	//生成get/set
    public User getUser() {
        return user;
    }

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

2.创建OrdersDao,并且写一个查询抽象方法。

public interface OrdersDao {
   List<Orders> findAll();
}

3.在OrdersMapper.xml中进行配置:

这里的结果集我们需要自己进行封装,所以我们不能用resultType

我们需要使用resultMap进行自己封装

resultMapMybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。**

resultMap包含的元素:

<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
  <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
  <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
  <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
    <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/>
    <result  column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
  </association>
  <!-- 集合中的property须为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性" ofType="集合中的pojo对象">
    <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" /> 
  </collection>
</resultMap>
<resultMap id="findUserOrder" type="Orders">
    <!--手动指定字段与实体属性的映射关系
            column:数据库的字段名称
            property:实体的属性名称
        -->
    <id column="oid" property="id"/>
    <result column="orderTime" property="orderTime"/>
    <result column="total" property="total"/>
    <result column="uid" property="user.id"/>
    <result column="username" property="user.username"/>
    <result column="email" property="user.email"/>
    <result column="password" property="user.password"/>
    <result column="phoneNum" property="user.phoneNum"/>
</resultMap>
<select id="findAll" resultMap="findUserOrder">
    SELECT *,u.id usid,o.id oid
    from user u,orders o
    where u.id=o.uid;
</select>

上面的配置使用逻辑不好,请看下面的逻辑

<resultMap id="findUserOrder" type="Orders">
        <!--手动指定字段与实体属性的映射关系
            column:数据库的字段名称
            property:实体的属性名称
        -->
        <id column="oid" property="id"/>
        <result column="orderTime" property="orderTime"/>
        <result column="total" property="total"/>
        <!--
        association标签:
            property:当前实体中的属性名称(private User user)
            javaType:当前实体中属性的类型(User)
        -->
        <association property="user" javaType="User">
            <id column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="email" property="email"/>
            <result column="password" property="password"/>
            <result column="phoneNum" property="phoneNum"/>
        </association>
    </resultMap>
    <select id="findAll" resultMap="findUserOrder">
        SELECT *,u.id usid,o.id oid
        from user u,orders o
        where u.id=o.uid;
    </select>

4.测试:

    //一对一多表查询
    @Test
    public void TestFindAll(){
        OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
        List<Orders> ordersList = ordersDao.findAll();
        for (Orders orders : ordersList) {
            System.out.println(orders);
        }
        sqlSession.close();
    }

在这里插入图片描述

  • 一对多

一对多的过程与一对一的过程只差了一点点:

业务:一个User有多个Order,要查询User的Order

1.我们首先在User里要封装一个list集合,这个集合的泛型是Order类型

package com.liu.pojo;

import java.util.List;

public class User {
    private int id;
    private String username;
    private String email;
    private String password;
    private String phoneNum;

    //描述的是当前用户存在哪些订单
    private List<Orders> orders;

    //生成get/set方法
    public List<Orders> getOrders() {
        return orders;
    }

    public void setOrders(List<Orders> orders) {
        this.orders = orders;
    }

    public User() {
    }

    public User(int id, String username, String email, String password, String phoneNum) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.password = password;
        this.phoneNum = phoneNum;
    }
	//重写toString方法
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", phoneNum='" + phoneNum + '\'' +
                ", orders=" + orders +
                '}';
    }

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

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

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }
}

2.在UserDao中创建一个方法

public interface UserDao {
    List<User> findOrders();
}

3.在UserMapper.xml中进行配置

因为orders属性是一个集合,所以要用到resultMapcollection标签:

  <!-- 集合中的property须为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性" ofType="集合中的pojo对象">
    <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" /> 
  </collection>

配置如下:

<resultMap id="userFindOrders" type="User">
    <id column="uid" property="id"/>
    <result column="username" property="username"/>
    <result column="email" property="email"/>
    <result column="password" property="password"/>
    <result column="phoneNum" property="phoneNum"/>
    <collection property="orders" ofType="Orders">
        <id column="oid" property="id"/>
        <result column="orderTime" property="orderTime"/>
        <result column="total" property="total"/>
    </collection>
</resultMap>
<select id="findOrders" resultMap="userFindOrders">
    select *,o.id oid,u.id uid from user u,orders o where u.id=o.uid;
</select>

4.进行Test测试

 //一对多查询
    @Test
    public void TestUserFindOrders(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.findOrders();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

在这里插入图片描述

  • 多对多

多对多的查询与一对多几乎是一样的,除了多了一个中间表

业务介绍:我们现在有一张user表,一张role表,还有一张连接表userrole。现在我们需要知道User是什么职位的。

1.首先封装一个list集合,一个user可能有多个role,而一个role可能有多个user。所以我们需要封装一个List,泛型为role.

Role类:

package com.liu.pojo;

public class Role {
    private int id;
    private String rolename;
    private String roleDesc;

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", rolename='" + rolename + '\'' +
                ", roleDesc='" + 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;
    }
}

User类

package com.liu.pojo;

import java.util.List;

public class User {
    private int id;
    private String username;
    private String email;
    private String password;
    private String phoneNum;

    //描述的是当前用户存在哪些订单
    private List<Orders> orders;

    //查询当前用户有几个职位
    private List<Role> roleList;

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

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

    public List<Orders> getOrders() {
        return orders;
    }

    public void setOrders(List<Orders> orders) {
        this.orders = orders;
    }

    public User() {
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", phoneNum='" + phoneNum + '\'' +
                ", orders=" + orders +
                ", 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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

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

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }
}

2.在UserDao创建一个方法

public interface UserDao {
    List<User> findUserAndRoleAll();
}

3.在UserMapper.xml进行配置

<resultMap id="UserAndRole" type="User">
    <id column="userId" property="id"/>
    <result column="username" property="username"/>
    <result column="email" property="email"/>
    <result column="password" property="password"/>
    <result column="phoneNum" property="phoneNum"/>
    <collection property="roleList" ofType="Role">
        <id column="roleId" property="id"/>
        <result property="rolename" column="rolename"/>
        <result property="roleDesc" column="roleDesc"/>
    </collection>
</resultMap>
<select id="findUserAndRoleAll" resultMap="UserAndRole">
    SELECT *
    from `user` u,role r,userrole ur
    where u.id=ur.userId
    and r.id=ur.roleId;
</select>

4.测试:

 //测试多对多查询
    @Test
    public void TestUserAndRole(){
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userAndRoleAll = mapper.findUserAndRoleAll();
        for (User user : userAndRoleAll) {
            System.out.println(user);
        }
        sqlSession.close();
    }
[com.liu.dao.UserDao.findUserAndRoleAll]-==>  Preparing: SELECT * from `user` u,role r,userrole ur where u.id=ur.userId and r.id=ur.roleId;
[com.liu.dao.UserDao.findUserAndRoleAll]-==> Parameters: 
[com.liu.dao.UserDao.findUserAndRoleAll]-<==      Total: 4
User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=1, rolename='院长', roleDesc='负责所有'}, Role{id=2, rolename='研究员', roleDesc='课程研发'}, Role{id=3, rolename='dd', roleDesc='dd'}]}
User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=4, rolename='辅导员', roleDesc='帮助学生进行学习、生活等等'}]}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2145b572]
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2145b572]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 558216562 to pool.

<10>mybatis的注解开发

每一个框架肯定是要有注解的,所以我们需要学习注解开发来简易开发流程。

  • @Insert:实现新增

  • @Update:实现更新

  • @Delete:实现删除

  • @Select:实现查询

  • @Result:实现结果集封装

  • @Results:可以与@Result 一起使用,封装多个结果集

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

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

  • 普通的增删改查

配置mybatis-config.xml核心配置文件:加载映射关系TODO

<!--加载映射关系 TODO-->
<mappers>
    <package name="com.liu.dao"/>
</mappers>

基本注解的使用:

public interface UserDao {
    @Select("select *from user")
    List<User> findAll();

    @Select("select *from user where id=#{id}")
    User findById(int id);

    @Update("update user set username=#{username} where id=#{id}")
    int updateUser(User user);

    @Insert("insert into user values (#{id},#{username},#{email},#{password},#{phoneNum})")
    int insertUser(User user);

    @Delete("delete from user where id=#{id}")
    int deleteUser(int id);
}

基本注解测试:

public class Test01 {
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @Before
    public void init(){
        //读取mybatis的配置文件得到配置文件流
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            //根据配置文件信息,创建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //通过工厂得到SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @After
    public void delect(){
        sqlSession.close();
    }
   @Test
    public void save(){
       User user = new User();
       user.setId(13);
       user.setUsername("哈哈");
       user.setPassword("131411");
       user.setEmail("7733333@qq.com");
       user.setPhoneNum("13141414");
       UserDao mapper = sqlSession.getMapper(UserDao.class);
       int i = mapper.insertUser(user);
       System.out.println(i);
   }
   @Test
    public void findUser(){
       UserDao mapper = sqlSession.getMapper(UserDao.class);
       List<User> userList = mapper.findAll();
       for (User user : userList) {
           System.out.println(user);
       }
   }
   @Test
    public void findByIdUser(){
       UserDao userDao = sqlSession.getMapper(UserDao.class);
       User users = userDao.findById(1);
       System.out.println(users);
   }
   @Test
    public void deleteUser(){
       UserDao userDao = sqlSession.getMapper(UserDao.class);
       int i = userDao.deleteUser(13);
       System.out.println(i);
   }
   @Test
    public void updateUser(){
       UserDao userDao = sqlSession.getMapper(UserDao.class);
       User user = new User();
       user.setId(1);
       user.setUsername("Hello!!!");
       int i = userDao.updateUser(user);
       System.out.println(i);
   }
}
  • 多表查询

实现复杂关系映射之前我们可以在映射文件中通过配置resultMap来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置

注解说明
@Results代替的是标签resultMap该注解中可以使用单个@Result注解,也可以使用@Result集合。使用格式:@Results({@Result(),@Result()})或@Results(@Result())
@Resut代替了id标签和result标签 @Result中属性介绍: column:数据库的列名 property:需要装配的属性名 one:需要使用的@One 注解(@Result(one=@One)())) many:需要使用的@Many 注解(@Result(many=@many)()))
注解说明
@One (一对一)代替了assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 @One注解属性介绍: select: 指定用来多表查询的 sqlmapper使用格式:@Result(column=" “,property=”",one=@One(select=""))
@Many (多对一)代替了collection标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。 使用格式:@Result(property="",column="",many=@Many(select=""))
  • 一对一

public interface OrdersDao {
/*   @Select(" SELECT *,u.id usid,o.id oid from user u,orders o where u.id=o.uid;")
   @Results({
           @Result(column = "oid",property = "id"),
           @Result(column = "orderTime",property = "orderTime"),
           @Result(column = "total",property = "total"),
           @Result(column = "uid",property = "user.id"),
           @Result(column = "username",property = "user.username"),
           @Result(column = "email",property = "user.email"),
           @Result(column = "password",property = "user.password"),
           @Result(column = "phoneNum",property = "user.phoneNum")
   }
   )*/
   @Select("SELECT * from orders")
   @Results({
           @Result(column = "id",property = "id"),
           @Result(column = "orderTime",property = "orderTime"),
           @Result(column = "total",property = "total"),
           @Result(
                   property = "user",//要封装的属性名称
                   column = "uid",//根据那个字段去查询user表的数据
                   javaType = User.class,//要封装的实体类型
                   //select属性 代表查询那个接口的方法获取数据
                   one = @One(select = "com.liu.dao.UserDao.findById")
           )
   })
   List<Orders> findAllAndUser();
}

测试:

   @Test
    public void findOrderAndUser(){
       OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
       List<Orders> ordersList = ordersDao.findAllAndUser();
       for (Orders orders : ordersList) {
           System.out.println(orders);
       }
   }

日志文件:

[com.liu.dao.OrdersDao.findAllAndUser]-==>  Preparing: SELECT * from orders
[com.liu.dao.OrdersDao.findAllAndUser]-==> Parameters: 
[com.liu.dao.UserDao.findById]-====>  Preparing: select *from user where id=?
[com.liu.dao.UserDao.findById]-====> Parameters: 1(Integer)
[com.liu.dao.UserDao.findById]-<====      Total: 1
[com.liu.dao.UserDao.findById]-====>  Preparing: select *from user where id=?
[com.liu.dao.UserDao.findById]-====> Parameters: 2(Integer)
[com.liu.dao.UserDao.findById]-<====      Total: 1
[com.liu.dao.OrdersDao.findAllAndUser]-<==      Total: 3
Orders{id=1, orderTime=Tue Oct 20 13:00:00 CST 2020, total=3000, user=User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}}
Orders{id=2, orderTime=Thu Oct 01 13:00:00 CST 2020, total=2000, user=User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}}
Orders{id=3, orderTime=Fri Oct 09 13:00:00 CST 2020, total=4000, user=User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=null}}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@be64738]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 199640888 to pool.
  • 一对多

UserDao中创建方法

//多表查询:一对多
@Select("select *from user")
@Results({
    @Result(id = true,column = "id",property ="id" ),
    @Result(column = "username",property = "username"),
    @Result(column = "email",property = "email"),
    @Result(column = "password",property = "password"),
    @Result(column = "phoneNum",property = "phoneNum"),
    @Result(
        property = "orders",
        column = "id",
        javaType =List.class,
        //这里发现我们要用OrdersDao的findById方法
        many = @Many(select = "com.liu.dao.OrdersDao.findById")
    )

})
List<User> findUserAndRole();

OrdersDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。

@Select("select *from orders where uid=#{uid}")
List<Orders> findById();

测试:

//测试一对多
@Test
public void findUserAndRole1(){
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.findUserAndRole();
    for (User user : userList) {
        System.out.println(user);
    }
}

测试日志结果:

[com.liu.dao.UserDao.findUserAndRole]-==>  Preparing: select *from user
[com.liu.dao.UserDao.findUserAndRole]-==> Parameters: 
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 1(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 2
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 2(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 1
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 3(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 0
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 4(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 0
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 10(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 0
[com.liu.dao.OrdersDao.findById]-====>  Preparing: select *from orders where uid=?
[com.liu.dao.OrdersDao.findById]-====> Parameters: 11(Integer)
[com.liu.dao.OrdersDao.findById]-<====      Total: 0
[com.liu.dao.UserDao.findUserAndRole]-<==      Total: 6
User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=[Orders{id=1, orderTime=Tue Oct 20 00:00:00 CST 2020, total=3000, user=null}, Orders{id=3, orderTime=Fri Oct 09 00:00:00 CST 2020, total=4000, user=null}], roleList=null}
User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=[Orders{id=2, orderTime=Thu Oct 01 00:00:00 CST 2020, total=2000, user=null}], roleList=null}
User{id=3, username='嘻嘻嘻嘻嘻', email='eeeeeeeeeeeeee', password='eeeeeeeeeeeee', phoneNum='eeeeeeeeeeeee', orders=[], roleList=null}
User{id=4, username='liuchang', email='773395726@qq.com', password='ed', phoneNum='dd', orders=[], roleList=null}
User{id=10, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=[], roleList=null}
User{id=11, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=[], roleList=null}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@be64738]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 199640888 to pool.
  • 多对多

UserDao中创建方法

//测试多对多
@Select("select *from user")
@Results({
    @Result(id = true,column = "id",property ="id" ),
    @Result(column = "username",property = "username"),
    @Result(column = "email",property = "email"),
    @Result(column = "password",property = "password"),
    @Result(column = "phoneNum",property = "phoneNum"),
    @Result(
        property = "roleList",
        column = "id",
        javaType =List.class,
        many = @Many(select = "com.liu.dao.RoleDao.findByUid")
    )})
List<User> findUserRoleAll();

RoleDao方法:把select *from user查到的uid传给这个方法,通过这个方法得到一些Orders,再把这些Order给封装到User的orders属性中。

public interface RoleDao {
    @Select("select * from role r,userrole ur where r.id=ur.roleId and ur.userId=#{uid}")
    List<Role> findByUid(int uid);
}

测试:

//测试多对多
@Test
public void findUserAndRoles(){
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.findUserRoleAll();
    for (User user : userList) {
        System.out.println(user);
    }
}

测试日志:

[com.liu.dao.UserDao.findUserRoleAll]-==>  Preparing: select *from user
[com.liu.dao.UserDao.findUserRoleAll]-==> Parameters: 
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 1(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 3
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 2(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 1
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 3(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 0
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 4(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 0
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 10(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 0
[com.liu.dao.RoleDao.findByUid]-====>  Preparing: select * from role r,userrole ur where r.id=ur.roleId and ur.userId=?
[com.liu.dao.RoleDao.findByUid]-====> Parameters: 11(Integer)
[com.liu.dao.RoleDao.findByUid]-<====      Total: 0
[com.liu.dao.UserDao.findUserRoleAll]-<==      Total: 6
User{id=1, username='Hello!!!', email='773395726@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=1, rolename='院长', roleDesc='负责所有'}, Role{id=2, rolename='研究员', roleDesc='课程研发'}, Role{id=3, rolename='dd', roleDesc='dd'}]}
User{id=2, username='王爽', email='1212313131@qq.com', password='131411', phoneNum='13461460194', orders=null, roleList=[Role{id=4, rolename='辅导员', roleDesc='帮助学生进行学习、生活等等'}]}
User{id=3, username='嘻嘻嘻嘻嘻', email='eeeeeeeeeeeeee', password='eeeeeeeeeeeee', phoneNum='eeeeeeeeeeeee', orders=null, roleList=[]}
User{id=4, username='liuchang', email='773395726@qq.com', password='ed', phoneNum='dd', orders=null, roleList=[]}
User{id=10, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=null, roleList=[]}
User{id=11, username='一球', email='314131@dwq', password='131411', phoneNum='13461460194', orders=null, roleList=[]}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@49d904ec]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1238959340 to pool.

Process finished with exit code 0

<11>mybatis总结

大家在开始学习mybatis插件的时候可以下载一个插件,可以通过这个插件就能像Spring查看方法的定义之处。

在这里插入图片描述

在这里插入图片描述

这算是第二遍学习mybatis了,还不错。过去学的东西忘了好多,但是学习过后,有的东西都加深了理解。以前很多不会的知识,现在懂了很多。要加油哦~接下来就要学习mybatis-plus,不知道这个难度如何。感觉这个应该和mybatis差距不大,毕竟是基于mybatis的。加油!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值