Mybatis的学习

本文介绍了Mybatis的基础概念,包括其封装jdbc的优点,以及如何通过全局配置文件、Mapper映射和SqlSessionFactory进行数据库操作。重点讲解了Mapper接口的代理模式,展示了如何利用动态代理在运行时扩展功能。
摘要由CSDN通过智能技术生成

一.什么是Mybatis?

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

相比于jdbc,mybatis提供了参数映射和结果集映射,使我们对参数设置和对结果集的封装变得更加简洁,而且mybatis还提供了动态sql关联查询 ,这使得我们能够对sql语句进行灵活的操作。

二.Mybatis入门

快速入门Mybatis只需要以下几个步骤:

  • 编写Mybatis的全局配置文件
  • 编写Mapper映射文件
  • 通过全局配置文件构建SqlSessionFactory
  • 通过SqlSessionFactory获取SqlSession

示例:

有一个tb_user表,我们使用mybatis对该表进行操作

1.创建一个maven项目:

2.加入mybatis以及相关的依赖

3.编写User类
package com.fs.entity;

import lombok.Data;

import java.util.Date;

@Data
public class User {
    private Integer id;

    private String username;

    private String password;

    private String sex;

    private Date birthday;

    private String address;
}
4.编写Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
 namespace: 命名空间
-->
<mapper namespace="User">

    <!--  查询所有用户:
       resultType:  结果集映射,我们这里查出来是User类型,所以resultType的值给User的全限定名
    -->
    <select id="selectAll" resultType="com.fs.entity.User">
        select * from tb_user
    </select>


    <!-- 根据id查询用户:
        parameterType:输入参数类型, 如果是简单数据类型(八大基本数据类型, String, 日期类型) 可以省略,
                          如果是自定义的类类型: 不可以省略,必须写类的全限定名
                          #{}是mybatis的占位符
    -->
    <select id="selectById" parameterType="int" resultType="com.fs.entity.User">
        select * from tb_user where id = #{id}
    </select>


    <!--添加用户:
    参数为自定义的User类型,必须写全限定名,
    没有结果集,返回的是首影响的行数
    -->
    <insert id="addUser" parameterType="com.fs.entity.User">
        insert into tb_user (id,username,password,sex,birthday,address) values(#{id},#{username},#{password},#{sex},#{birthday},#{address})
    </insert>


    <!--根据id删除用户-->
    <delete id="delById" parameterType="int">
        delete from tb_user where id = #{id}
    </delete>
</mapper>
5.编写全局配置文件(mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--开发环境-->
    <environments default="mysql">
        <environment id="mysql">
            <!--事务管理器: JDBC: 使用jdbc管理事务, 需要手动提交事务-->
            <transactionManager type="JDBC"/>
            <!--dataSource数据源的类型: POOLED 连接池   UNPOOLED: 不带连接池 -->
            <dataSource type="POOLED">
                <!--数据库四大参数-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/work"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

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

</configuration>
6.编写dao接口以及实现类
package com.fs.dao;

import com.fs.entity.User;

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

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

    User selectById(int id) throws IOException;

    int addUser(User user) throws IOException;

    int delById(int id) throws IOException;
}
package com.fs.dao.impl;

import com.fs.dao.UserDao;
import com.fs.entity.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserDaoImpl implements UserDao {

    private SqlSessionFactory sessionFactory;

    @Override
    public List<User> selectAll() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sessionFactory = sqlSessionFactoryBuilder.build(in);
        SqlSession session  = sessionFactory.openSession();
        List<User> users = session.selectList("selectAll");
        session.commit();//提交 不然对数据库的更改无效
        session.close();
        return users;
    }

    @Override
    public User selectById(int id) throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sessionFactory = sqlSessionFactoryBuilder.build(in);
        SqlSession session  = sessionFactory.openSession();
        User user = session.selectOne("selectById");
        session.commit();
        session.close();
        return user;
    }

    @Override
    public int addUser(User user) throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sessionFactory = sqlSessionFactoryBuilder.build(in);
        SqlSession session  = sessionFactory.openSession();
        int row = session.insert("addUser",user);
        session.commit();
        session.close();
        return row;
    }

    @Override
    public int delById(int id) throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        sessionFactory = sqlSessionFactoryBuilder.build(in);
        SqlSession session  = sessionFactory.openSession();
        int row = session.delete("delById",id);
        session.commit();
        session.close();
        return row;
    }
}
7.进行测试
package com.fs.dao.impl;

