什么是 MyBatis?

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

获取 MyBatis

因为已经搬到了GitHub,可以直接去GitHub上下载,最简单的当然还是使用Maven获取。

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>

什么是数据持久化?

持久化是将程序数据在持久状态和瞬时状态间转换的机制。

  • 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。

 

为什么需要Mybatis?

主要就是简化了jdbc操作,能够更方便的操作数据库。

Mybatis特点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql。

Mybatis环境配置

可以直接使用Maven配置导入依赖就行,需要导入的依赖也就是mysql驱动,mybatis,Junit

<dependencies>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.20</version>
    </dependency>

    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>
    <!-- junit -->
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
    </dependency>


</dependencies>

 

然后需要创建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>
    <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/tp5?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="heyexi/dao/UserMapper.xml"/>
    </mappers>
</configuration>

这个就是配置连接数据库而已。

然后就可以创建一个MybatisUtil包,用来获取可以操作数据的对象。

 

package heyexi.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils
{
    private static SqlSessionFactory sqlSessionFactory;

    //静态加载mybatis的核心配置文件
    static
    {
        try
        {
            //获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    //获取SqlSession对象
    public static SqlSession getSqlSession()
    {
        return sqlSessionFactory.openSession();
    }
}

 

SqlSessionFactory的用来创建SqlSession对象的,SqlSession又是拿来操作数据库的。

然后我们创建一个实体类,如下:

package heyexi.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User
{
    private Integer id;
    private String name;
    private Integer age;
    private String tel;
}

 

然后创建这个实体类的dao

package heyexi.dao;

import heyexi.pojo.User;
import java.util.List;

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

定义了接口以后,原来需要去实现这个接口,然后在里面写jdbc的代码,但是现在不用去实现了,直接写一个配置文件,相当于是实现了接口。也就是由原来的Impl变为Mapper配置文件。

注意点:

●接口和他的Mapper配置文件必须同名!

●接口和他的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="heyexi.dao.UserDao">

    <select id="selectUserList" resultType="heyexi.pojo.User">
        select * from tp5.user;
    </select>
</mapper>

 

如上,namespace代表的是命名空间,也就是需要指定dao的接口文件的地址。

select标签就是代表执行查询语句,然后id是代表接口中实现的方法名。

resultType是代表返回值的类型,这个可以直接指定我们要返回的实体类。

小注意:有时候xml在Maven文件中会无法导出,所以可以一开始就在pom中添加导出配置文件的标记,就是怕Maven打包的时候没有打包xml等配置文件。

<!-- 配置资源文件,防止资源导出出现问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

然后我们就可以来测试一下了!

package heyexi.dao;

import heyexi.pojo.User;
import heyexi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest
{
    @Test
    public void test()
    {
        //获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);

        List<User> users = userDao.selectUserList();
        for(User user:users)
        {
            System.out.println(user);
        }
    }
}

输出结果:
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
User(id=36, name=何夜息, age=99, tel=1821548748)

 

Mybatis的CRUD

现在可以弄一个根据id查询用户:

package heyexi.dao;

import heyexi.pojo.User;
import java.util.List;

public interface UserDao
{
    //查询所有用户
    List<User> selectUserList();

    //根据id查询用户
    User selectUserById(int id);
}

然后用配置文件实现一下:

<?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="heyexi.dao.UserDao">

    <select id="selectUserList" resultType="heyexi.pojo.User">
        select * from users;
    </select>

    <select id="selectUserById" parameterType="int" resultType="heyexi.pojo.User">
        select * from tp5.users where id=#{id};
    </select>
</mapper>

 上面的#{XX}代表的是参数的占位符,如果传入的是实体类,xx必须是实体对象的属性名!

然后测试:

package heyexi.dao;

import heyexi.pojo.User;
import heyexi.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest
{
    @Test
    public void test()
    {
        //获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);

        User user = userDao.selectUserById(36);
        System.out.println(user);
    }
}

输出:
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
User(id=36, name=何夜息, age=99, tel=1821548748)

 

SQL传参除了可以使用基本数据类型和传实体外,如果有多个参数,可以使用map进行传参!

例如定义添加用户方法2

package heyexi.dao;

import heyexi.pojo.User;
import java.util.List;
import java.util.Map;

public interface UserDao
{
    //查询所有用户
    List<User> selectUserList();

    //根据id查询用户
    User selectUserById(int id);

    //插入用户
    int insertUser(User user);

    //插入用户2
    int insertUser2(Map<String,Object> user);
}

在配置中,参数类型要选择map,最重要的是,下面的#{参数名},中的参数名,一定是map中的key的值!

<?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="heyexi.dao.UserDao">

    <select id="selectUserList" resultType="heyexi.pojo.User">
        select * from users;
    </select>

    <select id="selectUserById" parameterType="int" resultType="heyexi.pojo.User">
        select * from tp5.users where id=#{uid};
    </select>

    <!--    添加用户-->
    <insert id="insertUser" parameterType="heyexi.pojo.User">
        insert into tp5.users(name,age,tel) values (#{name},#{age},#{tel});
    </insert>

    <!--    添加用户2-->
    <insert id="insertUser2" parameterType="map">
        insert into users(name,age,tel) values (#{uName},#{uAge},#{uTel});
    </insert>
</mapper>

 然后在测试类中测试:

@Test
public void test3()
{
     SqlSession sqlSession = MybatisUtils.getSqlSession();

     UserDao userDao = sqlSession.getMapper(UserDao.class);

     Map<String,Object> user = new Hashtable<String, Object>();
     user.put("uName","刘德华");
    user.put("uAge",45);
    user.put("uTel","18784784");

    int s = userDao.insertUser2(user);
    System.out.println(s);
    sqlSession.close();
}

Map传递参数,直接在sq|中取出key即可! [parameterType="map"]

对象传递参数,直接在sq|中取对象的属性即可! [parameterType="Object"]

只有一个基本类型参数的情况下,可以直接在sq|中取到!

多个参数用Map,或者注解!

ResultMap结果集映射

这个存在的目的是:我们都知道Javabean的属性名要和数据库中的表的字段名保持一致,这个xml中返回的实体才能获得他的属性值,那么如果我们的Javabean的属性名和字段名不一致呢?就要使用这个resultmap来解决了。

这个的实现思路就是:在xml配置中吧restultType变为ResultMap,然后指定resultMap的id,然后创建这个resultMap标签,在里面依次把字段值赋值给属性值。

比如我们新建一个表:

@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class Book
{
    private Integer id;
    private String bookName;
    private float price;
}

 可以看到价格的属性和字段是不一样的,然后我创建dao

package heyexi.dao;

import heyexi.pojo.Book;

import java.util.List;

public interface BookMapper
{
    List<Book> getBooks();
    Book getBookById(int id);
}

然后新建一个配置文件:

<?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="heyexi.dao.BookMapper">
    <resultMap id="Book" type="heyexi.pojo.Book">
        <result column="id" property="id" />
        <result column="bookName" property="bookName" />
        <result column="bookPrice" property="price" />
    </resultMap>

    <select id="getBookById" resultMap="Book" parameterType="int">
        select * from books where id=#{id};
    </select>

</mapper>

 

可以看到,select中的resultMap要指向上面的resultMap的id属性值,然后在resultMap中的type类型我们需要指定要表示的实体,相当于resultMap是一个中间件!然后里面就依次把属性和字段对应起来!column代表的是数据库的字段,property代表的是实体类的属性。

注意:属性和字段相同的可以不写,只写不一样的就行!

然后在测试类测试一下!

@Test
public void test1()
{
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BookMapper bookMapper = sqlSession.getMapper(BookMapper.class);

    Book book = bookMapper.getBookById(1);
    System.out.println(book);
}

输出结果为:
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
Book(id=1, bookName=活着, price=25.6)

这个在多表查询的时候就要用到!