MyBatis学习总结(超级详细哦,尤其适合小白)

Posted 我实在是想不出什么好听的昵称了啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis学习总结(超级详细哦,尤其适合小白)相关的知识,希望对你有一定的参考价值。

什么是MyBatis?

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • MyBatis 本是apache的一个开源项目ibatis, 2010年这个项目由apache 迁移到了google code,并且改名为MyBatis 。
  • 附MyBatis官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html

MyBatis入门程序

  • MyBatis相关Jar包:(使用Maven构建)`

         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.5.2</version>
     </dependency>`
    
  • mysql数据库驱动包:`

         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>8.0.15</version>
     </dependency>`
    
  • Junit单元测试包:`

         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
     </dependency>`
    
  • XML核心配置文件(mybatis-config.xml)构建SqlSessionFactory:在这里插入图片描述

<configuration>
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybaits?serverTimezone=UTC&amp;allowPublicKeyRetrieval=true&amp;useSSL=false&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
</environments>
</configuration>
  • 创建一张user表:user表

环境搭建:

  • 提供实体类对象,(使用的是set方法注入)

public class User {
    private int id;
    private String last_name;
    private String email;

    public User() {
    }

    public User(int id, String last_name, String email) {
        this.id = id;
        this.last_name = last_name;
        this.email = email;
    }

    public int getId() {
        return id;
    }

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

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }

    public String getEmail() {
        return email;
    }

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

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

Tips:

平时为了避免不必要的麻烦,可以在设置实体类属性的时候,尽量保证其跟数据库字段名一致,当数据库字段名有下划线时候,实体类属性名可以采用驼峰命名规则。但是具体还是看要求,约定大于配置!!!后面也会有相关属性名跟字段名不一致的解决方案。
还有就是,最好自动写上get,set方法以及构造器和tostring方法。

  • 创建UserMapper接口(不需要实现类):

public interface UserMapper {
    //查询所有用户
    List<User> getUserList();
    }
  • 配置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.xxx.dao.UserMapper">
    <!--select查询所有用户语句-->
    <select id="getUserList" resultType="com.xxx.pojo.User">
        /*执行sql*/
        select * from user
    </select>
</mapper>
  • 单元测试:

  • 每个基于MyBatis 的应用都是以一个 SqlSessionFactory的实例为核心的,SqlSessionFactory 的实例可以通过SqlSessionFactoryBuilder 获得。
  • SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的Configuration 实例来构建出SqlSessionFactory 实例。
编写一个MyBatis工具类获取sqlSession对象
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    private static InputStream inputStream;

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

    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

  • 测试:

 @Test
    public void getUserList() {

        //1:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式1:getMapper,执行sql
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //3:关闭sqlSession
        sqlSession.close();
    }

以上是使用xml文件从SqlSessionFactory 中获取 SqlSession,使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
还有一种方式是:可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:(不推荐使用

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
  • 测试结果:

在这里插入图片描述

注意点和遇到的问题

  • MyBatis核心配置文件中,一定要配置mapper映射器:

 <!--每一个mapper.xml都需要在Mybatis核心配置文件中配置-->
    <mappers>
        <mapper resource="com/xxx/dao/UserMapper.xml"/>
    </mappers>
  • 单元测试中文乱码问题:可以在maven的pom文件中的标签内加入如下代码:

        <plugins>
            <plugin>
             <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12.4</version>
                <configuration>
                    <argLine>
                        -Dfile.encoding=UTF-8
                    </argLine>
                </configuration>
            </plugin>
        </plugins>
  • 添加后还是有如下问题:在这里插入图片描述这个问题我上网找了很多资料,都是说这是编码为UTF-8形式即可,但是还是一直报错,最后我自己捣鼓试了一下将UTF-8修改为UTF8,居然可以了,真是夺笋啊!!!!而且,是要将项目设计的两个UserMapper,xml和mybatis-config.xml都修改才行,如下所示:

<?xml version="1.0" encoding="UTF8" ?>
  • maven静态资源过滤问题:

相信很多人都出现过如下情况:

org.apache.ibatis.binding.BindingException: Type interface com.xxx.dao.UserMapper is not known to the MapperRegistry.

表示未绑定注册mapper,有可能是idea无法扫描到所需的xml资源,解决方法如下:在maven的pom文件中的标签内加上:

 <resources>
              <resource>
                  <directory>src/main/resources</directory>
                  <includes>
                      <include>**/*.properties</include>
                      <include>**/*.xml</include>
                  </includes>
                  <filtering>true</filtering>
              </resource>
              <resource>
                  <directory>src/main/java</directory>
                  <includes>
                      <include>**/*.properties</include>
                      <include>**/*.xml</include>
                  </includes>
                  <filtering>true</filtering>
              </resource>
          </resources>

即可扫描到src下的java和resources下的所有properties和xml资源。

MyBatis常用XML配置

  • configuration(配置)
  • properties(属性)
  • settings(设置)
  • typeAliases(类型别名)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境配置)
  • environment(环境变量)
  • transactionManager(事务管理器)
  • dataSource(数据源)
  • mappers(映射器)