import com.fs.entity.User;
import org.junit.Test;

import java.io.IOException;
import java.util.Date;

import static org.junit.Assert.*;

public class UserDaoImplTest {

    private UserDaoImpl userDao = new UserDaoImpl();

    @Test
    public void selectAll() throws IOException {
        System.out.println(userDao.selectAll());
    }

    @Test
    public void selectById() throws IOException {
        System.out.println(userDao.selectById(1));
    }

    @Test
    public void addUser() throws IOException {
        User user = new User();
        user.setId(1);
        user.setUsername("张三");
        user.setPassword("12345");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("北京");
        userDao.addUser(user);
    }

    @Test
    public void delById() throws IOException {
        System.out.println(userDao.delById(1));
    }
}

这就是mybatis的原始的dao开发,在dao层实现类中获取sqlsession的代码重复了,而且我们通过sqlsession调用操作数据库的方法,如selectOne,selectList等,需要指定statement的id,不利于程序的维护

这里我们可以使用MybatisUtil封装,来减少重复代码:

package com.fs.util;

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 MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    private static ThreadLocal<SqlSession> tl = new ThreadLocal<>();


    static {
        InputStream in = null;
        try {
            in = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static SqlSession openSqlSession(){
        SqlSession sqlSession = tl.get();
        if(sqlSession == null){
            sqlSession =  sqlSessionFactory.openSession();
            tl.set(sqlSession);
        }
        return sqlSession;
    }

    public static void closeSqlSession(){
        SqlSession sqlSession = tl.get();
        if(sqlSession != null){
            sqlSession.commit();
            sqlSession.close();
            tl.remove();//防止内存泄漏
        }
    }

    //定义泛型方法 <T>: 定义泛型变量    T: 使用泛型变量
    // MybatisUtil.getMapper(UserMapper.class);
    public static <T> T getMapper(Class<T> clazz){
        SqlSession sqlSession = tl.get();
        if(sqlSession == null){
            sqlSession = openSqlSession();
        }
        return sqlSession.getMapper(clazz);
    }
}

 这里关于Mybatis工具类的封装,后面会单独出一篇文章

使用工具类后,我们dao实现类代码就会简化成下面这样:

package com.fs.dao.impl;

import com.fs.dao.UserDao;
import com.fs.entity.User;
import com.fs.util.MybatisUtil;
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;
import java.util.List;

public class UserDaoImpl implements UserDao {


    @Override
    public List<User> selectAll() throws IOException {
        SqlSession session = MybatisUtil.openSqlSession();
        List<User> users = session.selectList("selectAll");
        MybatisUtil.closeSqlSession();
        return users;
    }

    @Override
    public User selectById(int id) throws IOException {
        SqlSession session = MybatisUtil.openSqlSession();
        User user = session.selectOne("selectById",id);
        MybatisUtil.closeSqlSession();
        return user;
    }

    @Override
    public int addUser(User user) throws IOException {
        SqlSession session = MybatisUtil.openSqlSession();
        int row = session.insert("addUser",user);
        MybatisUtil.closeSqlSession();
        return row;
    }

    @Override
    public int delById(int id) throws IOException {
        SqlSession session = MybatisUtil.openSqlSession();
        int row = session.delete("delById",id);
        MybatisUtil.closeSqlSession();
        return row;
    }
}

 进行测试:

 尽管重复代码减少了,但还是有重复代码。

不同的地方在于,调用方法的参数不同,sqlsesion调用的方法不同以及返回值不同

三.Mybatis的Mapper代理模式

Mapper代理模式使用的是动态代理:

在运行时根据接口动态生成代理对象,我们只需要编写Mapper接口,并不需要编写实现类,即使以后我们需要再添加功能,也只需要在接口中添加新的方法,以及在Mapper映射文件中添加新的映射就可以了

3.1Mapper代理模式的实现

要求: 

  • sql映射文件的namespace必须是对应Mapper接口的全限定名(包.接口名) ​​​​​​​
  • sql映射文件的Statement的id必须是对应方法的方法名

statement的id对应Mapper接口中的方法名:

 3.2获取Mapper接口代理对象

SqlSession的getMapper(Class clazz): 根据传递Mapper接口类型,通过反射得到对应Mapper接口代理对象

测试:

 

 这样我们就实现了Mapper代理模式

总结:简单说明了Mybatis的入门以及Mapper代理模式的实现,由于篇幅原因使用的细节以及更深层次的知识,下一篇再进行总结

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值