Mybatis

MyBatis是一个优秀的持久层框架,简化了JDBC的繁琐工作,提供了SQL映射文件和注解两种方式来管理SQL语句。本文详细介绍了Mybatis与JDBC的区别、Mybatis的使用步骤、映射文件的重点内容,以及如何编写测试方法。通过注解和XML文件结合使用,Mybatis能够灵活地应对复杂和简单的SQL需求,同时解决了JDBC中数据库连接管理、SQL语句维护等问题,提高了系统的可维护性和性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

Mybatis和JDBC的对比

通过上面的介绍,我们知道 MyBatis 是来和数据库打交道。那么在这之前,我们是使用 JDBC 来对数据库进行增删改查等一系列操作的,而我们之所以会放弃使用 JDBC,转而使用 MyBatis 框架,这是为什么呢?或者说使用 MyBatis 对比 JDBC 有什么好处?

数据类型转换 => 交给框架
数据校验 => 交给框架
将增删改查集中管理  => 交给框架
异常的统一处理
简化jdbc => 交给框架
使用框架组合各种技术

上面的这些问题我们都可以规避掉,将它们交给框架去管理;
而这个框架就是Mybatis,那我们就来学习一下Mybatis;

Mybatis使用

使用步骤:

  1. 添加依赖
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
  1. 添加配置文件 mybatis-config.xml
    用这个配置文件来告诉 mybatis 如何连接数据库
    告诉 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"/>
            <!-- 配置了 mybatis 连接数据库的信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--向 mybatis-config.xml 配置文件中注册 StudentMapper.xml 文件 -->
    <mappers>
        <!-- 指定映射文件的位置 包名+文件名(文件路径)-->
        <mapper resource="mapper/StudentMapper.xml"/>
    </mappers>
</configuration>
  1. 提供一个 映射文件
    用来管理 sql 语句,描述 sql 语句与数据库表之间的映射关系

  2. 调用 mybatis api 使用映射文件真正执行增删改查
    Configuration 对应 mybatis-config.xml

SqlSessionFactory 用来创建 SqlSession 的

SqlSession (接口)
.insert
.update
.delete
.selectOne
.selectList

Mybatis 映射文件(重点)

<?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(命名空间) 用来防止 sql 的命名冲突的 -->
<mapper namespace="mapper.StudentMapper">

新增