注意:

configuration" 里的标签顺序如下:(否则报错如下信息)

"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?
     objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
     databaseIdProvider?,mappers?)"

具体还是建议查看文档吧,这里比较齐全:

XML配置大全

MyBatis的CRUD操作示例

  • 第一步仍然是搭建入门程序的环境。

  • 接着在UserMapper中编写CRUD操作方法:

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

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

    //添加一个用户
    int addUser(User user);

    //修改用户
    int updateUser(User user);

    //删除一个用户
    int deleteUser(int id);

}
  • 配置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.xxx.dao.UserMapper">
    <!--select查询所有用户语句-->
    <select id="getUserList" resultType="com.xxx.pojo.User">
        /*执行sql*/
        select * from user
    </select>

    <!--根据id查询用户-->
    <select id="getUserById" resultType="com.xxx.pojo.User" parameterType="_int">
        select * from mybaits.user where id =#{id}
    </select>

    <!--添加一个用户-->
    <insert id="addUser"  parameterType="com.xxx.pojo.User" >
        insert into mybaits.user(id,last_name,email) values (#{id},#{last_name},#{email})
    </insert>

    <!--修改用户-->
    <update id="updateUser" parameterType="com.xxx.pojo.User">
        update mybaits.user
        set last_name =#{last_name},email=#{email}
        where id =#{id};
    </update>

    <!--删除用户-->
    <delete id="deleteUser" parameterType="com.xxx.pojo.User">/*这里写int也可以*/
        delete from mybaits.user where id =#{id}
    </delete>

</mapper>
  • Select

以上第二个select这个语句名为:getUserById,接受一个 int(或 Integer)类型的参数,并返回一个User类型的对象,其中的键是列名,值便是结果行中的对应值。其中,参数形式为:#{}

  • Select元素常用的属性:
id 	在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType 	将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器
resultType 	期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap 	对外部 resultMap 的命名引用。结果映射是 
flushCache 	将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache 	将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
resultOrdered 	这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false。
resultSets 	这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 

Update,Insert,Delete常用属性跟Select差不多,只是个别不同,用到时候再记录。

  • 单元测试:

public class UserMapperTest {
    @Test
    public void getUserList() {

        //1:获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式1:getMapper,执行sql
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //3:关闭sqlSession
        sqlSession.close();
    }

    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(2);
        System.out.println(userById);
        sqlSession.close();
    }

    @Test
    public void addUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int addUser = mapper.addUser(new User(4, "赵丽颖", "com@zhao"));
        if(addUser>0){
            System.out.println("插入成功!");
        }
        //一定要提交事务,否则及时输出插入成功,数据库也不会有数据
        sqlSession.commit();

        sqlSession.close();
    }

    @Test
    public void updateUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int updateUser = mapper.updateUser(new User(3, "张艺兴", "com@zhang"));
        if(updateUser>0){
            System.out.println("修改成功!");
        }
        //一定要提交事务,否则及时输出插入成功,数据库也不会有数据
        sqlSession.commit();

        sqlSession.close();
    }

    @Test
    public void deleteUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int deleteUser = mapper.deleteUser(2);
        if(deleteUser>0){
            System.out.println("删除成功!");
        }else {
            System.out.println("删除失败!");
        }
        //一定要提交事务,否则即使输出插入成功,数据库也不会有数据
        sqlSession.commit();

        sqlSession.close();
    }
}

解决数据库表字段名跟属性名不一致问题:(例如:字段名为last_name,属性名为lastName,若使用resultType,查询出来lastName为NULL)

  • lastName为NULL的原因为:MyBatis的自动映射机制会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) ,
    去对应的实体类中查找相应列名的set方法设值 , 由于找不到setlastName() , 所以lastName返回null.
  • 解决方法:
    方法一:为列名指定别名 , 别名和java实体类的属性名一致 。
<select id="getUserList" resultType="com.xxx.pojo.User">
  select id , last_name as lastName , eamil from user where id = #{id}
</select>

方法二:使用结果集映射->ResultMap 【推荐】

<select id="getUserList" resultType="com.xxx.pojo.User" resultMap="userMap">
        /*执行sql*/
        select * from user
    </select>
    <resultMap id="getUserList" type="com.xxx.pojo.User">
        <result column="last_name" property="name"></result>
    </resultMap>

(注意:除了select操作,其他三种都要提交事务,否则不会报错,但是会执行失败!)

作用域(Scope)和生命周期

理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。

我们可以先画一个流程图,分析一下Mybatis的执行过程!
在这里插入图片描述

  • 作用域理解

  • SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)
  • SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期
  • 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况
  • 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域

    以上是关于MyBatis学习总结(超级详细哦,尤其适合小白)的主要内容,如果未能解决你的问题,请参考以下文章

    给想学习VIM的超级小白的文章

    超级大神珍藏的Python初学者最详细学习路线图分享

    超级小白Java学习日记

    分享适合新手小白学习的UI设计详细学习课程资料

    超级小白Java学习日记(4.17~18)

    探寻从小白成长为深度学习大佬的过程,一些超级干货分享