<!-- #{sname} 用来获取 Student 参数对象中的 sname属性-->
<!-- useGeneratedKeys="true" 是告诉 mybatis 要使用由数据库产生的主键值 -->
<!-- keyProperty="主键对应的属性名" -->
<insert id="abc" parameterType="domain.Student"
        useGeneratedKeys="true" keyProperty="sid">
    insert into student(sid, sname, birthday, sex)
        values ( null, #{name}, #{birthday}, #{sex})
</insert>

删除

<delete id="delete" parameterType="int">
    delete from student where sid = #{sid}
</delete>

查询所有

<select id="findAll" resultType="domain.Student">
    select sid,sname name,birthday,sex from student
</select>

根据id查询

<select id="findById" resultType="domain.Student" parameterType="int">
    select sid,sname name,birthday,sex from student where sid = #{sid}
</select>

更新

<update id="update" parameterType="domain.Student">
    update student set sname=#{name}, birthday=#{birthday}, sex=#{sex} where sid=#{sid}
</update>
<!-- 动态更新列
Student stu = new Student();
stu.setSid(1001);
stu.setSex("男");

update student set sex=#{sex} where sid=#{sid}
用  set 标签可以去除多余的逗号
-->
<update id="update" parameterType="domain.Student">
    update student
    <set>
        <if test="name != null">
            sname=#{name},
        </if>
        <if test="birthday != null">
            birthday=#{birthday},
        </if>
        <if test="sex != null">
            sex=#{sex},
        </if>
    </set>
    where sid=#{sid}
</update>

分页查询

<!-- m , n
java.util.Map -> map
java.util.List -> list
java.lang.String -> string
map.put("m", 0);
map.put("n", 5);
-->
<select id="findByPage" parameterType="map" resultType="domain.Student">
    select sid,sname name,birthday,sex from student limit #{m}, #{n}
</select>

多条删除,条件查询


<!--
    (1008,1011,1012
    delete from student where id in (1008,1011,1012)-->
    <delete id="deleteByIds" parameterType="list">
        delete from student where sid in
        <foreach collection="list" item="x" open="(" close=")" separator=",">#{x}</foreach>
    </delete>

    <!-- map
    sname=?
    birthday=?
    sex=?
    -->
    <!--<select id="findByCondition" parameterType="map" resultType="domain.Student">
        select sid,sname name,birthday,sex from student
          where 1=1
          <if test="sname!=null">
              and sname = #{sname}
          </if>
          <if test="birthday!=null">
              and birthday = #{birthday}
          </if>
          <if test="sex != null">
              and sex = #{sex}
          </if>
    </select>-->

    <select id="findByCondition" parameterType="map" resultType="domain.Student">
        select sid,sname name,birthday,sex from student
        <where> <!-- 可以用 where 去除多余的 and -->
            <if test="testname!=null">
                and sname = #{testname}
            </if>
            <if test="birthday!=null">
                and birthday = #{birthday}
            </if>
            <if test="sex != null">
                and sex = #{sex}
            </if>
        </where>
    </select>
</mapper>

测试方法编写

    public class TestStudentMapper {
        static SqlSessionFactory factory;
        static {
            // 读取配置文件
            try(InputStream in = Resources.getResourceAsStream("mybatis-config.xml")){
                // 创建 sqlSession 工厂类
                factory = new SqlSessionFactoryBuilder().build(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Test
        public void testInsert() throws IOException {
    
            // 创建 sqlSession, 这里的 session 更类似于 jdbc 中的 Connection
            SqlSession sqlSession = factory.openSession();
    
    
            // 执行新增
            Student stu = new Student();
            stu.setName("李五");
            stu.setBirthday(new Date());
            stu.setSex("男");
            // 参数1 : namespace+sql_id ,  参数2: 传递sql语句需要的java对象
            sqlSession.insert("mapper.StudentMapper.abc", stu );
    
            // 执行 增删改, 没有启用自动提交事务
            sqlSession.commit();
    
            System.out.println("sid的值:" + stu.getSid());
    
            // 关闭资源
            sqlSession.close();
        }
 }

这里要注意,我们使用mybatis时要创建一个sqlsessionFactory的工厂类,sqlsession 接口中有各种操作数据的常用方法,方法参数则对应你映射文件中的sql语句

sqlSession.insert(“mapper.StudentMapper.abc”, stu );
参数一对应StudnetMapper.xml中命名好的mapper中的方法

<!-- namespace(命名空间) 用来防止 sql 的命名冲突的 -->
<mapper namespace="mapper.StudentMapper">
    <!-- #{sname} 用来获取 Student 参数对象中的 sname属性-->
    <!-- useGeneratedKeys="true" 是告诉 mybatis 要使用由数据库产生的主键值 -->
    <!-- keyProperty="主键对应的属性名" -->
    <insert id="abc" parameterType="domain.Student"
            useGeneratedKeys="true" keyProperty="sid">
        insert into student(sid, sname, birthday, sex)
          values ( null, #{name}, #{birthday}, #{sex})
    </insert>

参数二代表你映射文件需要的参数对象,stu 是domain.Student类的学生对象;


基于注解的mybatis(注解+XML文件)

其他的操作和上面的一样,而不一样的一点是,我们可以不用XML文件进行sql语句的映射了;这次我们定义一个接口,当中定义的方法上直接加入注解,参数写入我们对应的sql语句就达到了原来的效果了;

首先:
向 mybatis-configuration.xml 配置文件中注册 UserMapper.java 文件

<mappers>
        <!-- 指定映射接口的 包名.类名 -->
        <mapper class="mapper.StudentMapper"></mapper>
    </mappers>
public interface StudentMapper {

    @Insert("insert into student(sid,sname,birthday,sex) values(null,#{sname}, #{birthday}, #{sex})")
    @Options(useGeneratedKeys = true, keyProperty = "sid")
    void insert(Student student);

    @Update("update student set sname=#{sname}, birthday=#{birthday}, sex=#{sex} where sid=#{sid}")
    void update(Student student);

    @Delete("delete from student where sid=#{sid}")
    void delete(int sid);

    @Select("select * from student")
    List<Student> findAll();

    @Select("select * from student where sid = #{sid}")
    Student findById(int sid);

    @Select("select * from student limit #{m}, #{n}")
    List<Student> findByPage(Map map);

    // 同时根据姓名和性别查询
    //多参数的时候需要使用@Param注解,给传入的参数做对应
    @Select("select * from student where sname=#{a} and sex=#{b}")
    List<Student> find1(@Param("a") String sname, @Param("b") String sex);

    /*
    方法不能重载
    @Select("select * from student where sname=#{a}")
    List<Student> find1(String sname);*/

    @Select("select * from student where sname=#{a} and sex=#{b}")
    List<Student> find2(Map<String, Object> map);


	void deleteByIds(List<Integer> ids);

}

而它的测试:

public class TestStudentMapper {
    static SqlSessionFactory factory;
    static {
        // 读取配置文件
        try(InputStream in = Resources.getResourceAsStream("mybatis-config.xml")){
            // 创建 sqlSession 工厂类
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void testFindAll() {
        SqlSession sqlSession = factory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list = mapper.findAll();
        for (Student student : list) {
            System.out.println(student);
        }
        sqlSession.close();
    }

这次我们需要用sqlsession 对象调用getMapper方法,将接口类文件注入进去,得到一个StudentMapper对象,这样我们就可以调用之前用注解映射了sql语句的方法了,而它们亦可以关联数据库,获取我们想要的数据;
但是这里有一个要注意的问题,注解方式的sql语句比较的简单,而我们在完成复杂的逻辑的时候,这种方法可能不如我们之前用XML文件的方式简便直观,因此我们可以将它们两种方法结合起来,在较为简单的sql于继时使用注解方式,而复杂的sql映射时使用XML文件来映射,这样就更加灵活了;
就像上面的void deleteByIds(List ids);方法我们没有用注解,而是用了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="mapper.StudentMapper">
    <delete id="deleteByIds" parameterType="list">
        delete from student where sid in
        <foreach collection="list" item="x" open="(" close=")" separator=",">#{x}</foreach>
    </delete>
</mapper>

而这里要注意的是接口类名和XML文件名的对应,这样他才能在使用注解找不到sql语句时去对应的xml文件中去找映射了;
在这里插入图片描述

总结

mybatis相比于JDBC的好处还是十分明显的;

  • 问题一:数据库连接,使用时就创建,使用完毕就关闭,这样会对数据库进行频繁的获取连接和关闭连接,造成数据库资源浪费,影响数据库性能。

mybatis中的解决:使用数据库连接池管理数据库连接

  • 问题二:将 sql 语句硬编码到程序中,如果sql语句修改了,那么需要重新编译 Java 代码,不利于系统维护

mybatis中的解决:将 sql 语句配置到 xml 文件中,即使 sql 语句变化了,我们也不需要对 Java 代码进行修改,重新编译

  • 问题三:在 PreparedStatement 中设置参数,对占位符设置值都是硬编码在Java代码中,不利于系统维护

mybatis中的解决:将 sql 语句以及占位符和参数都配置到 xml 文件中

  • 问题四:从 resultset 中遍历结果集时,对表的字段存在硬编码,不利于系统维护

mybatis中的解决:将查询的结果集自动映射为 Java 对象

  • 问题五:重复性代码特别多,频繁的 try-catch

mybatis中的解决:将其整合到一个 try-catch 代码块中

  • 问题六:缓存做的很差,如果存在数据量很大的情况下,这种方式性能特别低

mybatis中的解决:集成缓存框架去操作数据库

  • 问题七:sql 的移植性不好,如果换个数据库,那么sql 语句可能要重写

mybatis中的解决:在 JDBC 和 数据库之间插入第三方框架,用第三方去生成 sql 语句,屏蔽数据库的差异

mybatis自身使用时的注意点:

  • parameterType:指定输入参数的类型

  • resultType:指定输出结果的类型,在select中如果查询结果是集合,那么也表示集合中每个元素的类型

  • #{}:表示占位符,用来接收输入参数,类型可以是简单类型,pojo,HashMap等等如果接收简单类型,#{}可以写成 value 或者其他名称

  • ${}:表示一个拼接符,会引起 sql 注入,不建议使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值